using MeterVision.Config;
using MeterVision.db;
using MeterVision.Helper;
using MeterVision.model;
using MeterVision.Util;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static MeterVision.FreeAi.FaImport;

namespace MeterVision.FreeAi
{
    //识别主程序
    public class FaRun
    {
        //private FaLog faLog;   //设备运行日志类

        public static bool SendAiLogEnable = false;
        

        private StringBuilder mRunLog = new StringBuilder();

        public event EventHandler<AiRealLogEventArgs> OnAiRealLogInfo;

        private UdpSender udpSender;

        private static RealLogger realLogger;

        //public static bool RecordRealLogEnable = false;     //实时日志记录
        private static bool _recordRealLogEnable = false;
        public static  bool RecordRealLogEnable
        {
            get => _recordRealLogEnable;
            set
            {
                if(_recordRealLogEnable != value)
                {
                    _recordRealLogEnable = value;
                }
                if (!_recordRealLogEnable && realLogger != null)
                {
                    realLogger.Close();
                }
            }
        }


        //ai输出的日志回调函数
        private void PrintfCallbackMethod(string message)
        {
            //Debug.Write(message);
            // 获取日志实例，将日志加入队列（不会创建新线程）
            //var logger = UdpLoggerSender.GetInstance();
            //logger.EnqueueLog(message); // 只加入队列，避免创建过多线程
            if (FaRun.SendAiLogEnable)
            {
                udpSender = UdpSender.GetInstance();
                udpSender.SendLog(message);
            }

            if (FaRun.RecordRealLogEnable)
            {
                realLogger = RealLogger.GetInstance();
                realLogger.Log(message);
            }

            //faLog.Append_aiLog(message);
            mRunLog.Append(message);
            //发送消息给主程序控件
            OnAiRealLogInfo?.Invoke(this, new AiRealLogEventArgs(message));
        }

        //增加MCU的日志
        private void AddMCULog(string message)
        {
            mRunLog.Append(message + "\n");
            OnAiRealLogInfo?.Invoke(this, new AiRealLogEventArgs(message));
        }

        public ResultModel StartRecognition(object detailItem)
        {
            PrintfCallback callback = PrintfCallbackMethod;

            string srcImage = string.Empty;
            if(detailItem is SingleDetailItem)
            {
                srcImage = ((SingleDetailItem)detailItem).SrcImage;
            }
            else if(detailItem is PatchDetailItem)
            {
                srcImage = ((PatchDetailItem)detailItem).SrcImage;
            }else if(detailItem is TPatchDetail)
            {
                srcImage = ((TPatchDetail)detailItem).SrcImage;
            }
            else
            {
                return null;
            }


            //判断图像尺寸是否合规
            if (!ThisApp.IsImageDimensionsValid(srcImage))
            {
                Console.WriteLine($"{srcImage}图像尺寸不合规！");
                return null;
            }


            short[] rgb565 = GetRGB565Array(srcImage);

            if (rgb565.Length != (320 * 240))
            {
                throw new InvalidOperationException("无效的图像大小。");
            }

            BeforeAI beforeAI = new BeforeAI();
            if(detailItem is SingleDetailItem)
            {
                beforeAI = FaBefore.getBeforeAI((SingleDetailItem)detailItem);
            }
            else if(detailItem is PatchDetailItem)
            {
                beforeAI = FaBefore.getBeforeAI((PatchDetailItem)detailItem);
            }
            else if(detailItem is TPatchDetail)
            {
                beforeAI = FaBefore.getBeforeAI((TPatchDetail)detailItem);
            }


          
            AfterAI afterAI = new AfterAI();
            SmallImage smallJpg = new SmallImage();
            BigImage bigJpg = new BigImage();

            //string onnxPath = ConfigItem.GetConfigItem().OnnxPath;
            string onnxPath = CfginiItem.GetConfigItem().OnnxPath;
            onnxPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, onnxPath);

            //判断onnxPath的路径是否存在
            if (!File.Exists(onnxPath))
            {
                throw new InvalidOperationException($"onnx文件{onnxPath}不存在！");
            }

            //调用动态加载的方式
            //初始化加载动态库,

            //string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigItem.GetConfigItem().AiDll);
            string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, CfginiItem.GetConfigItem().AiDll);

            if (!File.Exists(dllPath))
            {
                throw new InvalidOperationException($"AI动态库文件{dllPath}不存在！");
            }

            int result = -1;
            if (DynamicFaImport.Initialize(dllPath))
            {
                try
                {
                    result = DynamicFaImport.Recognition(rgb565, ref beforeAI, ref afterAI, ref smallJpg, ref bigJpg, onnxPath, callback);

                }
                catch (AccessViolationException ex)
                {
                    // 处理异常，例如记录日志
                    Console.WriteLine("Access violation: " + ex.Message);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exeception: " + ex.Message);
                }
            }
            else
            {
                throw new InvalidOperationException($"初始化AI动态库{dllPath}失败！");
            }
            DynamicFaImport.Unload();


            //存储图像
            string dstImagPath = CfginiItem.GetConfigItem().DstImgPath;
            dstImagPath = Path.Combine(dstImagPath, ThisApp.GetNowTime_yyyyMMdd());
            if (!Directory.Exists(dstImagPath))
            {
                Directory.CreateDirectory(dstImagPath);
            }
            dstImagPath = Path.Combine(dstImagPath, Guid.NewGuid().ToString() + ".jpg");
            SaveBigJpg(bigJpg, dstImagPath);


            //存储日志
            string aiLogPath = CfginiItem.GetConfigItem().AiLogPath;
            aiLogPath = Path.Combine(aiLogPath, ThisApp.GetNowTime_yyyyMMdd());
            if (!Directory.Exists(aiLogPath))
            {
                Directory.CreateDirectory(aiLogPath);
            }
            aiLogPath = Path.Combine(aiLogPath, Guid.NewGuid().ToString() + ".txt");

            try
            {
                if (LicenseMana.mLicenseModel != null && LicenseMana.mLicenseModel.IsPermanent)
                {
                    File.WriteAllText(aiLogPath, mRunLog.ToString());
                }
                else
                {
                    File.WriteAllText(aiLogPath, "");
                }
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"保存文件{aiLogPath}失败：{ex.Message}");
            }

            //结果对象赋值
            ResultModel resultModel = new ResultModel
            {
                SrcImage = srcImage,
                DstImage = dstImagPath,
                LogPath = aiLogPath,

                ResultMeter = afterAI.METER_TYPE,
                //1,2,7,8
                ResultType = afterAI.AI_RESULT_ARRAY[11],
                RawValue = afterAI.INIT_AI_RESULT,
                FinalValue = afterAI.AI_RESULT,
                CompleteValue = afterAI.AI_COMPLETE_RESULT,
                ValueChanged  = afterAI.IS_VALUE_CHANGED,
                CompressIndex = afterAI.COMPRESS_JPG_INDEX,
            };

            if (beforeAI.METER_TYPE == 1 || beforeAI.METER_TYPE == 3)
            {
                resultModel.FeatureRegions =
                    $"{afterAI.CONFIG_NUM_REGION[0]},{afterAI.CONFIG_NUM_REGION[1]} " +
                    $"{afterAI.CONFIG_NUM_REGION[2]},{afterAI.CONFIG_NUM_REGION[3]} " +
                    $"{afterAI.CONFIG_NUM_REGION[4]},{afterAI.CONFIG_NUM_REGION[5]} " +
                    $"{afterAI.CONFIG_NUM_REGION[6]},{afterAI.CONFIG_NUM_REGION[7]}"; 

                resultModel.MeterRegions = $"{afterAI.CONFIG_METER_REGION[0]}," +
                    $"{afterAI.CONFIG_METER_REGION[1]} " +
                    $"{afterAI.CONFIG_METER_REGION[2]}," +
                    $"{afterAI.CONFIG_METER_REGION[3]}";
            }
            else if (beforeAI.METER_TYPE == 2)
            {
                resultModel.FeatureRegions = $"{afterAI.CONFIG_TWO_IND[0]}," +
                    $"{afterAI.CONFIG_TWO_IND[1]} " +
                    $"{afterAI.CONFIG_TWO_IND[2]}," +
                    $"{afterAI.CONFIG_TWO_IND[3]}";

                resultModel.MeterRegions = $"{afterAI.CONFIG_METER_REGION[0]}," +
                    $"{afterAI.CONFIG_METER_REGION[1]} " +
                    $"{afterAI.CONFIG_METER_REGION[2]}," +
                    $"{afterAI.CONFIG_METER_REGION[3]}";
            }
            else
            {
                resultModel.MeterRegions = "";
                resultModel.FeatureRegions = "";
            }

            resultModel.AiVer = BitConverter.ToString(afterAI.AI_VER).Replace("-", "");
            resultModel.DebugInfoBytes = afterAI.AI_RESULT_ARRAY;
            
            return resultModel;
        }

        private short[] GetRGB565Array(string jpgFilePath)
        {
            using (Bitmap bmp = new Bitmap(jpgFilePath))
            {
                int width = bmp.Width;
                int height = bmp.Height;
                //string message = string.Format("width = %d,height = %d", width, height);
                string message = $"width = {width}, height = {height}";
                AddMCULog(message);

                //创建数组存储RGB565数据
                short[] rgb565Data = new short[width * height];
                //给它多分配1倍的内存
                //short[] rgb565Data = new short[width * height*2];

                //锁定位图内存
                BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                IntPtr ptr = bmpData.Scan0;

                //创建数据存储RGB888数据
                byte[] rgb888Data = new byte[Math.Abs(bmpData.Stride) * height];

                //将像素数据拷贝到字节数组中
                Marshal.Copy(ptr, rgb888Data, 0, rgb888Data.Length);

                // 逐个像素转换为 RGB565 格式，并进行上下颠倒处理
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        // 颠倒行的顺序
                        int invertedY = height - 1 - y;

                        //int index = y * bmpData.Stride + x * 3;
                        int index = invertedY * bmpData.Stride + x * 3;

                        byte r = rgb888Data[index + 2]; // R 通道
                        byte g = rgb888Data[index + 1]; // G 通道
                        byte b = rgb888Data[index];     // B 通道

                        // 将 RGB888 转换为 RGB565
                        short rgb565 = (short)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3));
                        rgb565Data[y * width + x] = rgb565;
                    }
                }

                //解锁位图
                bmp.UnlockBits(bmpData);
                bmp.Dispose();

                return rgb565Data;
            }//using Bitmap
        }


        private bool SaveBigJpg(BigImage bigJpg, string fileName)
        {
            if (bigJpg.size_of_JPEG_data == 0)
            {
                //Debug.Write("bigJpg dataSize error!");
                AddMCULog("bigJpg dataSize error!");
                return false;
            }

            bool saveResult = false;
            try
            {
                //获取文件夹路径
                string directoryPath = Path.GetDirectoryName(fileName);

                //如果文件夹不存在，创建文件夹
                if (!Directory.Exists(directoryPath))
                {
                    Directory.CreateDirectory(directoryPath);
                }

                //保存文件
                //File.WriteAllBytes(fileName, bigJpg.JPEG_data);
                using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
                {
                    fs.Write(bigJpg.JPEG_data, 0, bigJpg.size_of_JPEG_data);
                }
                saveResult = true;
            }
            catch (Exception e)
            {
                AddMCULog(e.Message);
                //Debug.Write(e.Message);
            }

            string strResult = string.Format("save {0} {1}", fileName, saveResult ? "success" : "fail");
            //Debug.Write(strResult);
            AddMCULog(strResult);

            return saveResult;
        }

        //-------------------------------------------------------------------
    }

    //日志信息事件
    public class AiRealLogEventArgs : EventArgs
    {
        public string mLogInfo { get; }

        public AiRealLogEventArgs(string logInfo)
        {
            mLogInfo = logInfo;
        }
    }
    //---------------------------------------------------
    
}
