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 System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using Thrift.Server;
using Thrift.Transport;
using ThriftService;
using static AngleSharp.Css.Values.CssRadialGradientValue;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Thrift.Protocol;
using System.Security.Cryptography.Xml;
using Z.EntityFramework.Plus;
using System.Net.NetworkInformation;

namespace Khd.Core.Wcs.Wcs
{
    /// <summary>
    /// 上件点线程
    /// </summary>
    public class UpLine : WcsServer
    {
        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; }
        public UpLine(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()
        {
            Thread TestThread1 = new Thread(new ParameterizedThreadStart(StartScanThrift));
            TestThread1.IsBackground = true;
            TestThread1.Start(this.sitenode);
            Thread TestThread2 = new Thread(new ParameterizedThreadStart(StartSendCarThrift));
            TestThread2.IsBackground = true;
            TestThread2.Start(this.sitenode);
            Thread TestThread3 = new Thread(ClearSendCar);
            TestThread3.IsBackground = true;
            TestThread3.Start();
        }
        /// <summary>
        /// 启动推送车辆到位队列
        /// </summary>
        private void StartScanThrift(object NodeSettingModel)
        {
            var sitenodemodel = NodeSettingModel as BaseSitenode;
            int TSpoint = Convert.ToInt32(sitenodemodel.thriftPort);
            string IpAddress = sitenodemodel.siteIpaddress;
            TTransport transport = new TSocket(IpAddress, TSpoint);
            while (true)
            {
                try
                {
                    //启动thrift 推送服务
                    //推送车辆到位情况
                    transport.Open();
                    TProtocol protocol = new TBinaryProtocol(transport);
                    WcsThrift.Client client = new WcsThrift.Client(protocol);
                    client.hello(ReceiveCarNo(""));
                }
                catch (Exception ex)
                {
                    LogManager.Info($"wcs上件控制类推送车辆到位信息Thrift方法报错 >>> {ex.Message}");
                }
                finally
                {
                    transport.Close();
                    Thread.Sleep(1000);
                }
            }
        }

        /// <summary>
        /// 启动小车扫描监听队列
        /// </summary>
        private void StartSendCarThrift(object NodeSettingModel)
        {
            SendCar(null, null, null);
            var sitenodemodel = NodeSettingModel as BaseSitenode;
            int JSport = Convert.ToInt32(sitenodemodel.siteServerport);
            while (true)
            {
                try
                {
                    //启动thrift接收服务
                    //接收挂具与Vin物料信息,上件绑定信息
                    WcsServer wcsServer = new WcsServer();
                    wcsServer.SendCarEvent += SendCar;
                    WcsThrift.Processor processor = new WcsThrift.Processor(wcsServer);
                    TServerTransport serverTransport = new TServerSocket(JSport);
                    TServer server = new TSimpleServer(processor, serverTransport);
                    Console.WriteLine($"站点:{this.sitenode.siteNo},当前时间:{DateTime.Now},接收客户端发车方法启动.. ");
                    server.Serve();
                }
                catch (Exception ex)
                {
                    LogManager.Info($"wcs上件控制类控制发车Thrift方法报错 >>> {ex.Message}");
                }
                finally
                {
                    Thread.Sleep(1000);
                }
            }
        }

        /// <summary>
        /// 发车
        /// </summary>
        /// <param name="carlist"></param>
        /// <param name="order_code"></param>
        /// <param name="amount"></param>
        /// <returns></returns>
        public string SendCar(List<string> carlist, string order_code, string amount)
        {
            #region 测试屏蔽
            //Console.WriteLine($"服务端发车触发 >>> carlist[0]:{carlist.FirstOrDefault()},vin条码:{order_code},车辆长度:{amount}");
            //return "11";
            #endregion
            //通用逻辑：（1 是否空车 2 物料号 3 上件数量）
            // 通用逻辑下，下一站点固定（配置）
            // -判断小车是否到位，小车已下发去向，清空下发数据信息
            // - 判断 小车是否到位，小车未下发去向
            // - 进库区判断： 库存是否满；
            // -特殊逻辑：下一站点多个站点，按多条线缓存数优先进少的；按物料 + 属性区分进哪个站点，可配置
            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) == 0 && Convert.ToInt32(wcsstate) == 0 && Convert.ToInt32(carstate) == 1 && Convert.ToInt32(carrun) == 0)
                    {
                        //根据上件点，物料号，获取下一点位信息
                        var TargetTo = GetTargetTo(Convert.ToInt32(carno), order_code, this.sitenode.siteNo);
                        //业务处理
                        if (string.IsNullOrWhiteSpace(TargetTo) || string.IsNullOrWhiteSpace(order_code))
                        {
                            //if (string.IsNullOrWhiteSpace(TargetTo)) LogManager.Info($"错误日志输出 >>> 站点:{this.sitenode.siteNo},挂具:{carno}上件车辆去向有误!");
                            //if (string.IsNullOrWhiteSpace(order_code)) LogManager.Info($"错误日志输出 >>>  站点:{this.sitenode.siteNo},挂具:{carno}Thrift传输Vin码为空!");
                            Thread.Sleep(1000);
                            return null;
                        }
                        //写入PLC
                        var ToInt16QuXiang = MainCentralControl.getValue("2", TargetTo);
                        var ToInt16ChangDu = MainCentralControl.getValue("2", amount);
                        this._plc.Write(this.NodeSettingCarRun.plcpointAddress, ToInt16QuXiang);//写入小车去向
                        this._plc.Write(this.NodeSettingWcsSend.plcpointAddress, MainCentralControl.WcsChuLiWanCheng);//写入wms处理完成
                        this._plc.Write(this.NodeSettingWcsSendMaterial.plcpointAddress, ToInt16ChangDu);//写入车身长度
                        LogManager.Info($"当前时间 :{DateTime.Now} >>> 上件站点 :{this.sitenode.siteNo}发车 ,挂具号:{carno},去向:{ToInt16QuXiang},Wcs处理完成:{MainCentralControl.WcsChuLiWanCheng},vin条码:{order_code},车身长度:{ToInt16ChangDu}");
                        return "1";//发车成功反馈
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.Error(ex);
            }
            finally
            {
                Thread.Sleep(1000);
            }
            return null;
        }
        //根据上件点，物料号，获取下一点位信息
        public string GetTargetTo(int carno, string materialNo, string sideno)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(materialNo) || string.IsNullOrWhiteSpace(sideno))
                {
                    return null;
                }
                using var scope = _host.Services.CreateScope();
                using var dbContext = scope.ServiceProvider.GetRequiredService<DefaultDbContext>();
                //1 读出点位信息，下一站点

                //2 根据物料查下一站点

                var WaitdownlineModel = dbContext.BaseWaitdownline.Where(t => t.carNo == carno).FirstOrDefault();
                var basecarModel = dbContext.BaseCar.Where(t => t.carNo == carno).FirstOrDefault();
                var orderModel = dbContext.BaseProductionOrderSplit.Where(t => t.orderCode == materialNo).FirstOrDefault();
                if (WaitdownlineModel == null && basecarModel != null && orderModel != null)//Waitdownline不存在当前车辆信息
                {
                    //添加挂具与物料绑定信息
                    BaseWaitdownline waitdownModel = new()
                    {
                        id = Guid.NewGuid(),
                        carId = basecarModel.id,
                        carNo = basecarModel.carNo,
                        carName = basecarModel.carName,
                        downline = 1,
                        materielNo = materialNo,
                        materielNum = 1,
                        isDelete = 0,
                        createTime = DateTime.Now,
                        createBy = sideno,
                        definefield1 = orderModel.lineCode
                    };
                    dbContext.Add(waitdownModel);
                    dbContext.SaveChanges();
                }
                else//Waitdownline存在当前车辆信息即改
                {
                    //base_waitdownline表中挂具与任务VIN码绑定,修改车辆线上状态为已上线
                    dbContext.BaseWaitdownline.Where(t => t.carNo == carno).Update(a => new BaseWaitdownline() { materielNo = materialNo, materielNum = 1, downline = 1, createBy = sideno, createTime = DateTime.Now, isDelete = 0, definefield1 = orderModel.lineCode });
                }
                return "1";
            }
            catch (Exception ex)
            {
                LogManager.Info($"UpLine类GetTargetTo方法报错 >>> {ex.Message}");
                return null;
            }

        }
        /// <summary>
        /// 返回给客户端车辆到位及车辆信息
        /// </summary>
        /// <param name="name">无用参数</param>
        /// <returns></returns>
        public string ReceiveCarNo(string name)
        {

            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)
                    {
                        return "";
                    }
                    //正常读到小车信息
                    if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 0 && Convert.ToInt32(wcsstate) == 0 && Convert.ToInt32(carstate) == 1 && Convert.ToInt32(carrun) == 0)
                    {
                        string TuiSongCarNo = carno.ToString();
                        return TuiSongCarNo;
                    }
                }
                Thread.Sleep(1000);
                return "";
            }
            catch (Exception ex)
            {
                LogManager.Info($"");
                return "";
            }
        }
        /// <summary>
        /// 启动小车发出后清空预设点位线程
        /// </summary>
        private void ClearSendCar()
        {
            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 (Convert.ToInt32(carno) == 0 && Convert.ToInt32(wcsend) == 1 && Convert.ToInt32(wcsstate) == 1)
                    {
                        this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei);
                        this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei);
                        this._plc.Write(NodeSettingWcsSendMaterial.plcpointAddress, MainCentralControl.QingKongDianWei);
                    }
                }
                catch (Exception ex)
                {
                    LogManager.Info($"发车后清空点位线程报错 >>> {ex.Message}");
                }
                finally
                {
                    Thread.Sleep(1000);
                }
            }
        }
    }
}
