using Newtonsoft.Json;
using PlcSiemens.Core.Extension;
using ServiceCenter.Extensions;
using ServiceCenter.Logs;
using ServiceCenter.SqlSugars;
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.Worlds;
using TaskStatus = WCS.Entity.TaskStatus;

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

        public AgvSystems()
        {
        }

        public override void Do(Device<IStation520> obj)
        {
            if (obj.Entity.Code == "AGVOut")
            {
                var agvTaskInfos = new List<WCS_AgvTaskInfo>();
                //获取所有未结束的叫料及背负式补空AGV任务
                SqlSugarHelper.Do(db =>
                {
                    agvTaskInfos = db.Default.Queryable<WCS_AgvTaskInfo>().ReadPast().Where(v => v.TaskType == AGVTaskType.CallMaterial)
                                                                         .Where(v => v.Status < AGVTaskStatus.MissionCompleted)
                                                                         .SplitTable(tabs => tabs.Take(2)).OrderBy(v => v.AddTime).ToList();
                });
                //有需要处理的AGV任务
                if (agvTaskInfos.Any())
                {
                    this.ExRecord(obj.Entity.Code, "可用出库AGV任务列表", agvTaskInfos.Select(v => v.ID).ToList());
                    var taskInfos = new List<WCS_TaskInfo>();

                    foreach (var agv in agvTaskInfos)
                    {
                        try
                        {
                            SqlSugarHelper.Do(db =>
                            {
                                switch (agv.AgvStatus)
                                {
                                    //取货点安全交互
                                    case AGVTaskStatus.RequestOrPermission2 when agv.Status != AGVTaskStatus.RequestOrPermission2:
                                        {
                                            var taskInfo = db.Default.Queryable<WCS_TaskInfo>().First(v => v.ID == agv.TaskId);
                                            agv.Status = AGVTaskStatus.RequestOrPermission2;
                                            db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                            taskInfo.AddWCS_TASK_DTL(db.Default, "agv", $"允许AGV任务{agv.ID}在站台{agv.Station}取货");
                                            AgvApi.ContinueTask(agv.AgvID, agv.Station);
                                            break;
                                        }
                                    case AGVTaskStatus.PutRequestOrPermission when agv.Status != AGVTaskStatus.PutRequestOrPermission:
                                        {
                                            agv.Status = AGVTaskStatus.PutRequestOrPermission;
                                            db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                            AgvApi.ContinueTask(agv.AgvID, agv.Station);
                                            break;
                                        }
                                    case AGVTaskStatus.LeaveGet when agv.Status != AGVTaskStatus.LeaveGet:
                                        World.Log($"AGV取货结束:开始{agv.ID}--{agv.Station}");
                                        var devinfo = new Device<IStation520>(Device.All.First(x => x.Code == agv.Station), World);
                                        devinfo.Data.CmdType = StationCmd.Res5;
                                        agv.Status = AGVTaskStatus.LeaveGet;
                                        db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                        World.Log($"AGV取货结束:结束{agv.ID}--{agv.Station}");
                                        break;
                                    //完成任务
                                    case AGVTaskStatus.MissionCompleted when agv.Status != AGVTaskStatus.MissionCompleted:
                                        {
                                            if (agv.TaskType is AGVTaskType.CallForMaterial or AGVTaskType.ForkliftFilling or AGVTaskType.CallMaterial)
                                            {
                                                var taskInfo = db.Default.Queryable<WCS_TaskInfo>().UpdLock().First(v => v.AgvTaskID == agv.ID);
                                                //if (taskInfo == null) throw new Exception($"未找到AGV任务{agv.ID}对应WCS任务");
                                                //更新AGV任务状态
                                                agv.Status = AGVTaskStatus.MissionCompleted;
                                                db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                                //更新WCS任务状态
                                                if (taskInfo != null)
                                                {
                                                    taskInfo.Status = Entity.TaskStatus.Finish;
                                                    taskInfo.EndTime = DateTime.Now;
                                                    db.Default.UpdateableRowLock(taskInfo).UpdateColumns(x => new { x.Status, x.EndTime }).ExecuteCommand();
                                                    taskInfo.AddWCS_TASK_DTL(db.Default, "agv", "任务完成");
                                                    taskInfos.Add(taskInfo);
                                                }  
                                            }
                                            else
                                            {
                                                agv.Status = AGVTaskStatus.MissionCompleted;
                                                db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                            }

                                            break;
                                        }
                                }
                            });
                        }
                        catch (Exception ex)
                        {
                            World.Log(ex.Message, LogLevelEnum.Mid);
                            this.ExRecord(obj.Entity.Code, ex.Message);
                        }
                    }
                }
            }
            else if (obj.Entity.Code == "AGVIn")
            {
                List<WCS_AgvTaskInfo> agvTaskInfos = new List<WCS_AgvTaskInfo>();
                //获取所有未结束的入库AGV任务
                SqlSugarHelper.Do(db =>
                {
                    agvTaskInfos = db.Default.Queryable<WCS_AgvTaskInfo>()
                                             .Where(v => v.Status < AGVTaskStatus.MissionCompleted && v.TaskType == AGVTaskType.EnterDepot)
                                             .SplitTable(tabs => tabs.Take(2)).OrderBy(v => v.EditTime).ToList();
                });

                if (agvTaskInfos.Any())
                {
                    foreach (var agv in agvTaskInfos)
                    {
                        try
                        {
                            SqlSugarHelper.Do(db =>
                            {
                                #region 开始跟据AGV状态做出处理

                                switch (agv.AgvStatus)
                                {
                                    case AGVTaskStatus.NewBuild when agv.Status == AGVTaskStatus.NewBuild:
                                        agv.AgvID = agv.ID.ToString();
                                        agv.Status = AGVTaskStatus.Confirm;
                                        agv.AgvStatus = AGVTaskStatus.Confirm;
                                        db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                        AgvApi.托盘回库(agv.Position, agv.ID.ToString(), agv.Station);
                                        break;
                                    //巷道分配
                                    case AGVTaskStatus.RequestOrPermission1 when agv.Status != AGVTaskStatus.Complete1:
                                        {
                                            var task = db.Default.Queryable<WCS_TaskOld>().NoLock().Where(x => x.Id == agv.TaskId).SplitTable(x => x.Take(2)).First();
                                            if (task == null) throw new Exception($"未找到对应的WCS任务{agv.TaskId}");

                                            //获取当前任务可以去的目标地址
                                            var positionList = new List<string>(); //当前分配点对应的放货点
                                            var allPositionList = new List<string>(); //同库区另一侧的放货点
                                            var nearPositionList = new List<string>(); //所有的放货点

                                            GetPositionList(positionList, nearPositionList, allPositionList, task.WarehouseCode);

                                            List<WCS_AgvTaskInfo> agvs = new List<WCS_AgvTaskInfo>(); //当前分配点对应的放货点已用点
                                            List<WCS_AgvTaskInfo> agvsNear = new List<WCS_AgvTaskInfo>(); //同库区另一侧的放货点已用点
                                            List<WCS_AgvTaskInfo> agvsAll = new List<WCS_AgvTaskInfo>(); //所有的放货点已用点

                                            agvs = db.Default.Queryable<WCS_AgvTaskInfo>().Where(v => v.Status > AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.MissionCompleted && v.TaskType == AGVTaskType.EnterDepot && positionList.Contains(v.Station))
                                                .SplitTable(v => v.Take(2)).ToList();
                                            agvsAll = db.Default.Queryable<WCS_AgvTaskInfo>().Where(v => v.Status > AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.MissionCompleted && v.TaskType == AGVTaskType.EnterDepot && allPositionList.Contains(v.Station))
                                                .SplitTable(v => v.Take(2)).ToList();
                                            agvsNear = db.Default.Queryable<WCS_AgvTaskInfo>().Where(v => v.Status > AGVTaskStatus.Confirm && v.Status < AGVTaskStatus.MissionCompleted && v.TaskType == AGVTaskType.EnterDepot && nearPositionList.Contains(v.Station))
                                                .SplitTable(v => v.Take(2)).ToList();
                                            //获取放货点
                                            var agvPositionLists = agvs.Select(x => x.Station).Distinct();
                                            var agvPositionListsNear = agvsNear.Select(x => x.Station).Distinct();
                                            var agvPositionListsAll = agvsAll.Select(x => x.Station).Distinct();
                                            //获取各区域可用点
                                            var endDev = positionList.Where(x => !agvPositionLists.Contains(x)).ToList();
                                            var endNearDev = nearPositionList.Where(x => !agvPositionListsNear.Contains(x)).ToList();
                                            var endAllDev = allPositionList.Where(x => !agvPositionListsAll.Contains(x)).ToList();

                                            World.Log($"agv可用巷道信息:{JsonConvert.SerializeObject(endDev)}");
                                            World.Log($"agv可用巷道信息(所有):{JsonConvert.SerializeObject(endAllDev)}");

                                            if (!endDev.Any() && !endAllDev.Any() && !endNearDev.Any())//没有可用放货站台
                                            {
                                                var msg = "已无可用放货站台,任务正在执行中:";
                                                foreach (var ag in agvs)
                                                {
                                                    msg += $"[任务号:{ag.ID},目标地址:{ag.Station}]";
                                                }
                                                throw new Exception(msg);
                                            }

                                            //获取没有光电信息的设备集合
                                            try
                                            {
                                                // 获取可用站台
                                                var devs = Device.All.Where(x => endDev.Contains(x.Code)).Select(x =>
                                                    new Device<IStation520, IStation521, IStation523>(x, World));
                                                devs = devs.Where(x =>
                                                    !x.Data3.Status.HasFlag(StationStatus.Run) &&
                                                    !x.Data3.Status.HasFlag(StationStatus.PH_Status) &&
                                                    x.Data3.Status.HasFlag(StationStatus.Auto)).ToList();

                                                var devsNear = Device.All.Where(x => endNearDev.Contains(x.Code)).Select(x =>
                                                    new Device<IStation520, IStation521, IStation523>(x, World));
                                                devsNear = devsNear.Where(x =>
                                                    !x.Data3.Status.HasFlag(StationStatus.Run) &&
                                                    !x.Data3.Status.HasFlag(StationStatus.PH_Status) &&
                                                    x.Data3.Status.HasFlag(StationStatus.Auto)).ToList();

                                                var devsAll = Device.All.Where(x => endAllDev.Contains(x.Code)).Select(x =>
                                                    new Device<IStation520, IStation521, IStation523>(x, World));
                                                devsAll = devsAll.Where(x =>
                                                    !x.Data3.Status.HasFlag(StationStatus.Run) &&
                                                    !x.Data3.Status.HasFlag(StationStatus.PH_Status) &&
                                                    x.Data3.Status.HasFlag(StationStatus.Auto)).OrderBy(v => allPositionList.Contains(v.Entity.Code)).ToList();
                                                if (!devs.Any()) //自身所属位置无可用放货点
                                                {
                                                    if (devsNear.Any())//先判断同库一侧
                                                    {
                                                        foreach (var dev in devsNear)
                                                        {
                                                            if (!dev.Data3.Status.HasFlag(StationStatus.Run) && !dev.Data3.Status.HasFlag(StationStatus.PH_Status) && dev.Data3.Status.HasFlag(StationStatus.Auto))
                                                            {
                                                                World.Log($"任务执行过程:开始{agv.ID}-{JsonConvert.SerializeObject(devsAll.Select(x => x.Entity.Code).ToList())}");
                                                                agv.Status = AGVTaskStatus.Complete1;
                                                                agv.Station = dev.Entity.Code;
                                                                db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                                                World.Log($"任务执行过程:完成agv任务更新{agv.ID}--{agv.Station}");
                                                                task.AddWCS_TASK_DTL(db.Default, "皮盘返库任务分配巷道", agv.Station, $"任务分配至:{agv.Station}");
                                                                World.Log($"任务执行过程:完成任务明细添加{agv.Station}");
                                                                AgvApi.ContinueTask(agv.AgvID, agv.Station);
                                                                World.Log($"任务执行过程:任务成功下发AGV{agv.AgvID}--{agv.Station}");
                                                                return;
                                                            }
                                                            
                                                        }
                                                    }
                                                    else if (devsAll.Any())
                                                    {
                                                        foreach (var dev in devsAll)
                                                        {
                                                            if (!dev.Data3.Status.HasFlag(StationStatus.Run) && !dev.Data3.Status.HasFlag(StationStatus.PH_Status) && dev.Data3.Status.HasFlag(StationStatus.Auto))
                                                            {
                                                                World.Log($"任务执行过程:开始{agv.ID}-{JsonConvert.SerializeObject(devsAll.Select(x => x.Entity.Code).ToList())}");
                                                                agv.Status = AGVTaskStatus.Complete1;
                                                                agv.Station = dev.Entity.Code;
                                                                db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                                                World.Log($"任务执行过程:完成agv任务更新{agv.ID}--{agv.Station}");
                                                                task.AddWCS_TASK_DTL(db.Default, "皮盘返库任务分配巷道", agv.Station, $"任务分配至:{agv.Station}");
                                                                World.Log($"任务执行过程:完成任务明细添加{agv.Station}");
                                                                AgvApi.ContinueTask(agv.AgvID, agv.Station);
                                                                World.Log($"任务执行过程:任务成功下发AGV{agv.AgvID}--{agv.Station}");
                                                                return;
                                                            }
                                                        }
                                                    }
                                                    World.Log("可用站台均有货或有执行中任务");
                                                    return;
                                                }

                                                World.Log($"任务执行过程:开始{agv.ID}-{JsonConvert.SerializeObject(devs.Select(x => x.Entity.Code).ToList())}");
                                                agv.Status = AGVTaskStatus.Complete1;
                                                agv.Station = devs.MinBy(x => x.Entity.Code).Entity.Code;
                                                db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                                World.Log($"任务执行过程:完成agv任务更新{agv.ID}--{agv.Station}");
                                                task.AddWCS_TASK_DTL(db.Default, "皮盘返库任务分配巷道", agv.Station, $"任务分配至:{agv.Station}");
                                                World.Log($"任务执行过程:完成任务明细添加{agv.Station}");
                                                AgvApi.ContinueTask(agv.AgvID, agv.Station);
                                                World.Log($"任务执行过程:任务成功下发AGV{agv.AgvID}--{agv.Station}");
                                            }
                                            catch (Exception e)
                                            {
                                                throw new Exception($"执行错误:{e.Message + e.StackTrace}");
                                            }

                                            break;
                                        }
                                    //取货站点安全交互
                                    case AGVTaskStatus.RequestOrPermission2 when agv.Status != AGVTaskStatus.RequestOrPermission2:
                                        {
                                            if (agv.Station.IsNullOrEmpty()) throw new Exception($"无有效放货地址");
                                            var dev = Device.All.First(x => x.Code == agv.Station);
                                            var ph = new Device<IStation523>(Device.All.First(x => x.Code == agv.Station), World);
                                            if (ph.Data.Status.HasFlag(StationStatus.PH_Status))
                                            {
                                                throw new Exception($"{agv.Station}站台有光电小车无法放货，请检查并处理");
                                            }
                                            //调继续执行任务接口
                                            AgvApi.ContinueTask(agv.AgvID, dev.Code);
                                            break;
                                        }
                                    case AGVTaskStatus.LeavePut when agv.Status != AGVTaskStatus.LeavePut:

                                        break;
                                    //完成任务
                                    case AGVTaskStatus.MissionCompleted when agv.Status != AGVTaskStatus.MissionCompleted:
                                        var taskold = db.Default.Queryable<WCS_TaskOld>().NoLock().Where(x => x.Id == agv.TaskId).SplitTable(x => x.Take(2)).First();
                                        if (agv.TaskType == AGVTaskType.EnterDepot)
                                        {
                                            agv.Status = AGVTaskStatus.MissionCompleted;
                                            db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                            var devinfo = new Device<IStation520, IStation521>(Device.All.First(x => x.Code == agv.Station), World);
                                            devinfo.Data.CmdType = StationCmd.Res2;
                                            if (taskold.LastInteractionPoint == "2") //如果是单独取空任务直接完成
                                            {
                                                var task = db.Default.Queryable<WCS_TaskInfo>().NoLock().Where(x => x.ID == agv.TaskId).First();
                                                if (task != null)
                                                {
                                                    task.Status = TaskStatus.Finish;
                                                    task.EndTime = DateTime.Now;
                                                    db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EndTime }).ExecuteCommand();
                                                    task.AddWCS_TASK_DTL(db.Default, "agv", "任务完成");
                                                }     
                                            }
                                        }
                                        break;

                                    case AGVTaskStatus.Cancel when agv.Status != AGVTaskStatus.Cancel:
                                        var taskold1 = db.Default.Queryable<WCS_TaskOld>().NoLock().Where(x => x.Id == agv.TaskId).SplitTable(x => x.Take(2)).First();
                                        agv.Status = AGVTaskStatus.Cancel;
                                        db.Default.UpdateableRowLock(agv).SplitTable(x => x.Take(2)).ExecuteCommand();
                                        if (taskold1.LastInteractionPoint == "2") //如果是单独取空任务直接取消
                                        {
                                            var task = db.Default.Queryable<WCS_TaskInfo>().NoLock().Where(x => x.ID == agv.TaskId).First();
                                            if (task != null)
                                            {
                                                task.Status = TaskStatus.Cancel;
                                                task.EndTime = DateTime.Now;
                                                db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EndTime }).ExecuteCommand();
                                                task.AddWCS_TASK_DTL(db.Default, "agv", "任务取消");
                                            }   
                                        }
                                        break;
                                }

                                #endregion 开始跟据AGV状态做出处理
                            });
                        }
                        catch (Exception ex)
                        {
                            if (ex.Message.Contains("SqlTransaction")) World.Log($"{ex.Message}:{ex.StackTrace}");
                            else World.Log(ex.Message, LogLevelEnum.Mid);
                        }
                    }
                }
            }
        }

        public override bool Select(Device dev)
        {
            return dev.Code is "AGVIn" or "AGVOut";
        }

        /// <summary>
        ///  获取可用放货点
        /// </summary>
        /// <param name="positionList"></param>
        /// <param name="nearPositionList"></param>
        /// <param name="allPositionList"></param>
        /// <param name="warehouseCode"></param>
        private void GetPositionList(List<string> positionList, List<string> nearPositionList, List<string> allPositionList, string warehouseCode)
        {
            switch (warehouseCode)
            {
                case "1N":
                    positionList.AddRange(new List<string>() { "2501", "2505", "2509", "2513" });
                    nearPositionList.AddRange(new List<string>() {
                                                        "2701", "2705", "2709", "2713" });
                    allPositionList.AddRange(new List<string>() {
                                                        "2901", "2905", "2909", "2913","3101", "3105", "3109", "3113", "3301", "3305", "3309", "3313","3501", "3505", "3509", "3513"});
                    break;

                case "1S":
                    positionList.AddRange(new List<string>() { "2701", "2705", "2709", "2713" });
                    nearPositionList.AddRange(new List<string>() {
                                                        "2501", "2505", "2509", "2513" });
                    allPositionList.AddRange(new List<string>() {
                                                        "3101", "3105", "3109", "3113", "2901", "2905", "2909", "2913", "3501", "3505", "3509", "3513", "3301", "3305", "3309", "3313"});
                    break;

                case "2N":
                    positionList.AddRange(new List<string>() { "2901", "2905", "2909", "2913" });
                    nearPositionList.AddRange(new List<string>() {
                                                        "3101", "3105", "3109", "3113" });
                    allPositionList.AddRange(new List<string>() {
                                                        "2501" , "2505" , "2509" , "2513" , "2701", "2705", "2709", "2713","3301", "3305", "3309", "3313", "3501", "3505", "3509", "3513"});
                    break;

                case "2S":
                    positionList.AddRange(new List<string>() { "3101", "3105", "3109", "3113" });
                    nearPositionList.AddRange(new List<string>() {
                                                        "2901", "2905", "2909", "2913" });
                    allPositionList.AddRange(new List<string>() {
                                                        "2701" , "2705" , "2709" , "2713" ,"2501" , "2505" , "2509" , "2513" ,  "3501" , "3505" , "3509" , "3513","3301", "3305", "3309", "3313"});
                    break;

                case "3N":
                    positionList.AddRange(new List<string>() { "3301", "3305", "3309", "3313" });
                    nearPositionList.AddRange(new List<string>() {
                                                        "3501", "3505", "3509", "3513" });
                    allPositionList.AddRange(new List<string>() {
                                                        "2901", "2905", "2909", "2913", "3101", "3105", "3109", "3113","2501" , "2505" , "2509" , "2513" , "2701", "2705", "2709", "2713" });
                    break;

                case "3S":
                    positionList.AddRange(new List<string>() { "3501", "3505", "3509", "3513" });
                    nearPositionList.AddRange(new List<string>() {
                                                        "3301", "3305", "3309", "3313" });
                    allPositionList.AddRange(new List<string>() {
                                                        "3101", "3105", "3109", "3113", "2901", "2905", "2909", "2913", "2701" , "2705" , "2709" , "2713" ,"2501" , "2505" , "2509" , "2513" });
                    break;
            }
        }
    }
}