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.Worlds;
using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags;
using TaskStatus = WCS.Entity.TaskStatus;

namespace WCS.WorkEngineering.Systems
{
    /// <summary>
    ///  分流点
    /// </summary>
    [BelongTo(typeof(SortingBranchWorld))]
    [Description("环形库分流点")]
    public class 环形库分流点 : DeviceSystem<Device<IStation520, IStation521, IStation523, IStation91>>
    {
        protected override bool ParallelDo => true;

        protected override bool SaveLogsToFile => true;

        public override void Do(Device<IStation520, IStation521, IStation523, IStation91> obj)
        {
            if (obj.Data.VoucherNo != obj.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{obj.Data.VoucherNo}-DB521:{obj.Data2.VoucherNo}", LogLevelEnum.High);
            if (obj.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
            if (!obj.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
            if (obj.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);

            //处理异常任务
            if (obj.Data2.TaskNumber == 1)
            {
                obj.Data.TaskNumber = 591;
                obj.Data.GoodsStart = obj.Entity.Code.ToShort();
                obj.Data.GoodsEnd = 591;
                obj.Data.VoucherNo++;
                World.Log($"执行记录:任务号[{591}]-[{obj.Data.VoucherNo}]");
            }

            var isPut = false;
            short nextAdd = 0;
            SqlSugarHelper.Do(_db =>
            {
                var db = _db.Default;
                var taskInfo = db.Queryable<WCS_TaskInfo>().First(v => v.ID == obj.Data2.TaskNumber && v.Status == TaskStatus.WaitingToExecute) ?? throw new KnownException($"未找到对应的WCS任务{obj.Data2.TaskNumber}", LogLevelEnum.Mid);
                switch (obj.Data4.Length)
                {
                    case 9:
                        isPut = Allot09Or18(db, taskInfo, obj);
                        nextAdd = 455;
                        break;

                    case 18:
                        nextAdd = 442;
                        taskInfo.AddrNext = nextAdd.ToString();
                        taskInfo.Status = TaskStatus.FinishOfShunt;
                        taskInfo.EditTime = DateTime.Now;
                        taskInfo.WarehouseCode += "R";
                        taskInfo.AddrTo = "Robot";
                        taskInfo.GoodsType = obj.Data4.Length.ToInt();
                        db.Updateable(taskInfo).ExecuteCommand();
                        taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流");
                        isPut = true;
                        obj.Data.CmdType = StationCmd.Res6;
                        break;

                    case 50:
                        nextAdd = 424;
                        taskInfo.AddrNext = nextAdd.ToString();
                        taskInfo.Status = TaskStatus.FinishOfShunt;
                        taskInfo.EditTime = DateTime.Now;
                        taskInfo.WarehouseCode += "R";
                        taskInfo.AddrTo = "Robot";
                        taskInfo.GoodsType = obj.Data4.Length.ToInt();
                        db.Updateable(taskInfo).ExecuteCommand();
                        taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流");
                        isPut = true;
                        break;

                    case 34:
                        nextAdd = 433;
                        taskInfo.AddrNext = nextAdd.ToString();
                        taskInfo.Status = TaskStatus.FinishOfShunt;
                        taskInfo.EditTime = DateTime.Now;
                        taskInfo.WarehouseCode += "R";
                        taskInfo.AddrTo = "Robot";
                        taskInfo.GoodsType = obj.Data4.Length.ToInt();
                        db.Updateable(taskInfo).ExecuteCommand();
                        taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流");
                        isPut = true;
                        break;
                }
            });
            if (!isPut) return;
            obj.Data.TaskNumber = obj.Data2.TaskNumber;
            obj.Data.GoodsStart = obj.Entity.Code.ToShort();
            obj.Data.GoodsEnd = nextAdd;
            obj.Data.VoucherNo++;
            World.Log($"执行记录:任务号[{obj.Data2.TaskNumber}]-[{obj.Data.VoucherNo}]");
        }

        public override bool Select(Device dev)
        {
            return dev.HasFlag(DeviceFlags.环形库分流点);
        }

        /// <summary>
        ///  计算非零九或18的去向
        /// </summary>
        /// <param name="db"></param>
        /// <param name="taskInfo"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool AllotNot09Or18(SqlSugarScopeProvider db, WCS_TaskInfo taskInfo, Device<IStation520, IStation521, IStation523, IStation91> obj)
        {
            return false;
        }

        /// <summary>
        ///  计算09/18去向
        /// </summary>
        /// <param name="db"></param>
        /// <param name="taskInfo"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool Allot09Or18(SqlSugarScopeProvider db, WCS_TaskInfo taskInfo, Device<IStation520, IStation521, IStation523, IStation91> obj)
        {
            //TODO：暂时不来考虑动态计算可前往的目标
            var nextAdd = taskInfo.WarehouseCode switch
            {
                "1N" => "455",
                "1S" => "455",
                "2N" => "455",
                "2S" => "455",
                "3N" => "455",
                "3S" => "455",
                _ => "0"
            };
            //获取这个地址的下一个地址集合
            var cacheLineDevList = Device.All.First(x => x.Code == nextAdd).Targets.Where(x => x.HasFlag(DeviceFlags.桁架缓存放行点));
            var cacheLineCodes = cacheLineDevList.Select(x => x.Code.ToShort());
            var cacheLineList = db.Queryable<WCS_CacheLine>().Includes(x => x.Locations).ToList();

            #region 跟据缓存信息寻找可以到达的缓存点

            //找到当前任务可用的缓存线信息
            var cacheLine = cacheLineList.Where(x => x.Locations.Any(l => l is { InStock: false, IsEmpty: false })).FirstOrDefault(x => cacheLineCodes.Contains(x.LocationNo) && x.MatCodeList.Contains(taskInfo.MatCode) && !x.InStock);

            if (cacheLine != null)//这个任务可以直接去一条线体，不需要新建缓存信息
            {
                //找到这条线体中序号最小的一条位信息 非空置且无货
                var cacheLoc = cacheLine.Locations.Where(x => x is { InStock: false, IsEmpty: false }).MinBy(x => x.XYNo);
                if (cacheLoc != null)
                {
                    cacheLoc = db.Queryable<WCS_CacheLineLoc>().Single(x => x.Id == cacheLoc.Id);
                    cacheLoc.InStock = true;
                    cacheLoc.TaskId = taskInfo.ID;
                    cacheLoc.EditTime = DateTime.Now;
                    db.Updateable(cacheLoc).ExecuteCommand();

                    //WCS任务相关信息
                    taskInfo.Status = TaskStatus.FinishOfShunt;
                    taskInfo.AddrNext = cacheLine.LocationNo.ToString();
                    taskInfo.EditWho = "WCS";
                    taskInfo.EditTime = DateTime.Now;
                    taskInfo.GoodsType = obj.Data4.Length.ToInt();
                    db.Updateable(taskInfo).ExecuteCommand();
                    taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}");

                    return true;
                }
            }

            #endregion 跟据缓存信息寻找可以到达的缓存点

            #region 初始化一个信息的缓存信息

            //TODO:暂时不处理就近分线的逻辑
            var devCode = cacheLineDevList.Select(x => x.Code.ToShort()).FirstOrDefault(x => !cacheLineList.Select(s => s.LocationNo).Contains(x));
            if (devCode == 0)
            {
                World.Log($"无可用线体:{taskInfo.ID}");
                return false;
            }
            var result = false;

            //未结束且包含当前物料编号的垛形,按时间排序，创建时间早的优先分配
            var palletizingList = db.Queryable<WCS_Palletizing>()
                .Includes(x => x.Layers, r => r.Rows, l => l.Locs)
                .Where(x => !x.Finish)
                .Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
                .OrderBy(x => x.AddTime)
                .ToList();

            foreach (var palletizing in palletizingList)
            {
                //当前任务已经分配结束，进入下一次迭代
                if (result) continue;

                //未结束且包含当前物料编号的层,按层号排序，层号小的优先分配
                var layers = palletizing.Layers.Where(x => x is { IsEmpty: false, Finish: false })
                    .Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
                    .OrderBy(x => x.LayerNo)
                    .ToList();

                //未找到可用层，进入下一次迭代
                if (!layers.Any()) continue;
                foreach (var layer in layers)
                {
                    //当前任务已经分配结束，进入下一次迭代
                    if (result) continue;

                    //未结束，未预分配缓存线信息且包含当前物料编号的行，行号小的优先分配
                    var rows = layer.Rows.Where(x => x is { IsEmpty: false, Finish: false })
                        .Where(x => x.CacheLineId == 0)
                        .Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
                        .ToList();
                    //未找到可用行，进入下一次迭代
                    if (!rows.Any()) continue;
                    var palletizingRow = rows.MinBy(x => x.RowNo);

                    //开始初始化缓存位信息
                    cacheLine = new WCS_CacheLine()
                    {
                        LocationNo = devCode,
                        AddTime = DateTime.Now,
                        PalletizingRowId = palletizingRow.Id,
                        InStock = false,
                        Put = false,
                        IsTruss = false,
                        MatCodeList = palletizingRow.MatCodeList
                    };

                    var res = db.Insertable(cacheLine).ExecuteReturnEntity();
                    palletizingRow = db.Queryable<WCS_PalletizingRow>().Includes(x => x.Locs).Single(x => x.Id == palletizingRow.Id);
                    palletizingRow.Locs = palletizingRow.Locs.OrderBy(x => x.XYNo).ToList();
                    palletizingRow.CacheLineId = res.Id;
                    palletizingRow.EditTime = DateTime.Now;
                    db.Updateable(palletizingRow).ExecuteCommand();

                    for (var i = 0; i < palletizingRow.Locs.Count; i++)
                    {
                        var loc = new WCS_CacheLineLoc()
                        {
                            XYNo = palletizingRow.Locs[i].XYNo,
                            InStock = i == 0,
                            IsEmpty = palletizingRow.Locs[i].IsEmpty,
                            MatCode = palletizingRow.Locs[i].MatCode,
                            TaskId = i == 0 ? taskInfo.ID : 0,
                            CacheLineId = res.Id
                        };
                        db.Insertable(loc).ExecuteCommand();
                    }

                    taskInfo.Status = TaskStatus.FinishOfShunt;
                    taskInfo.AddrNext = devCode.ToString();
                    taskInfo.EditWho = "WCS";
                    taskInfo.EditTime = DateTime.Now;
                    taskInfo.GoodsType = obj.Data4.Length.ToInt();
                    db.Updateable(taskInfo).ExecuteCommand();
                    taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}");
                    result = true;
                }
            }

            if (!result)
            {
                taskInfo.InitStackStructure(db);
            }
            return result;
            ////找到所有当前轮子可以去的垛形
            //var palletizingList = db.Queryable<WCS_Palletizing>()
            //    .Includes(x => x.Layers, r => r.Rows, l => l.Locs)
            //    .Where(x => x.MatCodeList.Contains(taskInfo.MatCode) && !x.Finish).ToList()
            //    .Where(x => x.Layers.SelectMany(x => x.Rows).Any(r => r.LineCode == null))
            //    .OrderBy(x => x.AddTime).ToList();
            ////如果没有对应的垛形信息就初始化一个垛形信息
            //if (palletizingList.Count <= 0)
            //{
            //    taskInfo.InitStackStructure(db);
            //    return false;
            //}

            //var b = palletizingList.Select(palletizing => palletizing.Layers
            //        .Where(x => !x.IsEmpty)
            //        .Where(x => !x.Finish)
            //        .Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
            //        .Where(x => x.Rows.Any(r => r is { IsEmpty: false, Finish: false } && r.MatCodeList.Contains(taskInfo.MatCode) && r.CacheLineId == 0))
            //        .MinBy(x => x.LayerNo)).Where(x => x != null);

            //foreach (var palletizingLayer in b)
            //{
            //    //如果没有哪一层需要这个物料号，就初始化一个新的垛形信息
            //    if (palletizingLayer == null)
            //    {
            //        taskInfo.InitStackStructure(db);
            //        return false;
            //    }

            //    //再找行:未空置、未结束
            //    var palletizingRow = palletizingLayer.Rows.Where(x => x is { IsEmpty: false, Finish: false } && x.MatCodeList.Contains(taskInfo.MatCode) && x.CacheLineId == 0)
            //        .MinBy(x => x.RowNo);
            //    //如果没有哪一行需要这个物料号，就初始化一个新的垛形信息
            //    if (palletizingRow == null)
            //    {
            //        taskInfo.InitStackStructure(db);
            //        return false;
            //    }
            //    //走到这一步就表示没有哪一段线体缓存了当前物料，需要选一段新的线体进行缓存

            //    //TODO:暂时不处理就近分线的逻辑
            //    //获取一个当前可以使用的分配锁
            //    var devCode = cacheLineDevList.Select(x => x.Code.ToShort()).FirstOrDefault(x => !cacheLineList.Select(s => s.LocationNo).Contains(x));
            //    if (devCode == 0)
            //    {
            //        World.Log($"无可用线体:{taskInfo.ID}");
            //        return false;
            //    }

            //    //开始初始化缓存位信息
            //    cacheLine = new WCS_CacheLine()
            //    {
            //        LocationNo = devCode,
            //        AddTime = DateTime.Now,
            //        PalletizingRowId = palletizingRow.Id,
            //        InStock = false,
            //        Put = false,
            //        IsTruss = false,
            //        MatCodeList = palletizingRow.MatCodeList
            //    };

            //    var res = db.Insertable(cacheLine).ExecuteReturnEntity();
            //    palletizingRow = db.Queryable<WCS_PalletizingRow>().Includes(x => x.Locs).Single(x => x.Id == palletizingRow.Id);
            //    palletizingRow.Locs = palletizingRow.Locs.OrderBy(x => x.XYNo).ToList();
            //    palletizingRow.CacheLineId = res.Id;
            //    palletizingRow.EditTime = DateTime.Now;
            //    db.Updateable(palletizingRow).ExecuteCommand();

            //    for (var i = 0; i < palletizingRow.Locs.Count; i++)
            //    {
            //        var loc = new WCS_CacheLineLoc()
            //        {
            //            XYNo = palletizingRow.Locs[i].XYNo,
            //            InStock = i == 0,
            //            IsEmpty = palletizingRow.Locs[i].IsEmpty,
            //            MatCode = palletizingRow.Locs[i].MatCode,
            //            TaskId = i == 0 ? taskInfo.ID : 0,
            //            CacheLineId = res.Id
            //        };
            //        db.Insertable(loc).ExecuteCommand();
            //    }

            //    taskInfo.Status = TaskStatus.FinishOfShunt;
            //    taskInfo.AddrNext = devCode.ToString();
            //    taskInfo.EditWho = "WCS";
            //    taskInfo.EditTime = DateTime.Now;
            //    taskInfo.GoodsType = obj.Data4.Length.ToInt();
            //    db.Updateable(taskInfo).ExecuteCommand();
            //    taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}");

            //    return true;
            //}

            #endregion 初始化一个信息的缓存信息
        }
    }
}
