using PlcSiemens.Core.Extension;
using ServiceCenter.Extensions;
using ServiceCenter.Logs;
using ServiceCenter.SqlSugars;
using SqlSugar;
using System.ComponentModel;
using WCS.Core;
using WCS.Entity;
using WCS.Entity.Protocol.Station;
using WCS.WorkEngineering.Extensions;
using WCS.WorkEngineering.WebApi.Controllers;
using WCS.WorkEngineering.WebApi.Models.WMS.Request;
using WCS.WorkEngineering.Worlds;
using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags;
using TaskStatus = WCS.Entity.TaskStatus;

namespace WCS.WorkEngineering.Systems
{
    /// <summary>
    ///  无交互系统
    /// </summary>
    [BelongTo(typeof(NoInteractionWorld))]
    [Description("无交互系统")]
    public class NoInteractionSystems : DeviceSystem<Device<IStation520>>
    {
        protected override bool ParallelDo => true;

        public override void Do(Device<IStation520> obj)
        {
            var taskInfos = new List<int>();
            var sqlSugar = new SqlSugarHelper();

            SqlSugarHelper.Do(db =>
            {
                //获取所有的新建任务，组盘任务不需要
                taskInfos = db.Default.Queryable<WCS_TaskInfo>().ReadPastUpdLock().Where(x => x.Status == 0).ToList()
                    .Where(x => x.Type != TaskType.SetPlate || (x.Type == TaskType.SetPlate && x.AddrFrom != "Robot")).Where(x => x.BusType != "人工满托入库").Select(x => x.ID).ToList();
                var time = DateTime.Now.AddMinutes(-20);
                var time1 = DateTime.Now.AddMinutes(-40);
                var timeOut = db.Default.Queryable<WCS_TaskInfo>().NoLock().Count(x => x.BusType == "车间叫料" && x.Status < TaskStatus.StackerExecution && x.AddTime < time);
                if (timeOut > 0) World.Log($"共有{timeOut}个车间叫料任务超过二十分钟未执行，请检查相关相关任务对应的堆垛机是否正常、堆垛机放货点是否卡任务等", LogLevelEnum.High);

                var timeOut1 = db.Default.Queryable<WCS_TaskInfo>().NoLock().Count(x => x.BusType == "车间叫料" && x.Status < TaskStatus.StackerExecution && x.AddTime < time1);
                if (timeOut1 > 0) World.Log($"共有{timeOut1}个车间叫料任务超过四十分钟未执行，请检查相关相关任务对应的堆垛机是否正常、堆垛机放货点是否卡任务等", LogLevelEnum.High);

                var timeOut2 = db.Default.Queryable<WCS_TaskInfo>().NoLock().Count(x => x.BusType == "皮盘入库" && x.Status < TaskStatus.StackerExecution && x.AddTime < time);
                if (timeOut2 > 0) World.Log($"共有{timeOut2}个皮盘入库任务超过二十分钟未执行，请检查相关相关任务及对应agv设备", LogLevelEnum.High);

                var timeOut3 = db.Default.Queryable<WCS_TaskInfo>().NoLock().Count(x => x.BusType == "皮盘入库" && x.Status < TaskStatus.StackerExecution && x.AddTime < time1);
                if (timeOut3 > 0) World.Log($"共有{timeOut3}个皮盘入库任务超过四十分钟未执行，请检查相关相关任务及对应agv设备", LogLevelEnum.High);

                var time3 = DateTime.Now.AddHours(-24);
                var timeOut4 = db.Default.Queryable<BillInvnow>().NoLock().Count(x => x.AddTime < time3);
                if (timeOut4 > 0) World.Log($"共有{timeOut4}个库存信息超过24小时未执行，请检查相关库存信息并处理", LogLevelEnum.High);
            });
            if (!taskInfos.Any())
            {
                return;
            }

            var isEnd = false; //每个周期只处理一个任务
            foreach (var item in taskInfos)
            {
                if (isEnd) return;

                try
                {
                    SqlSugarHelper.Do(db =>
                    {
                        var task = db.Default.Queryable<WCS_TaskInfo>().Where(t => t.ID == item).First();

                        switch (task.Type)
                        {
                            case TaskType.SetPlate:
                                if (task.AddrFrom != "Robot")
                                {
                                    //更新任务状态
                                    task.Status = TaskStatus.WaitingToExecute;
                                    db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status }).ExecuteCommand();
                                    task.AddWCS_TASK_DTL(db.Default, task.Device, $"初始化入库任务信息");
                                    isEnd = true;
                                }
                                break;

                            case TaskType.EnterDepot:
                                if (task.LastInteractionPoint == "2")
                                {
                                    var sta = GetAgvStation(task, db);
                                    var agv = new WCS_AgvTaskInfo()
                                    {
                                        ID = db.GetAgvTaskId(),
                                        TaskType = AGVTaskType.EnterDepot,
                                        Status = AGVTaskStatus.NewBuild,
                                        TaskId = task.ID,
                                        Position = task.WorkBench,
                                        Station = sta,
                                        AddWho = "WCS",
                                        AddTime = DateTime.Now
                                    };
                                    db.Default.InsertableRowLock(agv).SplitTable().ExecuteCommand();
                                    task.AgvTaskID = agv.ID;
                                    task.Status = Entity.TaskStatus.WaitingToExecute;
                                    db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.AgvTaskID }).ExecuteCommand();
                                    task.AddWCS_TASK_DTL(db.Default, task.Device, $"初始化单独返皮盘任务");
                                }
                                else if (task.BusType == TaskBusType.芯股用空托盘入库.GetDescription())
                                {
                                    return;
                                }
                                else
                                {
                                    //更新任务状态
                                    task.Status = Entity.TaskStatus.WaitingToExecute;
                                    task.Device = task.WarehouseCode switch
                                    {
                                        "1N" => "SRM1",
                                        "1S" => "SRM2",
                                        "2N" => "SRM3",
                                        "2S" => "SRM4",
                                        "3N" => "SRM5",
                                        "3S" => "SRM6",
                                        _ => task.Device
                                    };

                                    task.Device = task.AddrFrom switch
                                    {
                                        "1666" or "1661" => "SRM1",
                                        "1681" or "1676" => "SRM2",
                                        "1696" or "1691" => "SRM3",
                                        "1711" or "1706" => "SRM4",
                                        "1726" or "1721" => "SRM5",
                                        "1741" or "1736" => "SRM6",
                                        _ => task.Device
                                    };

                                    //计算下一个地址
                                    var path1 = DevicePath.GetPath(task.AddrFrom, task.Device);
                                    task.AddrNext = path1.Points[1].Code;
                                    task.SrmStation = task.BarCode.Contains("TPA") || task.BarCode.Contains("TPB") ? task.AddrFrom : path1.Points[2].Code;

                                    db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.Device, x.AddrNext, x.SrmStation }).ExecuteCommand();
                                    task.AddWCS_TASK_DTL(db.Default, task.Device, $"初始化入库任务信息");
                                }

                                isEnd = true;
                                break;

                            case TaskType.OutDepot:
                                {
                                    if (task.Device.Contains("Robot")) //机器人任务
                                    {
                                        var lastTask = db.Default.Queryable<WCS_TaskInfo>().NoLock().First(x => x.Type == TaskType.OutDepot && x.AddrTo == task.AddrTo && x.Status > TaskStatus.WaitingToExecute && x.Status < TaskStatus.Finish);
                                        if (lastTask != null)
                                        {
                                            World.Log($"等待任务结束:{task.AddrTo}上一组码垛任务未结束，等待{lastTask.ID}任务完成后开始初始化当前任务{task.ID}");
                                            return;
                                        }
                                        var pos = task.AddrFrom.Split("-");
                                        task.Status = Entity.TaskStatus.WaitingToExecute;
                                        task.Line = pos[0].ToShort();
                                        task.Col = pos[1].ToShort();
                                        task.Layer = pos[2].ToShort();
                                        task.Depth = pos[3].ToShort();
                                        db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.Line, x.Col, x.Layer, x.Depth }).ExecuteCommand();
                                        task.AddWCS_TASK_DTL(db.Default, task.Device, $"初始化出库任务信息,放货站台:{task.SrmStation}");
                                        isEnd = true;
                                    }
                                    else if (task.Device == "FJXG") //芯股仓库的任务
                                    {
                                        if (task.LastInteractionPoint != "3") //车间叫料任务，此值为3时是单独取满任务
                                        {
                                            var sta = GetAgvStation(task, db); //芯股任务，取货站台就是芯股站台
                                            var agv = new WCS_AgvTaskInfo()
                                            {
                                                ID = db.GetAgvTaskId(),
                                                TaskType = AGVTaskType.EnterDepot,
                                                Status = AGVTaskStatus.NewBuild,
                                                TaskId = task.ID,
                                                Position = task.WorkBench,
                                                Station = sta,
                                                AddWho = "WCS",
                                                AddTime = DateTime.Now
                                            };
                                            db.Default.InsertableRowLock(agv).SplitTable().ExecuteCommand();
                                        }
                                        var agvId = DateTime.Now.GetFormat(GetFormatterEnum.only) + task.ID;
                                        var agvTask = new WCS_AgvTaskInfo()
                                        {
                                            ID = db.GetAgvTaskId(),
                                            TaskType = AGVTaskType.CallMaterial,
                                            Status = AGVTaskStatus.NewBuild,
                                            TaskId = task.ID,
                                            Position = task.WorkBench,
                                            Station = task.AddrFrom,
                                            AddWho = "WCS",
                                            AddTime = DateTime.Now,
                                            AgvID = agvId
                                        };
                                        //开始处理车间叫料AGV任务任务
                                        db.Default.InsertableRowLock(agvTask).SplitTable().ExecuteCommand();
                                        agvTask = db.Default.Queryable<WCS_AgvTaskInfo>().UpdLock().SplitTable(x => x.Take(2)).Single(x => x.TaskId == task.ID && x.TaskType == AGVTaskType.CallMaterial);
                                        if (agvTask.Status != AGVTaskStatus.NewBuild)
                                        {
                                            World.Log($"AGV任务{agvTask.ID}状态不是新建", LogLevelEnum.High);
                                            return;
                                        }
                                        agvId = agvTask.AgvID;
                                        agvTask.Status = AGVTaskStatus.Confirm;
                                        agvTask.AgvStatus = AGVTaskStatus.Confirm;
                                        db.Default.UpdateableRowLock(agvTask).UpdateColumns(x => new { x.AgvID, x.Status, x.AgvStatus }).SplitTable(x => x.Take(2)).ExecuteCommand();
                                        task.Status = TaskStatus.AGVExecution;
                                        task.AgvTaskID = agvTask.ID;
                                        task.EditTime = DateTime.Now;
                                        task.EditWho = "WCS";
                                        db.Default.Updateable(task).UpdateColumns(x => new { x.Status, x.AgvTaskID, x.EditTime, x.EditWho }).ExecuteCommand();
                                        task.AddWCS_TASK_DTL(db.Default, task.AddrFrom, "AGV", $"任务下发至AGV{agvId}");
                                        var res = AgvApi.机台叫料(task.AddrFrom, task.WorkBench, agvId);

                                        isEnd = true;
                                    }
                                    else if (task.BusType == TaskBusType.芯股站台送空托.GetDescription())
                                    {
                                        if (task.SrmStation == "1")
                                        {
                                            var srmStation = new string[2];
                                            switch (task.Device)
                                            {
                                                case "SRM1":
                                                    srmStation[0] = "2534";
                                                    srmStation[1] = "2533";
                                                    break;

                                                case "SRM2":
                                                    srmStation[0] = "2734";
                                                    srmStation[1] = "2733";
                                                    break;

                                                case "SRM3":
                                                    srmStation[0] = "2934";
                                                    srmStation[1] = "2933";
                                                    break;

                                                case "SRM4":
                                                    srmStation[0] = "3134";
                                                    srmStation[1] = "3133";

                                                    break;

                                                case "SRM5":
                                                    srmStation[0] = "3334";
                                                    srmStation[1] = "3333";
                                                    break;

                                                case "SRM6":
                                                    srmStation[0] = "3534";
                                                    srmStation[1] = "3533";
                                                    break;
                                            }

                                            //开始计算当前这个任务要从哪个站台出
                                            //计算两个站台小于取货完成数量的AGV任务
                                            var agv1 = db.Default.Queryable<WCS_TaskInfo>().NoLock().Where(x => x.Status <= TaskStatus.StackerExecution && x.AddrTo == srmStation[0]).Count();
                                            var agv2 = db.Default.Queryable<WCS_TaskInfo>().NoLock().Where(x => x.Status <= TaskStatus.StackerExecution && x.AddrTo == srmStation[1]).Count();
                                            task.SrmStation = "";
                                            task.AddrTo = agv1 > agv2 ? srmStation[1] : srmStation[0];
                                        }
                                        if (task.SrmStation.IsNullOrEmpty()) //如果没有指定放货站台
                                        {
                                            if (task.Device.IsNullOrEmpty())
                                            {
                                                task.Device = "SRM" + task.Tunnel.GetLastDigit();
                                            }
                                            //获取堆垛机到目标地址的路径信息
                                            var path = DevicePath.GetPath(task.Device, task.AddrTo);
                                            task.SrmStation = path.Points[1].Code;
                                        }

                                        //更新任务状态
                                        task.Status = Entity.TaskStatus.WaitingToExecute;
                                        db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.SrmStation, x.AddrTo, x.Status }).ExecuteCommand();
                                        task.AddWCS_TASK_DTL(db.Default, task.Device, $"初始化出库任务信息,放货站台:{task.SrmStation}");
                                        isEnd = true;
                                    }
                                    else //立库出库任务
                                    {
                                        if (task.SrmStation == "1")
                                        {
                                            var srmStation = new string[2];
                                            switch (task.Device)
                                            {
                                                case "SRM1":
                                                    srmStation[0] = "2534";
                                                    srmStation[1] = "2533";
                                                    break;

                                                case "SRM2":
                                                    srmStation[0] = "2734";
                                                    srmStation[1] = "2733";
                                                    break;

                                                case "SRM3":
                                                    srmStation[0] = "2934";
                                                    srmStation[1] = "2933";
                                                    break;

                                                case "SRM4":
                                                    srmStation[0] = "3134";
                                                    srmStation[1] = "3133";

                                                    break;

                                                case "SRM5":
                                                    srmStation[0] = "3334";
                                                    srmStation[1] = "3333";
                                                    break;

                                                case "SRM6":
                                                    srmStation[0] = "3534";
                                                    srmStation[1] = "3533";
                                                    break;
                                            }

                                            //开始计算当前这个任务要从哪个站台出
                                            //计算两个站台小于取货完成数量的AGV任务
                                            var agv1 = db.Default.Queryable<WCS_TaskInfo>().NoLock().Where(x => x.Status <= TaskStatus.StackerExecution && x.AddrTo == srmStation[0]).Count();
                                            var agv2 = db.Default.Queryable<WCS_TaskInfo>().NoLock().Where(x => x.Status <= TaskStatus.StackerExecution && x.AddrTo == srmStation[1]).Count();
                                            task.SrmStation = "";
                                            task.AddrTo = agv1 > agv2 ? srmStation[1] : srmStation[0];
                                        }
                                        if (task.SrmStation.IsNullOrEmpty()) //如果没有指定放货站台
                                        {
                                            if (task.Device.IsNullOrEmpty())
                                            {
                                                task.Device = "SRM" + task.Tunnel.GetLastDigit();
                                            }
                                            //获取堆垛机到目标地址的路径信息
                                            var path = DevicePath.GetPath(task.Device, task.AddrTo);
                                            task.SrmStation = path.Points[1].Code;
                                        }

                                        var devs = Device.All.Where(x => x.HasFlag(DeviceFlags.AGV取货站台口)).Select(x => x.Code);
                                        if (devs.Contains(task.SrmStation) && task.LastInteractionPoint != "3") //车间叫料任务，此值为3时是单独取满任务
                                        {
                                            var sta = GetAgvStation(task, db);

                                            var agv = new WCS_AgvTaskInfo()
                                            {
                                                ID = db.GetAgvTaskId(),
                                                TaskType = AGVTaskType.EnterDepot,
                                                Status = AGVTaskStatus.NewBuild,
                                                TaskId = task.ID,
                                                Position = task.WorkBench,
                                                Station = sta,
                                                AddWho = "WCS",
                                                AddTime = DateTime.Now
                                            };
                                            db.Default.InsertableRowLock(agv).SplitTable().ExecuteCommand();
                                        }
                                        //更新任务状态
                                        task.Status = Entity.TaskStatus.WaitingToExecute;
                                        db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.SrmStation, x.AddrTo, x.Status }).ExecuteCommand();
                                        task.AddWCS_TASK_DTL(db.Default, task.Device, $"初始化出库任务信息,放货站台:{task.SrmStation}");
                                        isEnd = true;
                                    }
                                    break;
                                }
                            case TaskType.Delivery:
                                break;

                            case TaskType.EmptyInit:
                                break;
                        }
                    });
                }
                catch (Exception ex)
                {
                    if (ex.Message.Contains("Index")) World.Log($"{ex.Message}:{ex.StackTrace}");
                    if (ex.Message.Contains("SqlTransaction")) World.Log($"{ex.Message}:{ex.StackTrace}");
                    World.Log(ex.Message, LogLevelEnum.Mid);
                }
            }
        }

        public override bool Select(Device dev)
        {
            return dev.Code == nameof(NoInteractionSystems);
        }

        /// <summary>
        ///  获取AGV的目标站台
        /// </summary>
        /// <param name="task"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public string GetAgvStation(WCS_TaskInfo task, SqlSugarHelper db)
        {
            string sta = "";
            var n = 0;
            var s = 0;
            var warehouseCode = task.WarehouseCode;
            if (task.BusType == TaskBusType.皮盘入库.GetDescription() || task.BusType == TaskBusType.车间叫料.GetDescription())
            {
                warehouseCode = task.MaterialCode;
            }
            //同侧之间均分
            if (warehouseCode.Contains("1"))
            {
                n = db.Default.Queryable<WCS_AgvTaskInfo>().NoLock().Where(v => v.Status >= AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.Complete1 && v.TaskType == AGVTaskType.EnterDepot && v.Station.Contains("25"))
                           .SplitTable(v => v.Take(2)).Count();
                s = db.Default.Queryable<WCS_AgvTaskInfo>().NoLock().Where(v => v.Status >= AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.Complete1 && v.TaskType == AGVTaskType.EnterDepot && v.Station.Contains("27"))
                           .SplitTable(v => v.Take(2)).Count();
                sta = n > s ? "2701" : "2501";
            }
            else if (warehouseCode.Contains("2"))
            {
                n = db.Default.Queryable<WCS_AgvTaskInfo>().NoLock().Where(v => v.Status >= AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.Complete1 && v.TaskType == AGVTaskType.EnterDepot && v.Station.Contains("29"))
                           .SplitTable(v => v.Take(2)).Count();
                s = db.Default.Queryable<WCS_AgvTaskInfo>().NoLock().Where(v => v.Status >= AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.Complete1 && v.TaskType == AGVTaskType.EnterDepot && v.Station.Contains("31"))
                           .SplitTable(v => v.Take(2)).Count();
                sta = n > s ? "3101" : "2901";
            }
            else if (warehouseCode.Contains("3"))
            {
                n = db.Default.Queryable<WCS_AgvTaskInfo>().NoLock().Where(v => v.Status >= AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.Complete1 && v.TaskType == AGVTaskType.EnterDepot && v.Station.Contains("33"))
                           .SplitTable(v => v.Take(2)).Count();
                s = db.Default.Queryable<WCS_AgvTaskInfo>().NoLock().Where(v => v.Status >= AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.Complete1 && v.TaskType == AGVTaskType.EnterDepot && v.Station.Contains("35"))
                               .SplitTable(v => v.Take(2)).Count();
                sta = n > s ? "3501" : "3301";
            }
            else
            {
                return default;
            }

            n = db.Default.Queryable<WCS_AgvTaskInfo>().NoLock().Where(v =>
                    v.Status >= AGVTaskStatus.Confirm &&
                    v.Status < AGVTaskStatus.Complete1 &&
                    v.TaskType == AGVTaskType.EnterDepot && v.Station == sta)
                .SplitTable(v => v.Take(2)).Count();
            if (n > 5)
            {
                sta = db.Default.Queryable<WCS_AgvTaskInfo>().NoLock().Where(v => v.Status >= AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.Complete1 && v.TaskType == AGVTaskType.EnterDepot)
                    .SplitTable(v => v.Take(2)).ToList().GroupBy(x => x.Station).Select(x => new { x.Key, Count = x.Count() }).MinBy(x => x.Count).Key;
            }

            return sta;
        }
    }
}