using AngleSharp.Dom;
using Khd.Core.Domain.Dto.wcs;
using Khd.Core.Domain.Models;
using Khd.Core.EntityFramework;
using Khd.Core.Wcs.Global;
using Masuit.Tools.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Khd.Core.Domain.Dto.webapi;

using Khd.Core.Plc.S7;

using Khd.Core.Wcs.Wcs;
using System.Data;
using Microsoft.EntityFrameworkCore;
using Z.EntityFramework.Plus;
using Masuit.Tools;
using Microsoft.IdentityModel.Tokens;

namespace Khd.Core.Wcs.Wcs
{
    /// <summary>
    /// 出库点线程
    /// </summary>
    public class OutWarePoint
    {
        private readonly IHost _host;
        private readonly Plc.S7.Plc _plc;
        List<NodeSetting> ScanPoint { get; set; }//点位信息
        BaseSitenode? sitenode { get; set; }//站台信息

        NodeSetting? NodeSettingCarNo { get; set; }
        NodeSetting? NodeSettingCarState { get; set; }
        NodeSetting? NodeSettingCarRun { get; set; }
        NodeSetting? NodeSettingWcsState { get; set; }
        NodeSetting? NodeSettingWcsSend { get; set; }
        NodeSetting? NodeSettingWcsSendMaterial { get; set; }
        NodeSetting? NodeSettingPLCSendSendMaterialstate { get; set; }
        Thread FlowPointThread;
        public OutWarePoint(IHost host, Plc.S7.Plc plc, string siteNo)
        {
            this._host = host;
            this._plc = plc;
            //this.ScanPoint = StaticData.NodeSettingList.Where(t => t.siteNo == siteNo).ToList();//加载当前站点所对应的点位
            this.sitenode = StaticData.SiteNodeList.FirstOrDefault(t => t.siteNo == siteNo);//获取当前站台信息
            this.NodeSettingCarNo = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carno"));
            this.NodeSettingCarState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carstate"));
            this.NodeSettingCarRun = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carrun"));
            this.NodeSettingWcsState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("plcsendK"));
            this.NodeSettingWcsSend = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcsend"));
            this.NodeSettingWcsSendMaterial = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcssendmessage"));
            this.NodeSettingPLCSendSendMaterialstate = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("plcsendmessage"));
            try
            {
                //默认启动,清理plc的上位机写入点位值
                this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei);
                this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei);
                this._plc.Write(NodeSettingWcsSendMaterial.plcpointAddress, MainCentralControl.QingKongDianWei);
            }
            catch (Exception ex)
            {
                Console.WriteLine("站点" + siteNo + " 初始化数据异常" + ex.Message);
                LogManager.Error(ex);
            }
        }
        /// <summary>
        /// 启动上件扫描监听
        /// </summary>
        public void StartPoint()
        {

            FlowPointThread = new Thread(MonitorInLocatorPoint);
            FlowPointThread.Start();
        }
        public void MonitorInLocatorPoint()
        {
            while (true)
            {
                try
                {
                    //通用逻辑下，根据上件记录表，可区分业务，入库，出库，回库
                    //- 入库 - 根据小车任务表，可区分流入哪个站点
                    //- 出库 - 根据小车任务表，可区分流入哪个站点
                    //- 回库 - 根据小车任务表，可区分流入哪个站点
                    //- 特殊逻辑：下一站点多个站点，按多条线缓存数优先进少的；

                    var carno = this._plc.Read(NodeSettingCarNo.plcpointAddress);
                    var carstate = this._plc.Read(NodeSettingCarState.plcpointAddress);
                    var carrun = this._plc.Read(NodeSettingCarRun.plcpointAddress);
                    var wcsstate = this._plc.Read(NodeSettingWcsState.plcpointAddress);
                    var wcsend = this._plc.Read(NodeSettingWcsSend.plcpointAddress);
                    if (carno != null && carstate != null && carrun != null && wcsstate != null && wcsend != null)
                    {
                        //清除点位信息
                        if (Convert.ToInt32(carno) == 0 && Convert.ToInt32(wcsend) == 1 && Convert.ToInt32(wcsstate) == 1)
                        {
                            this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei); //清空小车去向点位
                            this._plc.Write(NodeSettingWcsSendMaterial.plcpointAddress, MainCentralControl.QingKongDianWei); //清空车身长度点位
                            this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei); //清空wcs处理完成点位
                        }
                        //正常读到小车信息
                        if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 0 && Convert.ToInt32(wcsstate) == 0 && Convert.ToInt32(carstate) == 1 && Convert.ToInt32(carrun) == 0)
                        {
                            var downLength = GetTargetTo(Convert.ToInt32(carno));
                            if (string.IsNullOrWhiteSpace(downLength))
                            {
                                //Console.WriteLine("OutWarePoint类 WriteMaterialMessage方法未确认返回值,查看报错日志!");
                                Thread.Sleep(1000);
                                continue;
                            }
                            object ToInt16downLength = MainCentralControl.getValue("2", downLength);
                            this._plc.Write(this.NodeSettingCarRun.plcpointAddress, MainCentralControl.WcsMoRenQuXiang);//写入小车去向
                            this._plc.Write(this.NodeSettingWcsSendMaterial.plcpointAddress, ToInt16downLength); //写入车身长度
                            this._plc.Write(this.NodeSettingWcsSend.plcpointAddress, MainCentralControl.WcsChuLiWanCheng);//写入wcs处理完成
                            string zfc = downLength == "2900" ? "空挂具" : "挂具";
                            LogManager.Info($"当前时间{DateTime.Now} >>> {zfc}:{carno}经过下件站点:{this.sitenode.siteNo},WCS写入去向:1,写入车身长度:{ToInt16downLength};");
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Error(ex);
                }
                finally
                {
                    Thread.Sleep(2000);
                }
            }
        }

        /// <summary>
        /// 根据上件点，物料号，获取下一点位信息
        /// </summary>
        /// <param name="siteNo">交互所属站点</param>
        /// <param name="carno">到位挂具号码</param>
        /// <param name="isOver">是否是订单结束处理的判断传参</param>
        /// <returns></returns>
        private string GetTargetTo(int carno)
        {
            try
            {
                using var scope = _host.Services.CreateScope();
                using var dbContext = scope.ServiceProvider.GetRequiredService<DefaultDbContext>();
                var basecarModel = dbContext.BaseCar.Where(t => t.carNo == carno).FirstOrDefault();
                var waitdownlineModel = dbContext.BaseWaitdownline.Where(t => t.carNo == carno).FirstOrDefault();
                if (waitdownlineModel == null && basecarModel != null)
                {
                    //添加车辆在Waitdownline表中的缓存信息
                    BaseWaitdownline waitdownModel = new()
                    {
                        id = Guid.NewGuid(),
                        carId = basecarModel.id,
                        carNo = basecarModel.carNo,
                        carName = basecarModel.carName,
                        downline = 2,
                        materielNo = "",
                        materielNum = 0,
                        isDelete = 0,
                        createTime = DateTime.Now,
                        createBy = "DownLine"
                    };
                    dbContext.Add(waitdownModel);
                    dbContext.SaveChanges();
                    return "2900";//调试无信息挂具写入数值
                }
                else if (waitdownlineModel != null)
                {
                    if (!string.IsNullOrWhiteSpace(waitdownlineModel.materielNo))//挂具绑定物料表中,物料不为空时
                    {
                        //查找车型长度后返回写入Plc
                        string sqlQuery = @$"
                                    SELECT 
                                        b1.material_no AS materialNo, 
                                        b1.k46up_length AS k46upLength,
                                        b1.k48up_length AS k48upLength,
                                        b1.down_length AS downLength, 
                                        b2.order_code AS definefield1,
                                        b2.line_code AS definefield2,
                                        b2.prod_code AS definefield3
                                    FROM 
                                        base_materialinfo b1
                                        JOIN base_production_order_split b2 
                                        ON b2.prod_code LIKE CONCAT('%', b1.material_no, '%')
                                    WHERE 
                                        b2.order_code = '{waitdownlineModel.materielNo}'";
                        var QueryOrder = dbContext.ExecuteSqlQuery<BaseMaterialinfo>(sqlQuery).ToList();
                        if (QueryOrder?.Count > 0 && !string.IsNullOrWhiteSpace(QueryOrder[0].downLength))
                        {
                            RelieveCarAndMaterial(carno, waitdownlineModel.materielNo);//下件点下件解除挂具与物料信息绑定关系
                            return QueryOrder[0].downLength;
                        }
                    }
                    else if (string.IsNullOrWhiteSpace(waitdownlineModel.materielNo))//挂具绑定物料表中,物料为空时
                    {
                        return "2900";//与电气沟通是空时写入长度最小值
                    }
                }
                //添加下线记录后修正任务和等待下线记录表
                void RelieveCarAndMaterial(int carno, string vin)
                {
                    //挂具在下件点交互完成后记录下线数据
                    var orderMessage = dbContext.BaseProductionOrderSplit.Where(t => t.orderCode == vin).ToList();
                    if (orderMessage?.Count > 0 && waitdownlineModel != null)
                    {
                        string XianBie = orderMessage[0].lineCode;
                        char lastChar = XianBie[XianBie.Length - 1];
                        var XianBieNum = Char.GetNumericValue(lastChar).ToString();
                        BaseFollowmessage baseFollowmessage = new()
                        {
                            id = Guid.NewGuid().ToString(),
                            sid = orderMessage[0].id,
                            vinCode = orderMessage[0].orderCode,
                            upSite = waitdownlineModel.createBy,
                            downSite = XianBieNum == "1" ? "K02" : "K07",
                            carNo = carno,
                            materialName = orderMessage[0].prodDesc,
                            lineCode = orderMessage[0].lineCode,
                            lineName = orderMessage[0].lineCode == "一线" ? "一线" : "二线",
                            isover = 1,
                            est = orderMessage[0].est,
                            quantity = orderMessage[0].quantity,
                            actualquantity = 1,
                            productionSequence = orderMessage[0].productionSequence,
                            createBy = "OrderOverInsert",
                            createDate = DateTime.Now
                        };
                        dbContext.Add(baseFollowmessage);
                        dbContext.SaveChanges();
                        //解除base_waitdownline表中挂具与任务VIN码绑定关系,修改车辆线上状态为已下线
                        dbContext.BaseWaitdownline.Where(t => t.id == waitdownlineModel.id).Update(a => new BaseWaitdownline() { materielNo = string.Empty, materielNum = 0, createTime = DateTime.Now, downline = 2, createBy = string.Empty, definefield1 = string.Empty});
                        //修改base_production_order_split表订单为结束状态 
                        dbContext.BaseProductionOrderSplit.Where(t => t.id == orderMessage[0].id).Update(a => new BaseProductionOrderSplit() { isover = 1 });
                    }
                }
                //LogManager.Info($"OutWarePoint类 WriteMaterialMessage方法未确认返回值,从底部返回NULL!");
                return "";
            }
            catch (Exception ex)
            {
                //LogManager.Info($"错误日志输出 >>> OutWarePoint类 WriteMaterialMessage 方法报错  {ex}");
                LogManager.Error(ex);
                return null;
            }

        }
    }
}
