using Khd.Core.Domain.Dto.TaskType;
using Khd.Core.Domain.Models;
using Khd.Core.EntityFramework;
using Khd.Core.Library;
using Khd.Core.Library.Mapper;
using Khd.Core.Plc.S7;
using Khd.Core.Wcs.Global;
using Masuit.Tools;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Z.EntityFramework.Plus;

namespace Khd.Core.Wcs.Wcs
{
    /// <summary>
    /// 五楼接驳位调度
    /// </summary>
    public class FiveFloorPoint
    {
        private readonly IHost _host;
        private readonly BasePlcpoint LineRFID;
        private readonly BasePlcpoint LineSignal;
        private readonly LoggerUtils _logger = new LoggerUtils();
        int FloorNo { get; set; }
        string EquipNo = "";
        public FiveFloorPoint(IHost host, int floor)
        {
            this._host = host;
            FloorNo = floor;
            this.LineRFID = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID005");
            this.LineSignal = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal05");

        }
        /// <summary>
        /// 启动上件扫描监听
        /// </summary>
        public void StartPoint()
        {

            var FlowPointThread = new Thread(MonitorInLocatorPoint);
            FlowPointThread.IsBackground = true;
            FlowPointThread.Name = "FiveFloorPoint";
            FlowPointThread.Start();
            Console.WriteLine(DateTime.Now + ":五楼接驳位调度启动成功");
            _logger.Info("五楼接驳位调度启动成功");
        }

        public void MonitorInLocatorPoint()
        {
            List<int?> ITypes = new() { 1, 3, 5, 7 };
            using var scope = _host.Services.CreateScope();
            using var dbContext = scope.ServiceProvider.GetRequiredService<DefaultDbContext>();
            List<string> canNotIn = new();
            string lastRFID = string.Empty;
            while (true)
            {
                try
                {
                    dbContext.ChangeTracker.Entries().ToList().ForEach(e => e.Reload());
                    //入库任务
                    var rfid = StaticData.PlcDic[0].ReadRFID(LineRFID.plcpointAddress);
                    var isSignal = StaticData.PlcDic[0].Read(LineSignal.plcpointAddress);
                    BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.equipType == 1 && t.floorNo == FloorNo);
                    if (rfid != null && isSignal != null)
                    {

                        //正常读到输送线信息 有到位信号,并且有托盘,获取条码信息
                        if (Convert.ToInt32(isSignal) == 1)//五楼接驳位
                        {
                            //获取条码信息
                            var wcsTask = dbContext.WcsTask.OrderBy(t => t.createTime)
                                .FirstOrDefault(t => t.containerNo == rfid && t.nextPointId == baseEquip.objid);
                            if (wcsTask != null)
                            {
                                if (StaticData.BigContainerCodes.Contains(rfid))
                                {
                                    if (rfid == lastRFID)
                                    {
                                        continue;
                                    }
                                    MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.FirstOrDefault(t => t.palletInfoCode == rfid);
                                    if (mesBasePalletInfo != null)
                                    {
                                        MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.Where(t => t.palletInfoCode == rfid).FirstOrDefault();
                                        if (mesBaseBarcodeInfo != null)
                                        {
                                            mesBaseBarcodeInfo.palletInfoCode = null;
                                            dbContext.Update(mesBaseBarcodeInfo);
                                        }
                                        mesBasePalletInfo.bindAmount = null;
                                        mesBasePalletInfo.bindAmount = null;
                                        mesBasePalletInfo.materialBarcode = null;
                                        mesBasePalletInfo.materialCode = null;
                                        mesBasePalletInfo.materialId = null;
                                        mesBasePalletInfo.materialName = null;
                                        mesBasePalletInfo.updateBy = "WCS";
                                        mesBasePalletInfo.updateTime = DateTime.Now;
                                        dbContext.Update(mesBasePalletInfo);
                                        dbContext.Remove(wcsTask);
                                        dbContext.WcsTaskLog.Where(t => t.objid == wcsTask.objid).Update(t => new WcsTaskLog { taskStatus = 6 });
                                        dbContext.SaveChanges();
                                        lastRFID = rfid;
                                    }
                                }
                                else//小托盘
                                {
                                    if (wcsTask.taskStatus == 5)//入库,提升机任务是完成状态
                                    {
                                        lock (SystemData.FiveTaskLock)
                                        {
                                            var wmsBaseLocations = dbContext.WmsBaseLocation.Where(t => t.warehouseFloor == FloorNo)
                                            .Where(t => t.activeFlag == "1")
                                            .Where(t => t.delFlag == "0")
                                            .Where(t => t.locationScrapType == "1")
                                            .Where(t => t.warehouseId == 511)
                                            .Where(t => t.locationStatus == "1")
                                            .ToList();
                                            if (wmsBaseLocations.Count > 0)
                                            {
                                                MesBasePalletInfo? mesBasePalletInfo = dbContext.MesBasePalletInfo.Where(t => t.palletInfoCode == rfid).FirstOrDefault();
                                                if (mesBasePalletInfo != null)
                                                {
                                                    MesBaseBarcodeInfo? mesBaseBarcodeInfo = dbContext.MesBaseBarcodeInfo.FirstOrDefault(t => t.barcodeInfo == mesBasePalletInfo.materialBarcode);
                                                    if (mesBaseBarcodeInfo != null)
                                                    {
                                                        List<string> containerCodes = wmsBaseLocations
                                                            .Where(t => t.locDeep == 1)
                                                            .Select(t => t.containerCode).ToList();//深库位的托盘
                                                        containerCodes.RemoveAll(t => string.IsNullOrEmpty(t));
                                                        List<WmsRawStock> wmsRawStocks = dbContext.WmsRawStock
                                                                .Where(t => t.materialId == mesBaseBarcodeInfo.materialId)
                                                                .Where(t => t.saleOrderId == mesBaseBarcodeInfo.saleOrderId)
                                                                .Where(t => t.palletInfoCode != null)
                                                                .Where(t => t.warehouseId == 511)
                                                                .Where(t => containerCodes.Contains(t.palletInfoCode)).ToList();

                                                        var bill = from a in wmsRawStocks
                                                                   join b in wmsBaseLocations
                                                                   .Where(t => t.locDeep == 1 && mesBaseBarcodeInfo.completeFlag == "0" ? t.returnFlag == "1" : t.returnFlag == "0") on a.palletInfoCode equals b.containerCode
                                                                   select new { b };//等于当前任务的物料的托盘的库位信息
                                                        var outBill = from a in bill
                                                                      from b in wmsBaseLocations
                                                                      where b.locDeep == 2
                                                                      && b.locRow == (a.b.locRow % 2 == 0 ? a.b.locRow - 1 : a.b.locRow + 1)
                                                                      && a.b.locColumn == b.locColumn
                                                                      && b.locationStatus == "1"
                                                                      && string.IsNullOrEmpty(b.containerCode)
                                                                      select new { a, b };//在上面的基础上获取对应托盘的外侧库位的空库位信息
                                                        if (mesBaseBarcodeInfo.completeFlag == "0")
                                                        {
                                                            outBill = outBill.OrderByDescending(t => t.b.locColumn).ToList();
                                                            wmsBaseLocations = wmsBaseLocations.OrderByDescending(t => t.locColumn).ToList();
                                                        }
                                                        else
                                                        {
                                                            outBill = outBill.OrderBy(t => t.b.locColumn).ToList();
                                                            wmsBaseLocations = wmsBaseLocations.OrderBy(t => t.locColumn).ToList();
                                                        }
                                                        WmsBaseLocation? wmsBaseLocation = null;
                                                        wmsBaseLocation ??= outBill.Where(t => !canNotIn.Contains(t.b.locationCode)).FirstOrDefault()?.b;//先找相同物料的外侧库位
                                                        wmsBaseLocation ??= wmsBaseLocations.Where(t => !canNotIn.Contains(t.locationCode)).Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault(t => t.locDeep == 1);//找不到再找深库位
                                                        wmsBaseLocation ??= wmsBaseLocations.Where(t => !canNotIn.Contains(t.locationCode)).Where(t => string.IsNullOrEmpty(t.containerCode)).FirstOrDefault();//找不到再找任意库位
                                                                                                                                                                                                               //深浅库位问题？库位入库优先级等

                                                        var AgvEquip = StaticData.BaseEquip.First(t => t.objid == 28);//5楼叉车
                                                        if (wmsBaseLocations.Count > 0 && wmsBaseLocation != null)
                                                        {
                                                            if (wmsBaseLocation.locDeep == 1)
                                                            {
                                                                bool hasLocation = wmsBaseLocations
                                                                .Where(t => t.locRow == (wmsBaseLocation.locRow % 2 == 1 ? (wmsBaseLocation.locRow + 1) : (wmsBaseLocation.locRow - 1)))
                                                                .Where(t => t.locColumn == wmsBaseLocation.locColumn)
                                                                .Where(t => !string.IsNullOrEmpty(t.containerCode) || t.locationStatus != "1")
                                                                .Any();
                                                                if (hasLocation)
                                                                {
                                                                    canNotIn.Add(wmsBaseLocation.locationCode);
                                                                    Console.WriteLine(DateTime.Now + $":目标库位{canNotIn.Join(",")}的浅库位库位状态异常，无法入库");
                                                                    _logger.Info($"目标库位{canNotIn.Join(",")}的浅库位库位状态异常，无法入库");
                                                                    continue;
                                                                }
                                                            }
                                                            WcsTask newTask = CoreMapper.Map<WcsTask>(wcsTask);
                                                            newTask.taskStatus = 0;//创建状态
                                                            newTask.updateTime = DateTime.Now;
                                                            newTask.currPointId = baseEquip.objid;
                                                            newTask.currPointNo = baseEquip.equipNo;
                                                            newTask.nextPointId = AgvEquip.objid;
                                                            newTask.nextPointNo = AgvEquip.equipNo;
                                                            newTask.endPointId = wmsBaseLocation.locationId;
                                                            newTask.endPointNo = wmsBaseLocation.locationCode;
                                                            newTask.objid = StaticData.SnowId.NextId();
                                                            newTask.createTime = DateTime.Now;
                                                            newTask.taskType = StaticTaskType.FiveRawIn;
                                                            if (newTask.fromFloorNo != 1)//如果不是一楼来的，需要通过接口确认入库（质检通过后，点击继续入库）
                                                            {
                                                                newTask.useFlag = 0;
                                                            }
                                                            else
                                                            {
                                                                newTask.useFlag = 1;
                                                            }
                                                            wmsBaseLocation.locationStatus = "2";
                                                            dbContext.Update(wmsBaseLocation);
                                                            dbContext.Remove(wcsTask);
                                                            SystemData.LockOutLocation(wmsBaseLocation, dbContext);

                                                            dbContext.Add(newTask);
                                                            WcsTaskLog wcsTaskLog = CoreMapper.Map<WcsTaskLog>(newTask);
                                                            dbContext.Add(wcsTaskLog);
                                                            dbContext.SaveChanges();
                                                            canNotIn.Clear();
                                                        }
                                                        else
                                                        {
                                                            Console.WriteLine(DateTime.Now + ":五楼接驳位调度入库任务,未找到库位");
                                                            _logger.Info("五楼接驳位调度入库任务,未找到库位");
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    else if (wcsTask.taskStatus == 6) //出库任务,小车任务是完成状态
                                    {
                                        BaseEquip nextEquip = StaticData.BaseEquip.First(t => t.equipType == 2);//提升机
                                        dbContext.Remove(wcsTask);
                                        WcsTask newTask = CoreMapper.Map<WcsTask>(wcsTask);
                                        newTask.objid = StaticData.SnowId.NextId();
                                        newTask.serialNo = SystemData.GetSerialNo(dbContext);
                                        newTask.nextPointId = nextEquip.objid;
                                        newTask.nextPointNo = nextEquip.equipNo;
                                        newTask.currPointId = baseEquip.objid;
                                        newTask.currPointNo = baseEquip.equipNo;
                                        newTask.fromFloorNo = FloorNo;
                                        newTask.taskType = 6;//成品出库
                                        newTask.floorNo = 1;//出库楼层
                                        newTask.taskStatus = 0;
                                        newTask.createTime = DateTime.Now;
                                        dbContext.Add(newTask);
                                        WcsTaskLog wcsTaskLog = CoreMapper.Map<WcsTaskLog>(newTask);
                                        dbContext.WcsTaskLog.Add(wcsTaskLog);
                                        dbContext.SaveChanges();
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (ex is PlcException)
                    {

                    }
                    else
                    {
                        _logger.Error(ex.Message + "\n" + ex.StackTrace);
                    }
                }
                finally
                {
                    Thread.Sleep(1000);
                }
            }
        }
    }
}
