using HslCommunication.Profinet.GE;
using Microsoft.Extensions.Logging;
using SlnMesnac.Common;
using SlnMesnac.Config;
using SlnMesnac.Model.domain;
using SlnMesnac.Model.dto;
using SlnMesnac.Plc;
using SlnMesnac.Repository.service;
using SlnMesnac.Repository.service.Impl;
using SlnMesnac.TouchSocket;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography.Xml;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using TouchSocket.Core;
using TouchSocket.Sockets;

namespace SlnMesnac.Business
{
    public class LogoBusiness
    {

        private TcpServer tcpServer = null;
        private ILogger<LogoBusiness> logger;

        private PlcAbsractFactory plc = null;
        private LightHelper lightHelper = LightHelper.Instance;
        private DebugConfig config = DebugConfig.Instance;
        private IBaseMaterialService baseMaterialService;
        private ILogoIdentifyService logoIdentifyService;
        private ILogoConfigService logoConfigService;
        public PaddleOCRSharp.PaddleOCREngine engine = null;
        private GunHelper gunHelper = GunHelper.Instance;

        private Queue<BarCodeModel> consumeQueue = new Queue<BarCodeModel>();
        private static LogoBusiness instance;

        // 存放照片路径
        public static string PicturePath = System.Environment.CurrentDirectory + "/picture/";
        // 存放日志路径
        public static string LogPath = System.Environment.CurrentDirectory + "/Logs/";

        /// <summary>
        /// 接收海康相机识别结果
        /// </summary>
        private static bool HikCameraResult = false;
        #region 委托定义  刷新界面扫描信息

        public delegate void RefreshBoxInfo(string boxCode, string boxTime, string model, bool isSuccess,bool isNeedCheck);
        public static event RefreshBoxInfo? RefreshBoxInfoEvent;

        public delegate void RefreshPicture(byte[] imageData);
        public static event RefreshPicture? RefreshPictureEvent;

        public delegate void RefreshMessage(string message, bool isWarning = false);
        public static event RefreshMessage? RefreshMessageEvent;

        public delegate void RefreshDataGrid();
        public static event RefreshDataGrid? RefreshDataGridEvent;

        #endregion


        private LogoBusiness(ILogger<LogoBusiness> logger, ILogoConfigService logoConfigService, IBaseMaterialService baseMaterialService, ILogoIdentifyService logoIdentifyService, PlcPool _plcPool, TcpServer _tcpServer)
        {
         
            this.logger = logger;
            tcpServer = _tcpServer;
            TcpServer.RefreshMaterialCodeStrEvent += BarCodeHandler;
            TcpServer.CameraResultEvent += ReceiveCameraResult;
            TcpServer.SerialSignalPushEvent += SerialSignalPush;
            TcpServer.MessageNoReadEvent += MessageNoRead;
            this.baseMaterialService = baseMaterialService;
            this.logoIdentifyService = logoIdentifyService;
            this.logoConfigService = logoConfigService;
            gunHelper.InstanceSerialPort();
            plc = _plcPool.GetPlcByKey("plc");
            lightHelper.InstanceSerialPort();

            //定时清除日志及照片
            CleanOldLogs(PicturePath);
            CleanOldLogs(LogPath);
            InitClearTimer();

           
        }

        public static LogoBusiness GetInstance(ILogger<LogoBusiness> logger, ILogoConfigService logoConfigService, IBaseMaterialService baseMaterialService, ILogoIdentifyService ocrVerfiyService, PlcPool _plcPool, TcpServer _tcpServer)
        {
            if (instance == null)
            {
                instance = new LogoBusiness(logger, logoConfigService, baseMaterialService, ocrVerfiyService, _plcPool, _tcpServer);
            }
            return instance;
        }


        /// <summary>
        /// 接收光电模块信号
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="flag"></param>
        private async void SerialSignalPush(string ip, int flag)
        {
            // 光电触发拍照
            if (flag == 1)
            {
                Task.Run(() =>
                {
                    logger.LogInformation($"光电触发时间:{DateTime.Now}");
                    CameraHandler();
                });
               
            }
            else //光电释放
            {
                //lightHelper.SendData("CLOSE");
            }
        }

        /// <summary>
        /// 接受相机识别结果
        /// </summary>
        /// <param name="result"></param>
        private void ReceiveCameraResult(string result)
        {
            logger.LogInformation($"相机返回结果:{result}");
            if (result == "OK")
            {
                HikCameraResult = true;
            }
            else
            {
                HikCameraResult = false;
            }

        }


        /// <summary>
        /// 条码触发相机拍照校验
        /// </summary>
        /// <param name="materialCodeStr"></param>
        /// <param name="ip"></param>
        public async void BarCodeHandler(string materialCodeStr, string ip)
        {
                
            try
            {
                logger.LogInformation("扫码流程开始:");
                #region 初始操作：复位海康上次结果，删除海康上次保存文件
                HikCameraResult = false;
                FileHelper.DeleteAllPictures(config.CameraFilePath);
                // 保证队列一条数据
                consumeQueue.Clear();              
                // 声光电报警复位
                gunHelper.SendData("OK");
                #endregion

                bool judge = FoamtJudge(materialCodeStr);
                if (!judge)
                {
                    WarningAndStop($"箱体码{materialCodeStr}格式不正确,停线报警!");
                    return;
                }
                logger.LogInformation($"扫描到箱体码:{materialCodeStr}");

                
                //1.根据箱体码查询型号，根据型号判断是否需要校验LOGO
                ProductModel mode = logoConfigService.GetMaterialTypeByBarCode(materialCodeStr);
                if(mode == null)
                {
                    // 根据成品码查询不到型号
                    Warning($"根据成品码{materialCodeStr}查询不到型号,判断该型号是否样机或检查网络!");
                    return;
                }
                LogoConfig logoConfig = logoConfigService.GetByMaterialType(mode.MaterialCode);
               
                if (logoConfig.IsChecked == 0)
                {
                    // 不需要校验
                    RefreshMessageEvent?.Invoke("LOGO+PCI无需识别，下发放行");
                    logger.LogInformation($"箱体码:{materialCodeStr}，Logo无需识别，下发放行");
                    RefreshBoxInfoEvent?.Invoke(materialCodeStr, DateTime.Now.ToString(), logoConfig.MaterialName, true,false);
                    #region 更新数据库
                    LogoIdentify record = new LogoIdentify();
                    record.ProductCode = materialCodeStr;
                    record.MaterialType = logoConfig.MaterialType;
                    record.MaterialName = logoConfig.MaterialName;
                    record.isChecked = logoConfig.IsChecked;
                    record.Result = 2;
                    record.RecordTime = DateTime.Now;
                    record.ProductLine = config.ProductLine;
                    logoIdentifyService.InsertRecord(record);
                    #endregion
                    RefreshDataGridEvent?.Invoke();
                }
                else
                {
                    // 需要检验但是还没设置配方
                   if(logoConfig.CheckKind == 0)
                    {
                        Warning($"箱体码:{materialCodeStr}，LOGO+PCI需要识别，但是未设置PCI模版");
                        return;
                    }
                    else
                    {
                       
                        BarCodeModel barCodeModel = new BarCodeModel();
                        barCodeModel.BarCode = materialCodeStr;
                        barCodeModel.logoConfig = logoConfig;
                        consumeQueue.Enqueue(barCodeModel);
                        logger.LogInformation($"箱体码:{materialCodeStr}，入队等待识别");       
                    }
                }
   
            }
            catch (Exception ex)
            {
                Warning($"BarCodeHandler异常,识别Logo失败,原因:{ex.Message},箱体条码:{materialCodeStr}");
            }
                    
        }

       
        /// <summary>
        /// 相机流程处理
        /// </summary>
        /// <returns></returns>
        private async void CameraHandler()
        {
            try
            {
              
              //Task.Run(() =>
              //  {
              //      Thread.Sleep(1000);
              //      lightHelper.SendData("CLOSE");
              //      logger.LogInformation("光源关掉");
              //  });
                logger.LogInformation("相机流程开始:");
                //照片
                byte[] ImageData = null;
                // 压缩后的图片
                byte[] compressedImageData = null;

                //从队列取出条码
                if (consumeQueue.Count <= 0) return;

                bool hikFlag = false;
                BarCodeModel barCodeModel = consumeQueue.Dequeue();
                // 打开灯光 
                lightHelper.SendData("OPEN", barCodeModel);
                logger.LogInformation($"灯光打开");


                Thread.Sleep(int.Parse(config.SleepStr));

               

                // Thread.Sleep(int.Parse(config.SleepStr));
                // 1.触发相机拍照
                tcpServer.SendCommand(config.CameraIP, barCodeModel.logoConfig.CheckKind.ToString());

                // 2.等待接收海康结果
                hikFlag = await JudgeIsSuccessAsync();
                if (hikFlag)
                {
                    RefreshMessageEvent?.Invoke("LOGO+PCI识别成功，下发放行");
                    logger.LogInformation($"箱体码:{barCodeModel.BarCode}，Logo识别成功，下发放行");
                }
                else
                {
                    WarningAndStop($"LOGO+PCI识别失败，禁止放行");
                    logger.LogInformation($"LOGO+PCI识别失败，禁止放行");
                }

               // lightHelper.SendData("CLOSE");
                // 刷新界面、刷新图片,照片按照日期存储本地
                #region
                RefreshBoxInfoEvent?.Invoke(barCodeModel.BarCode, DateTime.Now.ToString(), barCodeModel.logoConfig.MaterialName, hikFlag,true);
                await Task.Run(() =>
                {
                    Thread.Sleep(int.Parse(config.PictureSleep));
                    ImageData = FileHelper.FindPhoto(config.CameraFilePath);
                    if (ImageData != null)
                    {
                        // 图片压缩
                        compressedImageData = FileHelper.CompressImageData(ImageData, 20);
                        FileHelper.SaveImage(compressedImageData, barCodeModel.BarCode + ".jpg", PicturePath);
                        RefreshPictureEvent?.Invoke(ImageData);
                    }

                });
                #endregion


                #region 更新数据库
                LogoIdentify record = new LogoIdentify();
                record.ProductCode = barCodeModel.BarCode;
                record.MaterialType = barCodeModel.logoConfig.MaterialType;
                record.MaterialName = barCodeModel.logoConfig.MaterialName;
                record.isChecked = barCodeModel.logoConfig.IsChecked;
                record.Result = hikFlag == true ? 1 : 0;
                record.RecordTime = DateTime.Now;
                record.ProductLine = config.ProductLine;
                if (compressedImageData != null)
                {
                    record.Picture = compressedImageData;
                }
                logoIdentifyService.InsertRecord(record);
                #endregion
                RefreshDataGridEvent?.Invoke();
            }catch(Exception ex)
            {
                Warning($"相机流程异常,原因:{ex.Message}");
            }
            finally
            {
                
                #region 复位海康上次结果，删除海康上次保存文件、关闭灯光
                HikCameraResult = false;
                FileHelper.DeleteAllPictures(config.CameraFilePath);
                //  lightHelper.SendData("CLOSE");
                #endregion

                Thread.Sleep(1000);
                lightHelper.SendData("CLOSE");
                logger.LogInformation($"灯光关闭");
            }

        }


        public void MessageNoRead()
        {
            //logger.LogError($"扫码器NoRead报警!");
            //RefreshMessageEvent?.Invoke($"扫码器NoRead报警!", true);
            WarningAndStop("扫码器NoRead报警!");


        }

        /// <summary>
        /// 判断Logo校验是否成功
        /// </summary>
        /// <returns></returns>
        public async Task<bool> JudgeIsSuccessAsync()
        {
            bool result = false;
            // 设置计时器
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            //至多等待2.5s海康的校验结果
            result = await Task.Run(() =>
            {
                while (true)
                {
                    if (HikCameraResult == true)
                    {
                        return true;
                    }
                    // 检查是否超时
                    if (stopwatch.ElapsedMilliseconds > 2500)
                    {
                        return false;
                    }

                    Thread.Sleep(100);
                }
            });
            return result;

        }


        /// <summary>
        /// 箱体码格式校验，20位成品码，B开头的21位箱体码为MES码
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        private bool FoamtJudge(string code)
        {
            if (!string.IsNullOrEmpty(code))
            {
                if (code.Length == 20 || code.Length == 21&& code.Substring(0, 1) == "B")
                {
                    return true;
                }
            }
            return false;
        }




        /// <summary>
        /// 截取两个逗号之间的字符串
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        static string GetSubstringBetweenCommas(string input)
        {
            if (input == null) return null;
            // 找到第一个逗号的位置
            int firstCommaIndex = input.IndexOf(',');
            if (firstCommaIndex != -1)
            {
                // 找到第二个逗号的位置
                int secondCommaIndex = input.IndexOf(',', firstCommaIndex + 1);
                if (secondCommaIndex != -1)
                {
                    // 使用Substring截取第一个逗号和第二个逗号之间的字符
                    return input.Substring(firstCommaIndex + 1, secondCommaIndex - firstCommaIndex - 1);
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }



        #region PLC交互部分
        //M100停止点位
        public void Pass()
        {
            try
            {
                if (plc != null && plc.IsConnected)
                {
                    plc.writeInt16ByAddress("DB22.DBW2", 8);
                    Task.Run(() =>
                    {
                        // 设置计时器
                        Stopwatch stopwatch = new Stopwatch();
                        stopwatch.Start();
                        while (true)
                        {
                            if (plc.readInt16ByAddress("DB22.DBW2") == 0)
                            {
                                logger.LogInformation("PLC复位成功,启动线体");
                                RefreshMessageEvent?.Invoke("PLC复位成功,启动线体");
                                break;
                            }
                            // 检查是否超过两秒
                            if (stopwatch.ElapsedMilliseconds > 3000)
                            {
                                logger.LogError("PLC复位超时");
                                RefreshMessageEvent?.Invoke("PLC复位超时", true);
                                break;
                            }
                            Thread.Sleep(100);
                        }
                    });

                }
                else
                {
                    logger.LogError("PLC未连接，请检查连接");
                    RefreshMessageEvent?.Invoke("PLC未连接，请检查连接", true);
                }
                // 声光电报警复位
                gunHelper.SendData("OK");
            }
            catch (Exception ex)
            {
                logger.LogError($"下发PLC复位方法Pass()异常:{ex.Message}");
            }

        }

        public void Stop()
        {
            try
            {
                if (plc != null && plc.IsConnected && config.PlcStopLineFlag=="1")
                {
                    plc.writeInt16ByAddress("DB22.DBW2", 9);
                    Task.Run(() =>
                    {
                        // 设置计时器
                        Stopwatch stopwatch = new Stopwatch();
                        stopwatch.Start();
                        while (true)
                        {
                            if (plc.readInt16ByAddress("DB22.DBW2") == 1)
                            {
                                logger.LogInformation("PLC复位成功,启动线体");
                                RefreshMessageEvent?.Invoke("PLC复位成功,启动线体");
                                break;
                            }
                            // 检查是否超过两秒
                            if (stopwatch.ElapsedMilliseconds > 3000)
                            {
                                logger.LogError("PLC复位超时");
                                RefreshMessageEvent?.Invoke("PLC复位超时", true);
                                break;
                            }
                            Thread.Sleep(100);
                        }
                    });


                }
                // 声光电报警
                gunHelper.SendData("NG");
            }
            catch (Exception ex)
            {
                logger.LogError($"下发PLC报警方法Stop()异常:{ex.Message}");
            }

        }
        #endregion

        #region 记录日志，刷新界面及下发PLC报警
        public void WarningAndStop(string message)
        {
            logger.LogError(message);
            RefreshMessageEvent?.Invoke(message, true);
            Stop();
        }


        public void Warning(string message)
        {
            logger.LogError(message);
            RefreshMessageEvent?.Invoke(message, true);
           
        }
        #endregion


        #region 定时清除照片及日志
        private void InitClearTimer()
        {
            System.Timers.Timer timer = new System.Timers.Timer
            {
                Interval = TimeSpan.FromDays(1).TotalMilliseconds, // 每天执行一次
                AutoReset = true
            };
            timer.Elapsed += OnTimedEvent;
            timer.Start();

        }

        private  void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            CleanOldLogs(PicturePath);
            CleanOldLogs(LogPath);
        }


        private void CleanOldLogs(string Path)
        {
            try
            {
                int saveDays = int.Parse(config.PictureSaveTime);
                var directoryInfo = new DirectoryInfo(Path);
                if (!directoryInfo.Exists)
                {
                    Console.WriteLine($"日志文件夹 {Path} 不存在.");
                    return;
                }

                var cutoffDate = DateTime.Now.AddDays(-saveDays);

                var directories = directoryInfo.GetDirectories();
                foreach (var directory in directories)
                {
                    // 解析文件夹名称
                    if (DateTime.TryParseExact(directory.Name, "yyyy-MM-dd", null, System.Globalization.DateTimeStyles.None, out DateTime folderDate))
                    {
                        if (folderDate < cutoffDate)
                        {
                            Console.WriteLine($"删除过期日志文件夹: {directory.FullName}");
                            directory.Delete(true); // 删除文件夹及其内容
                        }
                    }
                    else
                    {
                        Console.WriteLine($"文件夹名称不符合日期格式: {directory.Name}");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"清理日志时发生错误: {ex.Message}");
            }
        }
        #endregion



        #region 测试用例
        /// <summary>
        /// 模拟光电发送byte，测试接收处理
        /// </summary>
        public void testPostByte()
        {
            Task.Run(async () =>
            {
                Thread.Sleep(5000);
                TcpClient _tcpClient = new TcpClient();

                _tcpClient.Setup(new TouchSocketConfig().SetRemoteIPHost($"127.0.0.1:7024"));
                _tcpClient.Connect();

                var waitClient = _tcpClient.CreateWaitingClient(new WaitingOptions()
                {
                    FilterFunc = response =>
                    {
                        return true;
                    }
                });
                byte[] release = new byte[] { (byte)0x01, (byte)0x03, (byte)0x02, (byte)0x01, (byte)0xFF, (byte)0xF9, (byte)0x94 };
                var reciveBuffer = await waitClient.SendThenResponseAsync(release);
            });

        }

        #endregion
    }
}
