using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiCommon.Utilities;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.AppSettings;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Log;
using Siger.Middlelayer.Redis.Repositories;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Redis.Utility;
using System.Linq.Expressions;
using Siger.ApiCommon.Result;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.ToolRepository.Entities;
using Siger.Middlelayer.ToolRepository.Repositories.Interface;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.ToolRepository.Request;
using Siger.Middlelayer.Utility.Helpers;
using Siger.Middlelayer.Utility.ImportEntities;
using Siger.Middlelayer.Redis.RedisEntities;
using Siger.ApiCommon.Filters;
namespace Siger.ApiTools.Controllers
{
    public class ToolConfigV2Controller : BaseController
    {
        readonly ISigerProjectToolcutterLocationalarmRepository sigerProjectToolcutterLocationalarmRepository;
        private readonly ISigerProjectToolCutterLocationTrueRepository _locationTrueRepository;
        private readonly ISigerProjectToolSpindleTrueRepository _spindleTrueRepository;
        private readonly ISigerProjectMachineRepository _sigerProjectMachine;
        private readonly IUnitOfWork _unitOfWork;

        public ToolConfigV2Controller(ISigerProjectToolcutterLocationalarmRepository sigerProjectToolcutterLocationalarmRepository,
            ISigerProjectToolCutterLocationTrueRepository locationTrueRepository, ISigerProjectToolSpindleTrueRepository spindleTrueRepository,
            ISigerProjectMachineRepository sigerProjectMachine, IUnitOfWork unitOfWork)
        {
            this.sigerProjectToolcutterLocationalarmRepository = sigerProjectToolcutterLocationalarmRepository;
            _locationTrueRepository = locationTrueRepository;
            _spindleTrueRepository = spindleTrueRepository;
            _sigerProjectMachine = sigerProjectMachine;
            _unitOfWork = unitOfWork;
        }

        [HttpGet]
        public IActionResult GetProgramListByCutterLocationConfig(int sectionid, int type)
        {
            var data = sigerProjectToolcutterLocationalarmRepository.GetProgralList((ProgramConfig)type, sectionid, ProjectId, "", 0);
            return new ObjectResult(data);
        }

        [HttpGet]
        public IActionResult GetProgramListByName(string name, int count)
        {
            var data = sigerProjectToolcutterLocationalarmRepository.GetProgralList(ProgramConfig.HasConfig, 0, ProjectId, name, count);
            return new ObjectResult(data);
        }

        [HttpPost]
        public IActionResult GetToolConfigInfo([FromBody]RequestGetToolConfigInfo req)
        {
            var data = sigerProjectToolcutterLocationalarmRepository.GetToolConfigInfo(req.program_no, req.sectionid, ProjectId, req.page, req.pagesize, out int totalCount);
            foreach (var d in data)
            {
                d.section_dsc = _sigerProjectMachine.GetLineLevelTitlebByMachine(d.machine_id, ProjectId);
            }
            return new PagedObjectResult(data, totalCount, req.page, req.pagesize);
        }

        [HttpPost]
        public IActionResult GetOriginalToolConfigInfo([FromBody]RequestGetOriginalToolConfigInfo req)
        {
            var data = sigerProjectToolcutterLocationalarmRepository.GetOriginalToolConfigInfo(req.programno, req.subprogramno,
                req.machine_id, ProjectId, req.page, req.pagesize, out int totalCount);
            return new PagedObjectResult(data, totalCount, req.page, req.pagesize);
        }

        /// <summary>
        /// v1.5新增获取未配置刀具信息页面列表
        /// </summary>
        /// <param name="sectionid"></param>
        /// <param name="program_no"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetUnConfigProgramList(int sectionid, String program_no, int page, int pageSize)
        {
            var data = sigerProjectToolcutterLocationalarmRepository.GetUnConfigProgramList(program_no, sectionid, ProjectId,
                page, pageSize, out int totalCount);
            if (data.Any())
            {
                var redis = new ToolCycleSortingRepository(CompanyId, ProjectId, false);
                foreach (var d in data)
                {
                    d.section_dsc = _sigerProjectMachine.GetLineLevelTitlebByMachine(d.machine_id, ProjectId);
                    //是否已配置
                    var BConfig = redis.BConfig(d.machine_id, d.programno);
                    if (BConfig != null)
                    {
                        var cfgspindle = BConfig.spindle.Find(f => f.no == 1);
                        if (cfgspindle != null)
                        {
                            d.isSort = 1;
                            d.default_sort = cfgspindle.tools;
                        }
                        continue;
                    }

                    //取模板
                    var cyclesort = redis.GetSequence(d.machine_id, d.programno);

                    if (cyclesort == null)
                        continue;
                    //取 默认1轴，主程序号
                    if (cyclesort.spindle == null)
                        continue;

                    var spindleOneData = cyclesort.spindle.Find(f => f.no == 1);
                    if (spindleOneData != null)
                    {
                        //  d.isSort = spindleOneData.iscfg;
                        d.isSort = 0;
                        d.default_sort = spindleOneData.tools;
                    }

                }
                redis.Dispose();
            }
            return new PagedObjectResult(data, totalCount, page, pageSize);
        }
        [HttpGet]
        public IActionResult GetCutterLocationEditInfo(int id)
        {
            var response = sigerProjectToolcutterLocationalarmRepository.GetCutterLocationEditInfo(id);
            if (response == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            return new ObjectResult(response);
        }

        [HttpPost]
        public async Task<IActionResult> ConfigCutterLocationAdd([FromBody]RequestToolCutterLocationAdd request)
        {
            if (request.coefficent.Any(f => f < 1))
            {
                throw new BadRequestException(ToolEnum.CoefficentError);
            }
            if (request.mid == 0)
            {
                throw new BadRequestException(RequestEnum.MachineNotFound);
            }
            var addResult = _locationTrueRepository.AddConfigCutterLocation(request);
            if (addResult == 0)
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
            if (addResult == 1)
            {
                try
                {
                    var repository = new RatedLifeConfigRepository(CompanyId, ProjectId, false);
                    for (var i = 0; i < request.cutter_location_name.Length; i++)
                    {
                        var coefficent = request.coefficent == null ? 0 : request.coefficent[i];
                        repository.AddRateLifeConfig(ProgramType.mainProgram + request.programno,
                            request.ratedlife.Length == 0 ? 0 : request.ratedlife[i].ToInt(),
                            request.cutter_location_name.Length == 0 ? "0" : request.cutter_location_name[i],
                            request.mid, request.spindle_name, request.type[i], request.tool_id[i].ToInt(), coefficent);

                        var redisUsage = new ToolMachineCycleUsageRepository(CompanyId, ProjectId);
                        var changeTime = DateTime.Now.ToString(UnixTimeHelper.DateTimeFormat);
                        redisUsage.ResetToolUsage(request.mid, ProgramType.mainProgram + request.programno, request.spindle_name, request.cutter_location_name[i], changeTime);

                        var targetRepository = new MonitorTargetRepository(CompanyId, ProjectId);
                        await targetRepository.AddMonitorTargetAsync(request.spindle_name, request.cutter_location_name[i], request.programno, request.mid);
                    }
                    repository.Dispose();
                }
                catch (Exception e)
                {
                    Logger.WriteLineError("AddConfigCutterLocation to redis failed, error:" + e);
                }
            }

            return new ObjectResult(CommonEnum.Succefull);
        }

        [HttpPost]
        public async Task<IActionResult> ConfigCutterLocationEdit([FromBody]RequestToolCutterLocationEdit request)
        {
            if (request.setting.Any(f => f.coefficent < 1))
            {
                throw new BadRequestException(ToolEnum.CoefficentError);
            }
            foreach (var item in request.setting)
            {
                var location = _locationTrueRepository.Get(item.id);
                if (location == null || location.status != (int)RowState.Valid)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }
                var spindle = _spindleTrueRepository.Get(q => q.id == location.spindleid && q.status == (int)RowState.Valid);
                if (spindle == null)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }
                Expression<Func<SigerProjectToolCutterLocationTrue, bool>> PnExp = f => f.status == (int)RowState.Valid;

                if (item.is_processing_program == (int)ProcessProgram.MainProgram)
                    PnExp = f => f.id != location.id && f.spindleid == location.spindleid && f.name == location.name && f.programno == location.programno &&
                    f.is_processing_program == (int)ProcessProgram.MainProgram && f.status == (int)RowState.Valid;
                else
                    PnExp = f => f.id != location.id && f.spindleid == location.spindleid && f.name == location.name && f.subprogramno == location.subprogramno &&
                    f.is_processing_program == (int)ProcessProgram.ChildProgram && f.status == (int)RowState.Valid;

                if (_locationTrueRepository.IsExist(PnExp))
                    throw new BadRequestException(CommonEnum.RecordExits);
                //程序号变化重置usage
                var initRest = item.is_processing_program != location.is_processing_program;
                //save to redis
                location.is_processing_program = item.is_processing_program;
                location.ratedlife = item.ratedlife;
                location.productid = item.product_id.ToInt();
                location.toolid = item.toolID;
                location.update_time = UnixTimeHelper.GetNow();
                location.type = (int)item.type;
                location.coefficent = item.coefficent;
                _locationTrueRepository.Update(location);

                spindle.productid = item.product_id.ToInt();
                spindle.update_time = UnixTimeHelper.GetNow();
                _spindleTrueRepository.Update(spindle);

                if (_unitOfWork.Commit() <= 0)
                {
                    throw new BadRequestException(CommonEnum.Fail);
                }
                try
                {

                    //monitor process pn
                    var pn = location.is_processing_program == (int)ProcessProgram.MainProgram ? location.programno : location.subprogramno;
                    //rate life redis process pn
                    var ratePn = location.is_processing_program == (int)ProcessProgram.MainProgram
                      ? ProgramType.mainProgram + location.programno : ProgramType.subProgram + location.subprogramno;

                    var repository = new RatedLifeConfigRepository(CompanyId, ProjectId);
                    repository.AddRateLifeConfig(ratePn, location.ratedlife.Value, location.name,
                        spindle.equipid, spindle.name, location.type, item.toolID, item.coefficent);
                    if (initRest)
                    {
                        var redisUsage = new ToolMachineCycleUsageRepository(CompanyId, ProjectId);
                        var changeTime = DateTime.Now.ToString(UnixTimeHelper.DateTimeFormat);
                        redisUsage.ResetToolUsage(spindle.equipid, ratePn, spindle.name, location.name, changeTime);
                    }
                    var targetRepository = new MonitorTargetRepository(CompanyId, ProjectId);
                    await targetRepository.AddMonitorTargetAsync(spindle.name, location.name, pn, spindle.equipid);
                }
                catch (Exception e)
                {
                    Logger.WriteLineError("ConfigCutterLocation to redis failed, error:" + e);
                }
            }
            return new ObjectResult(CommonEnum.Succefull);
        }

        [HttpPost]
        public IActionResult DeleteCutterLocation(int id)
        {
            var location = _locationTrueRepository.Get(id);
            if (location == null || location.status != (int)RowState.Valid)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            // location.status = (int) RowState.Invalid;
            location.is_processing_program = (int)ProcessProgram.NoConfig;
            _locationTrueRepository.Update(location);

            if (_unitOfWork.Commit() > 0)
            {
                var spindle = _spindleTrueRepository.Get(q => q.id == location.spindleid && q.status == (int)RowState.Valid);
                //sync redis
                if (spindle != null)
                {
                    var repository = new RatedLifeConfigRepository(CompanyId, ProjectId);
                    var pn = location.is_processing_program == (int)ProcessProgram.MainProgram
                  ? ProgramType.mainProgram + location.programno : ProgramType.subProgram + location.subprogramno;

                    repository.DeleteRateLifeConfig(spindle.equipid, pn, spindle.name, location.name);
                }
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.SystemExcetion);
        }

        [HttpGet]
        public IActionResult ExportRecords(int sectionId, string programNo)
        {
            var data = _locationTrueRepository.ExportToolConfigInfo(programNo, sectionId, ProjectId);
            if (!data.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            var exportData = new List<ToolLocationList>();
            var index = 1;
            foreach (var item in data)
            {
                var toolItem = new ToolLocationList
                {
                    No = index,
                    Code = item.machine_code,
                    Name = item.machine_name,
                    RateLife = item.ratedlife,
                    SpindleNo = item.spindle_name,
                    ToolName = item.tool_name,
                    ToolDrawingCode = item.drawingcode,
                    ProgramNo = item.programno,
                    ToolLocationName = item.cutter_location_name,
                    DrawingCode = item.productdrawingcode,
                    ISToolType = item.type == (int)ToolType.NOBlade ? "否" : "是",
                    Coefficent = item.coefficent
                };
                index++;
                exportData.Add(toolItem);
            }

            EpPlusExcelHelper<ToolLocationList> helper = null;
            try
            {
                helper = new EpPlusExcelHelper<ToolLocationList>();
                var temporaryFileName = $"toollocation_{DateTime.Now:yyyyMMddHHmmss}已配置刀具.xlsx";
                helper.GenerateExcel(exportData, Path.Combine(rootDir, temporaryFileName));
                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("Export Tool Location record failed, error:" + e);
                throw new BadRequestException(CommonEnum.SystemExcetion);
            }
            finally
            {
                helper?.Dispose();
            }
        }

        [HttpGet]
        public IActionResult GetToolsByProgram(int machine, string program)
        {
            if (machine == 0)
                throw new BadRequestException(RequestEnum.ParameterMiss);

            var redis = new ToolCycleSortingRepository(CompanyId, ProjectId);

            var data = redis.GetSequence(machine, program);

            return new ObjectResult(data);
        }
        /// <summary>
        /// 编辑刀位排序
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult ModifyCutterSort([FromBody]RequestCyclesort request)
        {
            //  var procPn = request.isProcess == (int)ProcessProgram.MainProgram ? ProgramType.mainProgram + request.program : ProgramType.subProgram + request.program;

            if (request.spindles == null || string.IsNullOrEmpty(request.program))
                throw new BadRequestException(RequestEnum.ParameterMiss);

            if (!request.spindles.Any())
                throw new BadRequestException(RequestEnum.ParameterError);

            var redis = new ToolCycleSortingRepository(CompanyId, ProjectId, false);

            var cyclesort = new ToolCycleSort
            {
                spindle = new List<SpindleSequence>()
            };
            foreach (var s in request.spindles)
            {
                cyclesort.spindle.Add(new SpindleSequence
                {
                    iscfg = 1,
                    no = s.no,
                    tools = s.tools
                });
                redis.UpdateSeq(cyclesort, request.machineId, request.program);
            }
            redis.Dispose();
            return new ObjectResult(CommonEnum.Succefull);
        }

        /// <summary>
        /// V.16 系统配置 :CC切分 
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult GetToolCCModeConfigInfo([FromBody]RequestGetToolConfigInfo req)
        {
            var data = sigerProjectToolcutterLocationalarmRepository.GetToolCCModeConfigInfos(req.program_no, req.sectionid, ProjectId, req.page, req.pagesize, out int totalCount);

            var redishelper = new CCInitializeConfigRepository(CompanyId, ProjectId, false);
            foreach (var d in data)
            {
                d.section_dsc = _sigerProjectMachine.GetLineLevelTitlebByMachine(d.machine_id, ProjectId);

                var ccMode = redishelper.GetCycleModeInit(d.machine_id, d.programno, d.spindle_name, d.cutter_location_name);
                d.mode = ccMode == null ? 0 : ccMode.mode;
                d.sro = ccMode == null ? 0d : ccMode.sro;
                d.fro = ccMode == null ? 0d : ccMode.fro;
                d.tnFilter = ccMode == null ? 0 : ccMode.tnFilter;
                d.time = ccMode == null ? "" : ccMode.time.ToStr();
            }
            redishelper.Dispose();
            return new PagedObjectResult(data, totalCount, req.page, req.pagesize);
        }
        /// <summary>
        /// 编辑CC 切分类型
        /// </summary>
        /// <param name="config"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult ModifyCCModeConfig([FromBody]requestCCModeConfig config)
        {
            var cuterTrue = _locationTrueRepository.Get(config.Id);
            if (cuterTrue == null)
                throw new BadRequestException(CommonEnum.RecordNotFound);
            var spindleTrue = _spindleTrueRepository.Get(cuterTrue.spindleid);
            if (spindleTrue == null)
                throw new BadRequestException(CommonEnum.RecordNotFound);

            var program = cuterTrue.is_processing_program == (int)ProcessProgram.MainProgram ? cuterTrue.programno : cuterTrue.subprogramno;
            var redisHelper = new CCInitializeConfigRepository(CompanyId, ProjectId);
            redisHelper.SetCCmode(spindleTrue.equipid, spindleTrue.name, cuterTrue.name, program, new CCInitializeConfig
            {
                spindleID = spindleTrue.name.ToInt(),
                sro = config.Sro,
                fro = config.Fro,
                pn = program.ToInt(),
                tnFilter = config.TnFilter,
                mode = config.Mode,
                time = UnixTimeHelper.GetNow()
            });

            return new ObjectResult(CommonEnum.Succefull);
        }
    }
}