using System;
using System.Collections.Generic;
using System.Linq;
using FluentScheduler;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Dapper;
using Siger.Middlelayer.Dapper.ResultData;
using Siger.Middlelayer.Log;
using Siger.Middlelayer.Redis;
using Siger.Middlelayer.Redis.RedisEntities;
using Siger.Middlelayer.ToolRepository;
using Siger.Middlelayer.ToolRepository.Entities;

namespace Siger.ApiTools.Tasks
{
    public class ProgramNumberJob : IJob
    {
        private static readonly ApiToolDbContext _context;

        static ProgramNumberJob()
        {
            _context = new ApiToolDbContext();
        }

        public void Execute()
        {
            var dbConfigs = RedisCache.Instance.GetDbNameConfigs();
            var programList = new List<ToolProgramList>();
            var now = DateTime.Now;
            var start = now.AddSeconds(-300); //只取5分钟内更新的
            foreach (var dbNameConfig in dbConfigs)
            {
                if (string.IsNullOrWhiteSpace(dbNameConfig.RedisDbName))
                {
                    Logger.WriteLineError($"ProgramNumberJob DbNameConfig setting error, can not find redisdbname by cid:{dbNameConfig.Cid}, pid:{dbNameConfig.Pid}.");
                    continue;
                }
                //去重
                foreach (var program in GetPrograms(dbNameConfig, start))
                {
                    if (program.MachineId == 0 || string.IsNullOrWhiteSpace(program.ProgramNo)
                                               || string.IsNullOrWhiteSpace(program.ToolName) || string.IsNullOrWhiteSpace(program.SpindleName))
                    {
                        Logger.WriteLineError("ProgramNumberJob program data error, has invalid data");
                        continue;
                    }
                    var isExist = programList.FirstOrDefault(q =>
                        q.MachineId == program.MachineId && q.ProgramNo == program.ProgramNo && q.SubProgramNo == program.SubProgramNo
                        && q.SpindleName == program.SpindleName && q.ToolName == program.ToolName);
                    if (isExist == null)
                    {
                        programList.Add(program);
                    }
                }
            }

            //插入mysql，siger_project_tool_cutter_location_true、siger_project_tool_spindle_true
            if (programList.Any())
            {
                InsertToMySql(programList);
            }
        }

        private IEnumerable<ToolProgramList> GetPrograms(DbNameConfig config, DateTime start)
        {
            try
            {
                var repository = new ToolPragramListRepository(config.Cid, config.Pid);
                return repository.GetRunningPrograms(start);
            }
            catch (Exception e)
            {
                Logger.WriteLineError($"ProgramNumberJob GetPrograms failed by cid:{config.Cid}, pid:{config.Pid}" + e);
            }

            return new List<ToolProgramList>();
        }

        private void InsertToMySql(IEnumerable<ToolProgramList> programs)
        {
            foreach (var program in programs)
            {
                try
                {
                    AddData(program);
                }
                catch (Exception e)
                {
                    Logger.WriteLineError("ProgramNumberJob: InsertToMySql failed, error:" + e);
                }
            }
        }

        private void AddData(ToolProgramList program)
        {
            var cutterLocationId = IsExistLocation(program);
            if (cutterLocationId > 0)
            {
                var result = UpdateToolCutterLocation(cutterLocationId, program.ChangeTime);
                if (result < 0)
                {
                    Logger.WriteLineError($"ProgramNumberJob: update siger_project_tool_cutter_location_true failed, id: {cutterLocationId}");
                }
            }
            else
            {
                //先插入主轴
                int spindleId;
                var spindle = _context.siger_project_tool_spindle_true.FirstOrDefault(q => q.equipid == program.MachineId
                                                                                           && q.name == program.SpindleName
                                                                                           && q.status == (int)RowState.Valid);
                if (spindle == null)
                {
                    spindleId = InsertToolSpindle(program.MachineId, program.SpindleName);
                    if (spindleId > 0)
                    {
                        Logger.WriteLineInfo($"ProgramNumberJob: insert siger_project_tool_spindle_true mid:{program.MachineId}, splindle: {program.SpindleName} successful.");
                    }
                }
                else
                {
                    spindleId = spindle.id;
                }
                //再插入刀位
                var cutterLocation = _context.siger_project_tool_cutter_location_true.FirstOrDefault(q => q.name == program.ToolName
                                                                                         && q.programno == program.ProgramNo
                                                                                         && q.subprogramno == program.SubProgramNo
                                                                                         && q.spindleid == spindleId
                                                                                         && q.status == (int)RowState.Valid);
                if (cutterLocation == null)
                {
                    var locationId = InsertToolCutterLocation(spindleId, program);
                    if (locationId > 0)
                    {
                        Logger.WriteLineInfo($"ProgramNumberJob: update siger_project_tool_cutter_location_true name:{ program.ToolName}, splindle: {program.SpindleName} successful.");
                    }
                }
            }
        }

        private int IsExistLocation(ToolProgramList program)
        {
            var query = from tcl in _context.siger_project_tool_cutter_location_true
                        join ts in _context.siger_project_tool_spindle_true on tcl.spindleid equals ts.id
                        where ts.equipid == program.MachineId
                              && tcl.name == program.ToolName
                              && ts.name == program.SpindleName
                              && tcl.programno == program.ProgramNo
                              && tcl.subprogramno == program.SubProgramNo
                              && tcl.status == (int)RowState.Valid
                              && ts.status == (int)RowState.Valid
                        select tcl.id;

            if (query.Any())
            {
                return query.FirstOrDefault();
            }
            return 0;
        }

        private int UpdateToolCutterLocation(int cutterLocationId, string time)
        {
            var entity = _context.siger_project_tool_cutter_location_true.FirstOrDefault(q => q.id == cutterLocationId && q.is_processing_program == 0);
            if (entity != null)
            {
                entity.is_identical_collection = 1;
                entity.update_time = UnixTimeHelper.GetUnixByShortDate(time);
                _context.siger_project_tool_cutter_location_true.Update(entity);
            }
            return _context.SaveChanges();
        }

        private int InsertToolSpindle(int mid, string name)
        {
            var entity = new SigerProjectToolSpindleTrue
            {
                equipid = mid,
                name = name,
                create_time = UnixTimeHelper.GetNow(),
                update_time = UnixTimeHelper.GetNow(),
                status = (int)RowState.Valid
            };
            _context.siger_project_tool_spindle_true.Add(entity);
            return _context.SaveChanges() > 0 ? entity.id : 0;
        }

        private int InsertToolCutterLocation(int spindleId, ToolProgramList program)
        {
            var entity = new SigerProjectToolCutterLocationTrue
            {
                spindleid = spindleId,
                name = program.ToolName,
                programno = program.ProgramNo,
                subprogramno = program.SubProgramNo,
                is_processing_program = (int)ProcessProgram.NoConfig,
                is_identical_collection = 1,
                create_time = UnixTimeHelper.GetNow(),
                update_time = UnixTimeHelper.GetNow(),
                status = (int)RowState.Valid
            };
            _context.siger_project_tool_cutter_location_true.Add(entity);
            return _context.SaveChanges() > 0 ? entity.id : 0;
        }

    }
}
