using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis;
using Siger.Middlelayer.AccRepository.Entities;
using Siger.Middlelayer.AccRepository.Repositories.Interface;
using Siger.Middlelayer.AccRepository.Request;
using Siger.Middlelayer.Common;
using Siger.ApiCommon.Filters;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Log;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Share.Constant;
using Siger.Middlelayer.Share.Enum.ModuleEnum;
using static Siger.Middlelayer.Share.Enum.ModuleEnum.Automation;
using Siger.Middlelayer.Repository.Entities;
using NPOI.SS.Formula.Functions;
using Siger.Middlelayer.AccRepository.Response;
using Siger.Middlelayer.Common.Helpers;

namespace Siger.ApiACC.Controllers
{
    [NoTokenValidateFilter]
    public class AutomationController : LaisiBaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly ISigerProjectLevelSectionRepository _sigerProjectLevelSection;
        private readonly IAutomationLineMode _automationLineMode;
        private readonly IAutomationMachineStatus _automationMachineStatus;
        private readonly ISigerDict _sigerDict;
        private readonly IAutomationTaskListRepository _automationTaskList;
        private readonly ISigerProjectMachineAttributionRepository _sigerProjectMachineAttribution;
        private readonly IAutomationFixtureMonitor _automationFixtureMonitor;
        private readonly IAutomationLocationRepository _automationLocation;
        private readonly IProductionBeatSetRepository _productionBeatSet;
        private readonly IAutomationFixtureToolsProductRepository _automationFixtureToolsProduct;
        private readonly IAutomationFixtureToolsRepository _automationFixtureTools;

        public AutomationController(IUnitOfWork unitOfWork,ISigerProjectLevelSectionRepository sigerProjectLevelSection,IAutomationLineMode automationLineMode,IAutomationMachineStatus automationMachineStatus,ISigerDict sigerDict,IAutomationTaskListRepository automationTaskList,
            ISigerProjectMachineAttributionRepository sigerProjectMachineAttribution, IAutomationFixtureMonitor automationFixtureMonitor, IAutomationLocationRepository automationLocation, IProductionBeatSetRepository productionBeatSet, IAutomationFixtureToolsProductRepository automationFixtureToolsProduct,
         IAutomationFixtureToolsRepository automationFixtureTools)
        {
            _unitOfWork = unitOfWork;
            _sigerProjectLevelSection = sigerProjectLevelSection;
            _automationLineMode = automationLineMode;
            _automationMachineStatus = automationMachineStatus;
            _sigerDict = sigerDict;
            _automationTaskList = automationTaskList;
            _sigerProjectMachineAttribution = sigerProjectMachineAttribution;
            _automationFixtureMonitor = automationFixtureMonitor;
            _automationLocation = automationLocation;
            _productionBeatSet = productionBeatSet;
            _automationFixtureToolsProduct = automationFixtureToolsProduct;
            _automationFixtureTools = automationFixtureTools;
        }
 
        /// <summary>
        /// 设备状态接口 用于 保存 设备当前可用状态
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult MachineStatus([FromBody]RequestAutomationMachine request)
        {
            var machineAttr = _sigerProjectMachineAttribution.Get(f => f.projectid == PID && f.machine == request.machineid);
            if (machineAttr==null)
            {
                throw new BadRequestException(ConfigEnum.MachineAttributionNotFound);
            }
            var exitsObj = _automationMachineStatus.Get(f => f.machineid == request.machineid);
            if (exitsObj==null)
            {
                _automationMachineStatus.Insert(new siger_automation_machine_status{ 
                     section=machineAttr.station,
                     machineid=request.machineid,
                     projectId=PID,
                     updatetime=DateTime.Now,
                     enable=request.enable,
                     status=request.status
                });
            }else
            {
                exitsObj.enable = request.enable;
                exitsObj.status = request.status;
                exitsObj.updatetime = DateTime.Now;
                _automationMachineStatus.Update(exitsObj);
            }
           
         
            if (_unitOfWork.Commit() > 0)
            {
                // 设备空闲，或者完成时触发 自动任务
                if (request.enable == 1)
                {
                    if (request.status == (int)Automation.MachineStatus.Waiting || request.status == (int)Automation.MachineStatus.Complated)
                    {

                        var stationDicts = _sigerDict.GetDataByCat(AccDictCost.Automation, PID);
                        if (!stationDicts.Any())
                        {
                            Logger.WriteLineInfo($"AutoProcess 未配置设备类型字典");
                            throw new BadRequestException(AccEnum.AutomationDictNotfound);
                        }


                        var uploadStation = stationDicts.Where(f => f.dkey == DictKeyValConst.UploadloadStation);
                        var uploadStations = uploadStation.Select(f => f.dval.ToInt()).ToList();

                        if (!uploadStations.Contains(machineAttr.station))
                        {
                            var tasklist = _automationTaskList.GetList(f => f.projectId == PID && f.status < (int)TaskResultStatus.Complated);
                            if (!tasklist.Any())
                            {
                                var section = _sigerProjectLevelSection.Get(f => f.id == machineAttr.station);
                                if (section != null)
                                {
                                    Logger.WriteLineInfo($"MachineStatus 设备 {section.title}状态 触发自动任务检查");
                                    AutoProcess(section.parentid, stationDicts);
                                }
                            }
                        }
                    }
                }
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        /// <summary>
        /// 产线模式  0:手动模式 /1:自动模式（产生自动任务）
        /// </summary>
        /// <param name="line"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult LineMode(int line, int mode)
        {
            var exitObj = _automationLineMode.Get(f => f.section == line);
            if (exitObj == null)
            {
                _automationLineMode.Insert(new siger_automation_line_mode
                {
                    section = line,
                    projectId = PID,
                    status = 0, 
                    updatetime = DateTime.Now,
                    mode = mode
                });
            }
            else
            {
                exitObj.updatetime = DateTime.Now;
                exitObj.mode = mode;
                _automationLineMode.Update(exitObj);
            }
        
            if (_unitOfWork.Commit() > 0)
            {
                if (mode == 1)
                {
                    //TODO
                    //手动-》自动 时
                    //task 无任务时候 ，根据设备状态创建任务

                    var stationDicts = _sigerDict.GetDataByCat(AccDictCost.Automation, PID);
                    if (!stationDicts.Any())
                    {
                        Logger.WriteLineInfo($"AutoProcess 未配置设备类型字典");
                        throw new BadRequestException(AccEnum.AutomationDictNotfound);
                    }

                    var tasklist = _automationTaskList.GetList(f => f.projectId == PID && f.status < (int)TaskResultStatus.Complated);
                    if (!tasklist.Any())
                    {
                        Logger.WriteLineInfo($"LineMode Mode=1 触发自动任务检查");
                        AutoProcess(line, stationDicts);
                    }
                }
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        /// <summary>
        ///  产线 需要检验
        /// </summary>
        /// <param name="line"></param>
        /// <param name="enable"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult Inspect(int line, int enable)
        {
            var exitObj = _automationLineMode.Get(f => f.section == line);
            if (exitObj == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            exitObj.updatetime = DateTime.Now;
            exitObj.inspect = enable;

            if (_unitOfWork.Commit() > 0)
                return new ObjectResult(CommonEnum.Succefull);
            else
                throw new BadRequestException(CommonEnum.Fail);
        }
        /// <summary>
        /// 任务状态接口  用于保存PLC 实时任务状态 ()
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult TaskResult([FromBody]RequestAutomationTaskResult request)
        {
            //1.检查Tasklist
            var taskObj = _automationTaskList.Get(f => f.no== request.guid);
            if (taskObj == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            if (taskObj.status==(int)TaskResultStatus.Complated)
            {
                throw new BadRequestException(AccEnum.AutoTaskDone);
            }
            var stationDicts = _sigerDict.GetDataByCat(AccDictCost.Automation, PID);
            if (!stationDicts.Any())
            {
                Logger.WriteLineInfo($"AutoProcess 未配置设备类型字典");
                throw new BadRequestException(AccEnum.AutomationDictNotfound);
            }
            //更新Tasklist
            PlCfeeback(taskObj, request.status, stationDicts);

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

            //还有未完成任务 退出 等待任务下发
            if (!_automationTaskList.CanTask(PID, taskObj.sectionid))
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            //3.Tasklist 任务全部完成 ,创建自动任务

            switch (request.status)
            {
                case (int)TaskResultStatus.Cancel:
                case (int)TaskResultStatus.Complated:
                    {
                        var section = _sigerProjectLevelSection.Get(f => f.id == taskObj.sectionid);
                        if (section != null)
                        {
                            var updownDic = stationDicts.Where(s => s.dkey == DictKeyValConst.UploadloadStation);
                            var uploadStations = updownDic.Select(f => f.dval.ToInt()).ToList();
                            var uploadPostion = uploadStations.Contains(taskObj.sectionid);
                            if (uploadPostion)
                            {
                                Logger.WriteLineInfo($"AutoProcess 上料料工站 无需自动创建任务 ");
                                break;
                            }
                            AutoProcess(section.parentid, stationDicts);
                        }
                        break;
                    }
                case (int)TaskResultStatus.Waiting:
                case (int)TaskResultStatus.Produce:
                default:
                    {
                        break;
                    }
            }
            return new ObjectResult(CommonEnum.Succefull);
        }

        void PlCfeeback(siger_automation_task_list taskObj,int status, IEnumerable<SigerTrDict> stationDicts)
        {
            //2.更新状态
            taskObj.status = status;
            taskObj.completetime = DateTime.Now;
            _automationTaskList.Update(taskObj);

            //PLC 反馈结束. 
            if (status == (int)TaskResultStatus.Complated)
            {
                var uploadStation = stationDicts.Where(f => f.dkey == DictKeyValConst.UploadloadStation);
                var uploadStations = uploadStation.Select(f => f.dval).ToList();

                if (taskObj.action == TaskAction.Step_SXLW_LK)
                {
                    // 业务入口： 上料位-》 入库 如果是上料工装 安装完成 ,绑定 储位与装配
                    if (uploadStations.Exists(f => f.Contains(taskObj.sectionid.ToString())))
                    {
                        var location = _automationLocation.Get(f => f.fixturetools == taskObj.fixtureguid);
                        if (location == null)
                        {
                            Logger.WriteLineInfo($"PlCfeeback 未找到该工装储位信息");
                            throw new BadRequestException(AccEnum.MachineDisable);
                        }
                        location.fixturetools = taskObj.fixtureguid;
                        location.fixturename = taskObj.fixturename;
                        location.ordernumber = taskObj.ordercode;
                        location.productcode = taskObj.productcode;
                        location.productid = taskObj.productid;
                        location.sn = taskObj.sn;
                        _automationLocation.Update(location);

                        var monitor = _automationFixtureMonitor.Get(f => f.section == taskObj.sectionid);
                        monitor.section = 0;
                        _automationFixtureMonitor.Update(monitor);
                    }
                }
               
            }

        }

        /// <summary>
        /// 创建自动 Task任务
        /// </summary>
        /// <param name="line"></param>
        /// <param name="fixture"></param>
        /// <param name="stationDicts"></param>
        void AutoProcess(int line,IEnumerable<SigerTrDict> stationDicts)
        {
            var lineMode = _automationLineMode.Get(f => f.projectId == PID && f.section == line);
            if (lineMode==null)
            {
                Logger.WriteLineInfo($"AutoProcess 产线模式未找到");
                throw new BadRequestException(AccEnum.LineModeNotfound);
            }
            if (lineMode.mode==0)
            {
                Logger.WriteLineInfo($"AutoProcess 手动模式");
                //手动模式时 退出
                return;
            }

            /*
            //自动Task任务 顺序 
            //1.清洗机下料
            //2.其他设备上料
            //3.其他设备下料 
            */
            var updownDic= stationDicts.Where(s => s.dkey == DictKeyValConst.UploadloadStation);
            var uploadStations = updownDic.Select(f => f.dval.ToInt()).ToList();
            /* 自动任务创建只有CNC 设备;排除上料设备（手动任务） */
            var dictClean = stationDicts.FirstOrDefault(s=>s.dkey==DictKeyValConst.CleanStation);
            if (dictClean==null)
            {
                Logger.WriteLineInfo($"AutoProcess 未配置清洗机字典");
                return;
            }
            // 获取可用 设备状态列表 排除上料工位
            var machineStatusList = _automationMachineStatus.GetList(f => f.projectId == PID && !uploadStations.Contains(f.section) && f.enable == 1);
            if (!machineStatusList.Any())
            {
                Logger.WriteLineInfo($"AutoProcess 无可用状态的设备");
                return;
            }
            //优先级1 ：清洗机完成 。待下料
            var cleanMachine = machineStatusList.FirstOrDefault(f => f.section == dictClean.dval.ToInt());
            if (cleanMachine!=null)
            {
                if (cleanMachine.status == (int)Automation.MachineStatus.Complated)
                {
                    Logger.WriteLineInfo($"AutoProcess 有清洗机完成，创建清洗机Task");
                    var monitor = _automationFixtureMonitor.Get(f => f.section == cleanMachine.section);
                    if (monitor != null)
                    {
                        CreateTask(cleanMachine, TaskActionType.Unload, TaskAction.Step_QXJ_LK, monitor.fixtureguid, monitor.ordernumber, monitor.sn, "无程序",monitor.productId, monitor.productCode, monitor.locationId);
                        return; //完成当前任务 退出
                    }
                }
            }


            //优先级2 ：其他设备待上料 (立库->加工中心)
            var freeMachine = machineStatusList.FirstOrDefault(f=>f.status==(int)Automation.MachineStatus.Waiting);
            if (freeMachine != null)
            {
                Logger.WriteLineInfo($"AutoProcess 普通空闲，创建普通设备上料Task");
                var location = SelectLocation(freeMachine.machineid);
                if (location != null)
                {
                    var monitor = _automationFixtureMonitor.Get(f => f.section == freeMachine.section);
                    if (monitor == null)
                    {
                        _automationFixtureMonitor.Insert(new siger_automation_fixture_tools_monitor
                        {
                            projectId = PID,
                            productId=location.productId,
                            productCode = location.productCode,
                            productName = location.productName,
                            fixtureguid = location.fixture,
                            fixturename = location.fixturename,
                            ordernumber = location.ordernumber,
                            locationId = location.location,
                            section = freeMachine.section,
                            sn = location.sn,
                            createtime = DateTime.Now,
                            updatetime = DateTime.Now
                        });
                    }
                    else
                    {
                        monitor.productId = location.productId;
                        monitor.productCode = location.productCode;
                        monitor.productName = location.productName;
                        monitor.fixtureguid = location.fixture;
                        monitor.fixturename = location.fixturename;
                        monitor.ordernumber = location.ordernumber;
                        monitor.locationId = location.location;
                        monitor.sn = location.sn;
                        monitor.updatetime = DateTime.Now;
                        _automationFixtureMonitor.Update(monitor);
                    }
                    CreateTask(freeMachine, TaskActionType.Load, TaskAction.Step_LK_JGZX, location.fixture, location.ordernumber, location.sn, location.pn,location.productId, location.productCode, location.location);
                    return; //完成当前任务 退出
                }
            }
            //优先级3：其他设备下料  (加工中心 ->清洗机)
            if (cleanMachine != null)
            {
                var fullMachine = machineStatusList.FirstOrDefault(f => f.status == (int)Automation.MachineStatus.Complated);
                if (fullMachine != null && cleanMachine.status==(int)Automation.MachineStatus.Waiting)
                {
                    Logger.WriteLineInfo($"AutoProcess 普通空闲，创建普通设备下料Task ");

                    var monitor = _automationFixtureMonitor.Get(f => f.section == fullMachine.section);
                    if (monitor == null)
                    {
                        Logger.WriteLineInfo($"AutoProcess 找不到CNC监控信息");
                        return;
                    }
                    CreateTask(fullMachine,TaskActionType.Unload, TaskAction.Step_JGZX_QXJ, monitor.fixtureguid, monitor.ordernumber, monitor.sn,"无程序",monitor.productId, monitor.productCode, monitor.locationId);

                    return; //完成当前任务 退出
                }
            }
        }


        /// <summary>
        /// 创建自动任务
        /// </summary>
        /// <param name="machineStatus"></param>
        /// <param name="actionType"></param>
        /// <param name="taskAction"></param>
        /// <param name="guid">工装GUID</param>
        /// <param name="orderno">订单</param>
        /// <param name="sn">工件</param>
        /// <param name="productCode">产品CODE</param>
        /// <param name="locationid">储位ID</param>
        void CreateTask(siger_automation_machine_status machineStatus,TaskActionType actionType, TaskAction taskAction,string guid,string orderno,string sn,string program,int productId,string productCode,int locationid)
        {
            var taskNo = _automationTaskList.CrateTaskNumber(Automation.TaskTrigerType.Auto);
            _automationTaskList.Insert(new siger_automation_task_list
            {
                no= taskNo,
                projectId = PID,
                sectionid = machineStatus.section,
                trigger = TaskTrigerType.Auto,
                action = taskAction,
                actiontype = ExcueType.None,
                tasktype = actionType,
                triggertime = DateTime.Now,
                completetime = DateTime.MinValue,
                operatetime = DateTime.MinValue,
                send = 0,
                operater = 0,
                status = 1,
                fixtureguid= guid,
                productid = productId,
                productcode = productCode,
                programnumber=program,
                locationid= locationid,
                ordercode= orderno,
                sn= sn, 
                remark= EnumHelper.GetEnumDesc(taskAction)

            });
            

            if (_unitOfWork.Commit() > 0)
                Logger.WriteLineInfo($"CreateTask 工站 完成");
            else
                Logger.WriteLineInfo($"CreateTask 工站 失败");
        }
        /// <summary>
        /// 自动匹配储位 储位 ->CNC 
        /// </summary>
        ResponseAutomationLocationRouteInfo SelectLocation(int machine)
        {
            // 当前空闲设备能加工的产品
            var beats = _productionBeatSet.GetList(f => f.projectID == PID && f.machineID == machine);
            var productIds = beats.Select(f => f.product_name.ToInt()).Distinct().ToList();

            // 取产品交期最近的订单
            var planOrder = _automationFixtureToolsProduct.GetDeliveryOrder(productIds, PID);
            if (!planOrder.Any())
            {
                Logger.WriteLineInfo($"SelectLocation 未找到最近订单号信息");
                return null;
            }
            var order = planOrder.FirstOrDefault();

            //TODO 20210126
            var beatset = beats.Where(f => f.product_name == order.productId.ToString());
            //var location = _automationLocation.GetList(f => f.projectId == PID && f.ordernumber == order.ordernumber && productIds.Contains(f.productid));
            //if (!location.Any())
            //{
            //    Logger.WriteLineInfo($"SelectLocation 未找到最近交期订单号{order.ordernumber} 对应产品 {order.productName}的储位信息");
            //    return null;

            //}
            //储位有SN 工件

            var location = _automationLocation.GetList(f => f.projectId == PID && productIds.Contains(f.productid));
            var hasSnloaction = location.Where(f =>!string.IsNullOrEmpty(f.sn));
            if (!hasSnloaction.Any())
                return null;

            var result = location.FirstOrDefault();

            var valiateBeat = beatset.FirstOrDefault(f=>f.route_number.ToInt()>result.routenum);
            if (valiateBeat==null)
            {
                Logger.WriteLineInfo($"SelectLocation 未找到产品的工艺顺序");
                return null;
            }
            return new ResponseAutomationLocationRouteInfo
            {
                fixture = result.fixturetools,
                fixturename = result.fixturename,
                ordernumber =result.ordernumber,
                location=result.locationid,
                productId=result.productid,
                productCode=result.productcode,
                productName = result.productname,
                sn =result.sn,
                pn= valiateBeat.process_number,
                route=valiateBeat.route_name
            };
        }



    }
}
