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 ThirdFloorPoint
    {
        private readonly LoggerUtils _logger = new LoggerUtils();
        private readonly IHost _host;
        private readonly BasePlcpoint LineRFID;
        private readonly BasePlcpoint LineSignal;
        int FloorNo { get; set; }
        public ThirdFloorPoint(IHost host, int floor)
        {
            this._host = host;
            FloorNo = floor;
            this.LineRFID = StaticData.BasePlcpointList.First(t => t.plcpointNo == "RFID003");
            this.LineSignal = StaticData.BasePlcpointList.First(t => t.plcpointNo == "linesignal03");
        }
        /// <summary>
        /// 启动上件扫描监听
        /// </summary>
        public void StartPoint()
        {

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

        public void MonitorInLocatorPoint()
        {
            List<int> ITypes = new List<int> { 1, 3, 5, 7 };
            using var scope = _host.Services.CreateScope();
            using var dbContext = scope.ServiceProvider.GetRequiredService<DefaultDbContext>();
            List<string> canNotIn = new List<string>();
            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);
                    if (rfid != null && isSignal != null)
                    {
                        if (Convert.ToInt32(isSignal) == 1)//托盘到位
                        {
                            BaseEquip baseEquip = StaticData.BaseEquip.First(t => t.floorNo == 3 && t.equipType == 1);
                            var wcsTask = dbContext.WcsTask.FirstOrDefault(t => t.nextPointId == baseEquip.objid);
                            var AgvEquip = StaticData.BaseEquip.First(t => t.floorNo == 3 && t.equipType == 4);//背负Agv
                            if (wcsTask != null)//如果不是null
                            {
                                if (wcsTask.taskStatus == 5)//提升机任务是完成状态
                                {
                                    lock (SystemData.ThirdTaskLock)
                                    {
                                        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)
                                            {
                                                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.locationStatus == "1")
                                                      .OrderByDescending(t => t.locRow)
                                                      .ThenByDescending(t => t.locColumn)
                                                      .ToList();

                                                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 == 311)
                                                    .Where(t => containerCodes.Contains(t.palletInfoCode)).ToList();

                                                var bill = from a in wmsRawStocks
                                                           join b in wmsBaseLocations.Where(t => t.locDeep == 1 && !string.IsNullOrEmpty(t.containerCode)) on a.palletInfoCode equals b.containerCode
                                                           select new { b };//等于当前任务的物料的托盘的库位信息


                                                var outBill = from b in wmsBaseLocations
                                                              from a in bill
                                                              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 { b };//在上面的基础上获取对应托盘的外侧库位的空库位信息
                                                WmsBaseLocation? 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();//找不到再找任意库位

                                                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;
                                                        }
                                                    }
                                                    dbContext.Remove(wcsTask);
                                                    WcsTask newTask = CoreMapper.Map<WcsTask>(wcsTask);
                                                    newTask.objid = StaticData.SnowId.NextId();
                                                    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.taskType = StaticTaskType.ThirdRawIn;
                                                    newTask.useFlag = 1;
                                                    wmsBaseLocation.locationStatus = "2";
                                                    SystemData.LockOutLocation(wmsBaseLocation, dbContext);
                                                    dbContext.Update(wmsBaseLocation);
                                                    dbContext.Add(newTask);
                                                    WcsTaskLog wcsTaskLog = CoreMapper.Map<WcsTaskLog>(newTask);
                                                    dbContext.Add(wcsTaskLog);
                                                    dbContext.SaveChanges();
                                                    canNotIn.Clear();
                                                    Console.WriteLine(DateTime.Now + $":三楼接驳位调度入库任务,物料{mesBaseBarcodeInfo.materialId},托盘{rfid},库位{wmsBaseLocation.locationCode}");
                                                    _logger.Info($"三楼接驳位调度入库任务,物料{mesBaseBarcodeInfo.materialId},托盘{rfid},库位{wmsBaseLocation.locationCode}");
                                                }
                                                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.containerNo = rfid;
                                    newTask.nextPointId = nextEquip.objid;
                                    newTask.nextPointNo = nextEquip.equipNo;
                                    newTask.currPointId = baseEquip.objid;
                                    newTask.currPointNo = baseEquip.equipNo;
                                    newTask.fromFloorNo = FloorNo;
                                    newTask.taskStatus = 0;
                                    newTask.updateTime = DateTime.Now;
                                    dbContext.Add(newTask);
                                    WcsTaskLog wcsTaskLog = CoreMapper.Map<WcsTaskLog>(newTask);
                                    dbContext.Add(wcsTaskLog);
                                    dbContext.SaveChanges();
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (ex is PlcException)
                    {

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