using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SlnMesnac.Business.@base;
using SlnMesnac.Common;
using SlnMesnac.Config;
using SlnMesnac.Model.domain;
using SlnMesnac.Model.dto;
using SlnMesnac.Model.enums;
using SlnMesnac.Plc;
using SlnMesnac.Repository.service;
using SlnMesnac.Rfid;
using SlnMesnac.TouchSocket;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using TouchSocket.Core;
using static System.Net.Mime.MediaTypeNames;

#region << 版 本 注 释 >>

/*--------------------------------------------------------------------
* 版权所有 (c) 2024 WenJY 保留所有权利。
* CLR版本：4.0.30319.42000
* 机器名称：LAPTOP-E0N2L34V
* 命名空间：SlnMesnac.Business
* 唯一标识：f79d6d97-d9b0-4b0b-a442-e6bb1c1c79e6
*
* 创建者：WenJY
* 电子邮箱：wenjy@mesnac.com
* 创建时间：2024-04-10 16:36:01
* 版本：V1.0.0
* 描述：
*
*--------------------------------------------------------------------
* 修改人：
* 时间：
* 修改说明：
*
* 版本：V1.0.0
*--------------------------------------------------------------------*/

#endregion << 版 本 注 释 >>

namespace SlnMesnac.Business
{
    /// <summary>
    /// 设备产出业务逻辑
    /// </summary>
    public class ProdCompletionBusiness : BaseBusiness
    {
        private FJ500Comm.FJ500SP fj500s = new FJ500Comm.FJ500SP();

        //喷码机喷码失败或者设备状态检查重试次数,0代表状态正常
        public static int PmTryAmount = 0;

        //喷码机心跳，每次收到回复刷新时间，如果超过1分钟，则认为喷码机断开连接，添加一条报警
        private DateTime PmHeartTime = DateTime.Now;

        private readonly IMesProductPlanService _mesProductPlanService;
        private readonly IMesProductOrderService _mesProductOrderService;
        private readonly IMesPrdBarCodeService _barCodeTaskService;
        private readonly IBaseMaterialInfoService _baseMaterialInfoService;
        private readonly IMesBaseBarcodeInfoService _mesBaseBarcodeInfoService;
        public readonly IMesPrdBarCodeService _mesPrdBarCodeService;
        private readonly IRealPalletTaskService _realPalletTaskService;
        private readonly UdpServer udpServer;
        private DebugConfig debugConfig = DebugConfig.Instance;
        private ISqlSugarClient sqlSugarClient;

        public ProdCompletionBusiness(ISqlSugarClient _sqlSugarClient, ILogger<BaseBusiness> logger, AppConfig appConfig, List<PlcAbsractFactory> plcFactories, List<RfidAbsractFactory> rfidFactories, IMesProductPlanService mesProductPlanService, IMesPrdBarCodeService barCodeTaskService, IServiceProvider serviceProvider) : base(logger, appConfig, plcFactories, rfidFactories, serviceProvider)
        {
            udpServer = serviceProvider.GetRequiredService<UdpServer>();
            UdpServer.ReceivedPMCodeEvent += PmCodeHandler;
            sqlSugarClient = _sqlSugarClient;
            _mesProductPlanService = mesProductPlanService;
            _barCodeTaskService = barCodeTaskService;
            _realPalletTaskService = serviceProvider.GetRequiredService<IRealPalletTaskService>();
            _mesBaseBarcodeInfoService = serviceProvider.GetRequiredService<IMesBaseBarcodeInfoService>();
            _mesPrdBarCodeService = serviceProvider.GetRequiredService<IMesPrdBarCodeService>();
            _mesProductOrderService = serviceProvider.GetRequiredService<IMesProductOrderService>();
            _baseMaterialInfoService = serviceProvider.GetRequiredService<IBaseMaterialInfoService>();
            Init();
        }

        private void test()
        {
            try
            {
                sqlSugarClient.AsTenant().BeginTran();
                string palletCode1 = "";

                WmsBaseLocation source = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<WmsBaseLocation>().Where(x => x.LocationCode == "3114").First();
                WmsBaseLocation target = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<WmsBaseLocation>().Where(x => x.LocationCode == "3314").First();
                // palletCode1 = source.ContainerCode;

                // source.ContainerCode = target.ContainerCode;
                target.ContainerCode = source.ContainerCode;
                sqlSugarClient.AsTenant().GetConnection("mes").Updateable<WmsBaseLocation>(source).ExecuteCommand();
                sqlSugarClient.AsTenant().GetConnection("mes").Updateable<WmsBaseLocation>(target).ExecuteCommand();
                sqlSugarClient.AsTenant().CommitTran();
            }
            catch (Exception ex)
            {
                sqlSugarClient.AsTenant().RollbackTran();
            }
            // MesProductPlanDetail? mesProductPlanDetail = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<MesProductPlanDetail>().First(x => x.PlanCode == "20240724144533JL001");
            //sqlSugarClient.AsTenant().BeginTran();
            //string epc = "JYHB01010102";
            //_mesProductPlanService.GetStartedProdPlan(out MesProductPlanDto productPlanDto);
            //string bigCode = GenerateBigBarcode(productPlanDto, epc);
            //BindingBarCode(bigCode, epc, productPlanDto);
            //sqlSugarClient.AsTenant().BeginTran();
        }

        // 3114

        private static bool isEmptyPalletHandleRunning = false;

        public void Init()
        {
            Task.Run(async () =>
           {
               await EmptyPalletHandle();
           });
            Task.Run(() =>
            {
                DeviceOutPutHandle();
            });

            //喷码机设备状态检查
            checkPmStatus();
        }

        #region 喷码机设备相关通讯

        /// <summary>
        /// 喷码机状态检查
        /// </summary>
        public void checkPmStatus()
        {
            PmTryAmount++;
            Task.Run(() =>
            {
                while (true)
                {
                    try
                    {
                        //发送检查状态指令
                        // udpServer.SendMessage(fj500s.CheckState());
                        // Thread.Sleep(1000 * 5);
                        // 重新发送带喷印条码，保证始终有条码
                        SendFirstPmCode();
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError("checkStatus异常:" + ex.Message);
                    }
                    Thread.Sleep(1000 * 30);

                    if (DateTime.Now - PmHeartTime > TimeSpan.FromMinutes(2))
                    {
                        //报警
                        _logger.LogError("====================喷码机通讯心跳失败预警，推送报警");
                        AddAlarm(WarnStatusEnum.喷码机设备状态检查故障或者喷印失败预警超过30次);
                        PmTryAmount++;
                    }
                }
            });
        }

        /// <summary>
        /// 喷码机返回信息解析处理
        /// 1.传输完成及喷码完成
        /// 2.喷码机状态检查
        /// </summary>
        /// <param name="str"></param>
        private void PmCodeHandler(string str)
        {
            PmHeartTime = DateTime.Now;
            try
            {
                int LastTryAmount = PmTryAmount;
                var result = fj500s.GetAck(str);
                if (result == "00")
                {
                    // 发送数据成功
                    _logger.LogInformation("====================收到喷码机发送数据成功");
                    PmTryAmount = 0;
                }
                else if (result == "0E")
                {
                    // 喷码机设备故障
                    _logger.LogError($"====================收到喷码机设备状态检查故障或者喷印失败预警,喷码机重试次数:{PmTryAmount}");
                    PmTryAmount++;

                    if (PmTryAmount <= 30)
                    {
                        //重新发送
                        Task.Run(() =>
                        {
                            Thread.Sleep(1000 * 5);
                            SendFirstPmCode();
                        });
                    }
                    else
                    {
                        _logger.LogError("====================超过30次，推送报警");
                        AddAlarm(WarnStatusEnum.喷码机设备状态检查故障或者喷印失败预警超过30次);
                    }
                }
                else if (result == "0F")
                {
                    _logger.LogInformation("====================收到喷码机打印完成，推送下一条待打印条码");
                    updatePrdBarcodeInfo();
                    SendFirstPmCode();
                    _logger.LogInformation("====================推送下一条待打印条码成功");
                    PmTryAmount = 0;
                }

                if (LastTryAmount > 0 && PmTryAmount == 0)
                { // 报警消除
                    _logger.LogInformation("喷码机报警消除");
                    deleteAlarm(WarnStatusEnum.喷码机设备状态检查故障或者喷印失败预警超过30次);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("PmCodeHandler喷码机回复信息解析处理异常:" + ex.Message);
            }
        }

        /// <summary>
        /// 获取数据库最早未喷印未绑定条码
        /// </summary>
        private void SendFirstPmCode()
        {
            try
            {
                MesPrdBarcodeInfo mesPrdBarcodeInfo = _barCodeTaskService.Query(x => x.PrintFlag == "0" && x.BindStatus == 0).OrderBy(x => x.PrdBarcodeId).FirstOrDefault();
                if (mesPrdBarcodeInfo != null)
                {
                    udpServer.SendMessage(mesPrdBarcodeInfo.PrdBarcodeInfo);
                }
                else
                {
                    _logger.LogError("可喷码数不足，请检查原因");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("SendFirstPmCode获取数据库最早未喷印未绑定条码异常:" + ex.Message);
            }
        }

        /// <summary>
        /// 喷印完成更新条码
        /// </summary>
        private void updatePrdBarcodeInfo()
        {
            MesPrdBarcodeInfo mesPrdBarcodeInfo = _barCodeTaskService.Query(x => x.PrintFlag == "0" && x.BindStatus == 0).OrderBy(x => x.PrdBarcodeId).FirstOrDefault();
            mesPrdBarcodeInfo.PrintFlag = "1";
            mesPrdBarcodeInfo.PrintTime = DateTime.Now;
            _barCodeTaskService.Update(mesPrdBarcodeInfo);
        }

        #endregion 喷码机设备相关通讯

        /// <summary>
        /// 设备产出逻辑处理
        /// </summary>
        private async void DeviceOutPutHandle()
        {
            // 读取RFID失败重试次数，超过5次推送报警
            int readRfidAmount = 0;
            while (true)
            {
                try
                {
                    var plc = base.GetPlcByKey("plc");

                    if (plc == null || plc.IsConnected == false)
                    {
                        _logger.LogInformation("2F读取小包出口信号,PLC连接信息为空......");
                        Thread.Sleep(3000);
                        continue;
                    }

                    if (!plc.readBoolByAddress(GetPlcAddressByConfigKey("2楼小包出口到位信号")))
                    {
                        plc.writeStringByAddress(GetPlcAddressByConfigKey("2楼码垛出口RFID条码地址"), "", 12);
                        Thread.Sleep(5000);
                        continue;
                    }
                    // 判断插取有物料信号
                    if (!plc.readBoolByAddress(GetPlcAddressByConfigKey("2楼小包出口插取有物料信号")))
                    {
                        Thread.Sleep(1000);
                        continue;
                    }

                    string rfid = plc.readStringByAddress(GetPlcAddressByConfigKey("2楼码垛出口RFID条码地址"), 12).Replace("\0", "");

                    if (!string.IsNullOrWhiteSpace(rfid))
                    {
                        //_logger.LogInformation("小包出口已经有RFID了，无需再读");
                        Thread.Sleep(5000);
                        continue;
                    }

                    string epcStr = await ReadEpcStrByRfidKeyAsync("secondFloorOut");

                    if (string.IsNullOrEmpty(epcStr))
                    {
                        _logger.LogError("小包出口到位信号触发,读取RFID失败......");
                        //判断前一位置是否有托盘缓存
                        RealPalletTask realPalletTask = _realPalletTaskService.Query().FirstOrDefault();
                        if (realPalletTask != null)
                        {
                            epcStr = realPalletTask.PalletCode;
                        }
                        else if (!string.IsNullOrEmpty(debugConfig.MdjOutRFID))
                        {  //判断人工是否有输入条码
                            epcStr = debugConfig.MdjOutRFID;
                        }
                        else
                        {
                            readRfidAmount++;
                            if (readRfidAmount == 5)
                            {
                                string virtualEpc = NoReadRFIDAlarm();
                                _logger.LogError("小包出口到位信号触发,读取RFID失败超过5次......");
                                //if (!string.IsNullOrEmpty(virtualEpc))
                                //{
                                //    //TODU 虚拟托盘号需要在系统存储
                                //    epcStr = virtualEpc;
                                //    _logger.LogError("小包出口到位信号触发,读取RFID失败超过5次,生成虚拟托盘号:" + virtualEpc);
                                //}
                                Thread.Sleep(1000 * 5);
                                continue;
                            }
                            else
                            {
                                Thread.Sleep(1000 * 5);
                                continue;
                            }
                        }
                    }

                    // 校验该epc是否已经存在库存里，有的话重新读

                    var hasLocation = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<BaseLocation>().Where(x => x.ContainerCode == epcStr).First();
                    if (hasLocation != null)
                    {
                        _logger.LogError("小包出口到位信号触发,读取RFID失败,该epc已经存在库存里:" + epcStr);
                        Thread.Sleep(5000);
                        continue;
                    }

                    RefreshMessage($"2F小包出口读取到RFID条码{epcStr},开始入库:");

                    _mesProductPlanService.GetStartedProdPlan(out MesProductPlanDto productPlanDto);
                    if (productPlanDto == null)
                    {
                        //throw new ArgumentException($"未获取到正在执行的生产计划");

                        //无计划时，按照无计划订单处理，MaterialId可修改，在配置文件
                        productPlanDto = new MesProductPlanDto();
                        productPlanDto.PlanCode = "0";
                        productPlanDto.MaterialId = long.Parse(debugConfig.MaterialId);
                        productPlanDto.SaleOrderId = 0;
                        productPlanDto.SaleorderCode = "0";
                    }

                    #region 开启事务

                    sqlSugarClient.AsTenant().BeginTran();
                    //1.生成大条码插入mes_barcode_info；
                    string bigCode = GenerateBigBarcode(productPlanDto, epcStr);
                    //2.40个小条码及大条码绑定托盘号，小条码绑定大条码,，托盘绑定大条码
                    BindingBarCode(bigCode, epcStr, productPlanDto);
                    //3.更新mes_product_plan及mes_product_order表，更新已生产数量
                    UpdatePlanInfoAndOrder(productPlanDto);

                    // 删除所有数据库托盘号
                    List<RealPalletTask> realPalletList = _realPalletTaskService.Query();
                    if (realPalletList != null && realPalletList.Count > 0)
                    {
                        sqlSugarClient.AsTenant().GetConnection("mes").Deleteable(realPalletList).ExecuteCommand();
                    }
                    // 写入PLC RFID号供调度使用
                    plc.writeStringByAddress(GetPlcAddressByConfigKey("2楼码垛出口RFID条码地址"), epcStr, 12);
                    // plc.writeByteByAddress(GetPlcAddressByConfigKey("2楼小包出口到位信号"), 2);
                    readRfidAmount = 0;
                    debugConfig.MdjOutRFID = "";
                    sqlSugarClient.AsTenant().CommitTran();

                    #endregion 开启事务
                }
                catch (Exception ex)
                {
                    sqlSugarClient.AsTenant().RollbackTran();

                    _logger.LogError($"DeviceOutPutHandle异常:{ex.Message}");
                }

                Thread.Sleep(1000 * 5);
            }
        }

        /// <summary>
        /// 生成大条码插入mes_barcode_info；
        /// </summary>
        /// <param name="productPlanDto"></param>
        /// <param name="epcStr"></param>
        /// <returns></returns>
        private string GenerateBigBarcode(MesProductPlanDto productPlanDto, string epcStr)
        {
            string bigBarcode = productPlanDto.PlanCode + DateTime.Now.ToString("_MMddHHmmss");
            MesBaseBarcodeInfo mesBaseBarcodeInfo = new MesBaseBarcodeInfo();
            mesBaseBarcodeInfo.printTime = DateTime.Now;
            mesBaseBarcodeInfo.printPerson = "SlnMesnac";
            mesBaseBarcodeInfo.printFlag = "1";
            mesBaseBarcodeInfo.batchFlag = "0";
            mesBaseBarcodeInfo.barcodeType = "3";
            mesBaseBarcodeInfo.barcodeInfo = bigBarcode;
            mesBaseBarcodeInfo.batchCode = bigBarcode;
            mesBaseBarcodeInfo.palletInfoCode = epcStr;
            mesBaseBarcodeInfo.materialId = productPlanDto.MaterialId;
            mesBaseBarcodeInfo.amount = 1;
            mesBaseBarcodeInfo.printNumber = 1;
            mesBaseBarcodeInfo.productionDate = DateTime.Now;
            mesBaseBarcodeInfo.acceptedDate = DateTime.Now;
            mesBaseBarcodeInfo.planCode = productPlanDto.PlanCode;
            MesProductPlanDetail? mesProductPlanDetail = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<MesProductPlanDetail>().First(x => x.PlanCode == productPlanDto.PlanCode);
            if (mesProductPlanDetail != null)
            {
                mesBaseBarcodeInfo.planDetailCode = mesProductPlanDetail.PlanDetailCode;
            }
            mesBaseBarcodeInfo.safeFlag = productPlanDto.SaleOrderId == 0 ? "1" : "0";
            mesBaseBarcodeInfo.saleOrderId = productPlanDto.SaleOrderId;
            mesBaseBarcodeInfo.saleorderCode = productPlanDto.SaleorderCode;
            mesBaseBarcodeInfo.bindStatus = "1";
            mesBaseBarcodeInfo.bindTime = DateTime.Now;
            mesBaseBarcodeInfo.updateBy = "SlnMesnac";
            mesBaseBarcodeInfo.updateTime = DateTime.Now;
            mesBaseBarcodeInfo.completeFlag = "1";
            mesBaseBarcodeInfo.singleFlag = "0";
            var materialInfo = _baseMaterialInfoService.Query(x => x.MaterialId == productPlanDto.MaterialId).FirstOrDefault();
            if (materialInfo != null)
            {
                mesBaseBarcodeInfo.barcodeSpec = materialInfo.MaterialSpec;
            }
            sqlSugarClient.AsTenant().GetConnection("mes").Insertable(mesBaseBarcodeInfo).ExecuteCommand();
            return bigBarcode;
        }

        /// <summary>
        /// 40个小条码及大条码绑定托盘号，小条码绑定大条码
        /// </summary>
        /// <param name="bigBarcode"></param>
        /// <param name="epcStr"></param>
        private void BindingBarCode(string bigBarcode, string epcStr, MesProductPlanDto productPlanDto)
        {
            List<MesPrdBarcodeInfo> list = _mesPrdBarCodeService.GetUseBarCodeList();
            if (list != null && list.Count > 0)
            {
                if (list.Where(x => x.PrintFlag == "1").ToList().Count < 40)
                {
                    // 推送低级别报警
                    AddAlarm(WarnStatusEnum.托盘绑定时已喷码数不足40);
                }
                foreach (var item in list)
                {
                    item.PalletInfoCode = epcStr;
                    item.MesBarcodeInfo = bigBarcode;
                    item.BindTime = DateTime.Now;
                    item.BindStatus = 1;
                }
                sqlSugarClient.AsTenant().GetConnection("mes").Updateable(list).ExecuteCommand();
            }
            //if (list == null || list.Count == 0)
            //{
            //    _logger.LogError("托盘未找到可以绑定的小条码");
            //    return;
            //    // throw new InvalidOperationException("托盘未找到可以绑定的小条码");
            //}

            //托盘绑定大条码信息
            BasePalletInfo palletInfo = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<BasePalletInfo>().Where(x => x.PalletInfoCode == epcStr).First();
            if (palletInfo != null)
            {
                palletInfo.MaterialBarcode = bigBarcode;
                palletInfo.MaterialId = productPlanDto.MaterialId;
            }
            sqlSugarClient.AsTenant().GetConnection("mes").Updateable(palletInfo).ExecuteCommand();
        }

        private void UpdatePlanInfoAndOrder(MesProductPlanDto productPlanDto)
        {
            MesProductPlan productPlan = _mesProductPlanService.Query(x => x.PlanCode == productPlanDto.PlanCode).FirstOrDefault();
            if (productPlan == null)
            {
                _logger.LogInformation("未找到该生产计划对应的生产工单!,按照无工单处理，无需更新计划");
                return;
            }
            MesProductOrder productOrder = _mesProductOrderService.Query(x => x.ProductOrderId == productPlan.ProductOrderId).FirstOrDefault();
            if (productPlan == null)
            {
                _logger.LogInformation("未找到该生产计划对应的生产工单!,按照无工单处理，无需更新计划");
                return;
            }

            #region 更新生产计划

            if (productPlan.CompleteAmount == 0)
            {
                productPlan.RealBeginTime = DateTime.Now;
            }
            productPlan.CompleteAmount++;
            if (productPlan.CompleteAmount == productPlan.PlanAmount)
            {
                productPlan.RealEndTime = DateTime.Now;
                productPlan.PlanStatus = Model.enums.PlanStatusEnum.已完成;
            }
            productPlan.UpdateTime = DateTime.Now;
            productPlan.UpdateBy = "SlnMesnac";
            sqlSugarClient.AsTenant().GetConnection("mes").Updateable(productPlan).ExecuteCommand();

            #endregion 更新生产计划

            #region 更新生产工单

            if (productOrder.CompleteAmount == 0)
            {
                productOrder.RealBeginTime = DateTime.Now;
            }
            productOrder.CompleteAmount++;
            if (productOrder.CompleteAmount == productOrder.PlanAmount)
            {
                productOrder.RealEndTime = DateTime.Now;
                productOrder.OrderStatus = "2";
            }
            productOrder.UpdateTime = DateTime.Now;
            productOrder.UpdateBy = "SlnMesnac";
            sqlSugarClient.AsTenant().GetConnection("mes").Updateable(productOrder).ExecuteCommand();

            #endregion 更新生产工单
        }

        #region 报警

        /// <summary>
        ///
        /// 插入报警
        /// </summary>
        private void AddAlarm(WarnStatusEnum warnStatusEnum)
        {
            try
            {
                sqlSugarClient.AsTenant().BeginTran();

                // 有报警，找出该设备的报警记录，如果没有报警记录或者报警记录已结束，则新增报警记录
                int warnRuleId = int.Parse(warnStatusEnum.GetDescription());
                DmsRecordAlarmTime? dmsRecordAlarmTime = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<DmsRecordAlarmTime>().First(x => x.AlarmRuleId == warnRuleId);
                if (dmsRecordAlarmTime == null)
                {
                    DmsBaseAlarmRule dmsBaseAlarmRule = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<DmsBaseAlarmRule>().First(x => x.AlarmRuleId == warnRuleId);

                    dmsRecordAlarmTime = new DmsRecordAlarmTime();
                    dmsRecordAlarmTime.DeviceId = dmsBaseAlarmRule.DeviceId;
                    dmsRecordAlarmTime.AlarmRuleId = warnRuleId;
                    dmsRecordAlarmTime.AlarmBeginTime = DateTime.Now;
                    dmsRecordAlarmTime.ContinueTime = dmsBaseAlarmRule.ContinueTime;
                    dmsRecordAlarmTime.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                    dmsRecordAlarmTime.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                    dmsRecordAlarmTime.AlarmData = warnStatusEnum.ToString();
                    dmsRecordAlarmTime.HandleSuggest = dmsBaseAlarmRule.HandleSuggest;
                    dmsRecordAlarmTime.CreateBy = "SlnMesnac";
                    dmsRecordAlarmTime.CreateTime = DateTime.Now;

                    DmsRecordAlarmInfo dmsRecordAlarmInfo = new DmsRecordAlarmInfo();
                    dmsRecordAlarmInfo.DeviceId = dmsBaseAlarmRule.DeviceId;
                    dmsRecordAlarmInfo.AlarmRuleId = warnRuleId;
                    dmsRecordAlarmInfo.AlarmBeginTime = DateTime.Now;
                    dmsRecordAlarmInfo.AlarmStatus = "0";
                    dmsRecordAlarmInfo.NoticeStatus = "0";
                    dmsRecordAlarmInfo.ContinueTime = dmsBaseAlarmRule.ContinueTime;
                    dmsRecordAlarmInfo.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                    dmsRecordAlarmInfo.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                    dmsRecordAlarmInfo.AlarmData = warnStatusEnum.ToString();
                    dmsRecordAlarmInfo.HandleSuggest = dmsBaseAlarmRule.HandleSuggest;
                    dmsRecordAlarmInfo.CreateBy = "SlnMesnac";
                    dmsRecordAlarmInfo.CreateTime = DateTime.Now;

                    sqlSugarClient.AsTenant().GetConnection("mes").Insertable(dmsRecordAlarmTime).ExecuteCommand();
                    sqlSugarClient.AsTenant().GetConnection("mes").Insertable(dmsRecordAlarmInfo).ExecuteCommand();
                }
                else
                {
                    dmsRecordAlarmTime.UpdateTime = DateTime.Now;
                    dmsRecordAlarmTime.UpdateBy = "SlnMesnac";
                    DmsRecordAlarmInfo dmsRecordAlarmInfo = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<DmsRecordAlarmInfo>().First(x => x.AlarmRuleId == warnRuleId);
                    if (dmsRecordAlarmInfo != null)
                    {
                        dmsRecordAlarmInfo.UpdateTime = DateTime.Now;
                        dmsRecordAlarmInfo.UpdateBy = "SlnMesnac";
                        sqlSugarClient.AsTenant().GetConnection("mes").Updateable(dmsRecordAlarmInfo).ExecuteCommand();
                    }
                    else
                    {
                        DmsBaseAlarmRule dmsBaseAlarmRule = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<DmsBaseAlarmRule>().First(x => x.AlarmRuleId == warnRuleId);

                        dmsRecordAlarmInfo = new DmsRecordAlarmInfo();
                        dmsRecordAlarmInfo.DeviceId = dmsRecordAlarmTime.DeviceId;
                        dmsRecordAlarmInfo.AlarmRuleId = warnRuleId;
                        dmsRecordAlarmInfo.AlarmBeginTime = DateTime.Now;
                        dmsRecordAlarmInfo.AlarmStatus = "0";
                        dmsRecordAlarmInfo.NoticeStatus = "0";
                        dmsRecordAlarmInfo.ContinueTime = dmsBaseAlarmRule.ContinueTime;
                        dmsRecordAlarmInfo.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                        dmsRecordAlarmInfo.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                        dmsRecordAlarmInfo.AlarmData = warnStatusEnum.ToString();
                        dmsRecordAlarmInfo.HandleSuggest = dmsBaseAlarmRule.HandleSuggest;
                        dmsRecordAlarmInfo.CreateBy = "SlnMesnac";
                        dmsRecordAlarmInfo.CreateTime = DateTime.Now;
                        sqlSugarClient.AsTenant().GetConnection("mes").Insertable(dmsRecordAlarmInfo).ExecuteCommand();
                    }

                    sqlSugarClient.AsTenant().GetConnection("mes").Updateable(dmsRecordAlarmTime).ExecuteCommand();
                }

                sqlSugarClient.AsTenant().CommitTran();
            }
            catch (Exception ex)
            {
                sqlSugarClient.AsTenant().RollbackTran();
                _logger.LogError($"插入或者更新报错信息异常{warnStatusEnum.ToString()} ==>:{ex.Message}");
            }
        }

        /// <summary>
        /// 消除报警
        /// </summary>
        /// <exception cref="InvalidOperationException"></exception>
        private void deleteAlarm(WarnStatusEnum warnStatusEnum)
        {
            DmsRecordAlarmTime? dmsRecordAlarmTime = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<DmsRecordAlarmTime>().First(x => x.AlarmRuleId == long.Parse(warnStatusEnum.GetDescription()));
            if (dmsRecordAlarmTime != null)
            {
                sqlSugarClient.AsTenant().BeginTran();
                DmsRecordAlarmInfo dmsRecordAlarmInfo = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<DmsRecordAlarmInfo>().First(x => x.AlarmRuleId == dmsRecordAlarmTime.AlarmRuleId && x.AlarmStatus == "0");
                if (dmsRecordAlarmInfo != null)
                {
                    dmsRecordAlarmInfo.AlarmEndTime = DateTime.Now;
                    dmsRecordAlarmInfo.AlarmStatus = "2";
                    dmsRecordAlarmInfo.UpdateTime = DateTime.Now;
                    sqlSugarClient.AsTenant().GetConnection("mes").Updateable(dmsRecordAlarmInfo).ExecuteCommand();
                }
                sqlSugarClient.AsTenant().GetConnection("mes").Deleteable(dmsRecordAlarmTime).ExecuteCommand();

                sqlSugarClient.AsTenant().CommitTran();
            }
        }

        /// <summary>
        /// 推送报警,并生成虚拟托盘号暂时使用，虚拟托盘号储存到报警信息，人工处理可以将虚拟托盘号替换为正常托盘号
        /// <return> 返回生产的虚拟托盘号
        /// </summary>
        private string NoReadRFIDAlarm()
        {
            string epcStr;
            try
            {
                epcStr = "TEMP" + DateTime.Now.ToString("MMddHHmm");
                sqlSugarClient.AsTenant().BeginTran();

                // 有报警，找出该设备的报警记录，如果没有报警记录或者报警记录已结束，则新增报警记录
                int warnRuleId = int.Parse(WarnStatusEnum.小包出口读取RFID失败5次.GetDescription());
                DmsRecordAlarmTime? dmsRecordAlarmTime = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<DmsRecordAlarmTime>().First(x => x.AlarmRuleId == warnRuleId);
                if (dmsRecordAlarmTime == null)
                {
                    DmsBaseAlarmRule dmsBaseAlarmRule = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<DmsBaseAlarmRule>().First(x => x.AlarmRuleId == warnRuleId);

                    dmsRecordAlarmTime = new DmsRecordAlarmTime();
                    dmsRecordAlarmTime.DeviceId = dmsBaseAlarmRule.DeviceId;
                    dmsRecordAlarmTime.AlarmRuleId = warnRuleId;
                    dmsRecordAlarmTime.AlarmBeginTime = DateTime.Now;
                    dmsRecordAlarmTime.ContinueTime = dmsBaseAlarmRule.ContinueTime;
                    dmsRecordAlarmTime.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                    dmsRecordAlarmTime.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                    dmsRecordAlarmTime.AlarmData = WarnStatusEnum.小包出口读取RFID失败5次.ToString();
                    dmsRecordAlarmTime.HandleSuggest = dmsBaseAlarmRule.HandleSuggest + ";;虚拟托盘号为:" + epcStr;
                    dmsRecordAlarmTime.CreateBy = "SlnMesnac";
                    dmsRecordAlarmTime.CreateTime = DateTime.Now;

                    DmsRecordAlarmInfo dmsRecordAlarmInfo = new DmsRecordAlarmInfo();
                    dmsRecordAlarmInfo.DeviceId = dmsBaseAlarmRule.DeviceId;
                    dmsRecordAlarmInfo.AlarmRuleId = warnRuleId;
                    dmsRecordAlarmInfo.AlarmBeginTime = DateTime.Now;
                    dmsRecordAlarmInfo.AlarmStatus = "0";
                    dmsRecordAlarmInfo.NoticeStatus = "0";
                    dmsRecordAlarmInfo.ContinueTime = dmsBaseAlarmRule.ContinueTime;
                    dmsRecordAlarmInfo.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                    dmsRecordAlarmInfo.AlarmReason = dmsBaseAlarmRule.AlarmReason;
                    dmsRecordAlarmInfo.AlarmData = WarnStatusEnum.小包出口读取RFID失败5次.ToString();
                    dmsRecordAlarmInfo.HandleSuggest = dmsBaseAlarmRule.HandleSuggest + ";;虚拟托盘号为:" + epcStr;
                    dmsRecordAlarmInfo.CreateBy = "SlnMesnac";
                    dmsRecordAlarmInfo.CreateTime = DateTime.Now;

                    sqlSugarClient.AsTenant().GetConnection("mes").Insertable(dmsRecordAlarmTime).ExecuteCommand();
                    sqlSugarClient.AsTenant().GetConnection("mes").Insertable(dmsRecordAlarmInfo).ExecuteCommand();
                }
                else
                {
                    dmsRecordAlarmTime.UpdateTime = DateTime.Now;
                    dmsRecordAlarmTime.UpdateBy = "SlnMesnac";
                    DmsRecordAlarmInfo dmsRecordAlarmInfo = sqlSugarClient.AsTenant().GetConnection("mes").Queryable<DmsRecordAlarmInfo>().First(x => x.AlarmRuleId == warnRuleId);
                    if (dmsRecordAlarmInfo != null)
                    {
                        dmsRecordAlarmInfo.UpdateTime = DateTime.Now;
                        dmsRecordAlarmInfo.UpdateBy = "SlnMesnac";
                    }
                    sqlSugarClient.AsTenant().GetConnection("mes").Updateable(dmsRecordAlarmTime).ExecuteCommand();
                    sqlSugarClient.AsTenant().GetConnection("mes").Updateable(dmsRecordAlarmInfo).ExecuteCommand();
                }

                sqlSugarClient.AsTenant().CommitTran();
                return epcStr;
            }
            catch (Exception ex)
            {
                sqlSugarClient.AsTenant().RollbackTran();
                _logger.LogError($"NoReadRFIDAlarm异常:{ex.Message}");
                return "";
            }
        }

        #endregion 报警

        /// <summary>
        /// 空托盘进入码垛位,读取RFID备用
        /// </summary>
        private async Task EmptyPalletHandle()
        {
            //读取PLC空托盘流转信号
            while (true)
            {
                try
                {
                    var plc = base.GetPlcByKey("plc");
                    if (plc == null)
                    {
                        _logger.LogInformation("读取PLC空托盘码垛到位信号,PLC连接信息为空......");
                        Thread.Sleep(5000);
                        continue;
                    }
                    if (!plc.readBoolByAddress(GetPlcAddressByConfigKey("2楼码垛到位信号")))
                    {
                        //_logger.LogInformation("等待空托盘到位信号触发......");
                        Thread.Sleep(5000);
                        continue;
                    }

                    RealPalletTask realPalletTask = _realPalletTaskService.Query().FirstOrDefault();
                    if (realPalletTask != null)
                    {
                        // _logger.LogInformation("空托盘到位信号触发,已经有读取托盘，不再读取......");
                        Thread.Sleep(5000);
                        continue;
                    }

                    //读取RFID、获取当前正在执行的计划、将当前计划、工单等信息与托盘绑定
                    RefreshMessage("空托盘到位信号触发成功,读取托盘RFID信息");

                    string epcStr = await ReadEpcStrByRfidKeyAsync("secondFloorPallet");

                    if (string.IsNullOrEmpty(epcStr))
                    {
                        _logger.LogError("空托盘到位信号触发,读取RFID失败......");
                        Thread.Sleep(1000 * 10);
                        continue;
                    }

                    RefreshMessage($"空托盘RFID信息读取成功，标签信息：{epcStr}");

                    // 插入一条托盘记录
                    realPalletTask = new RealPalletTask()
                    {
                        PalletCode = epcStr,
                        RecordTime = DateTime.Now,
                    };
                    _realPalletTaskService.Insert(realPalletTask);
                }
                catch (Exception e)
                {
                    RefreshMessage($"空托盘进入码垛位处理异常：{e.Message}");
                }
                Thread.Sleep(1000 * 10);
            }
        }

        /// <summary>
        /// 根据条码提取序列
        /// </summary>
        /// <param name="barCode"></param>
        /// <param name="result"></param>
        /// <exception cref="InvalidOperationException"></exception>
        private void ExtractNumber(string barCode, out int result)
        {
            string pattern = @"\b0*(\d{1,6})\b$";

            Match match = Regex.Match(barCode, pattern);
            if (match.Success)
            {
                result = Convert.ToInt32(match.Groups[1].Value) + 1;
            }
            else
            {
                throw new InvalidOperationException($"通过条码:{barCode}提取当前序列异常:未找到匹配的数字");
            }
        }
    }
}