using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Xml.Linq;
using DH.Commons.Base;
using DH.Commons.Enums;
using DH.Commons.Helper;
using DVPCameraType;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using static System.Net.Mime.MediaTypeNames;
using static MvCamCtrl.NET.MyCamera;
using LogLevel = DH.Commons.Enums.EnumHelper.LogLevel;


namespace DH.Devices.Camera
{

    public class Do3ThinkCamera : CameraBase, ILogger
    {

        private dvpCameraInfo stDevInfo = new dvpCameraInfo();
        private dvpStatus nRet = dvpStatus.DVP_STATUS_OK;
        private DVPCamera.dvpEventCallback pCallBackFunc;
        private uint m_handle;
        public bool Connected=false;
        public int m_n_dev_count = 0;
        private DVPCamera.dvpStreamCallback ImageCallback;
        public dvpStreamFormat dvpStreamFormat = dvpStreamFormat.S_RGB24;
        public int m_CamCount = 0;
        public Double m_dfDisplayCount = 0;

        public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
        public event Action<LogMsg> OnLog;
        public ConcurrentDictionary<string, MatSet> _imageSetList = new ConcurrentDictionary<string, MatSet>();


        public Do3ThinkCamera()
        {
            LoggerHelper.LogPath = "D://";
            LoggerHelper.LogPrefix = CameraName;

        }





        public bool IsValidHandle(uint handle)
        {
            bool bValidHandle = false;
            dvpStatus status = DVPCamera.dvpIsValid(handle, ref bValidHandle);
            if (status == dvpStatus.DVP_STATUS_OK)
            {
                return bValidHandle;
            }
            return false;
        }


        public override bool CameraConnect()
        {
            try
            {
                pCallBackFunc = new DVPCamera.dvpEventCallback(cbExceptiondelegate);
                nRet = DVPCamera.dvpOpenByUserId(CameraName,
                 dvpOpenMode.OPEN_NORMAL,
                 ref m_handle);

                // ch:打开设备 | en:Open device
                if (dvpStatus.DVP_STATUS_OK != nRet)
                {
                    throw new Exception($"Create device failed:{nRet:x8}");
                }

                nRet = DVPCamera.dvpSetTargetFormat(m_handle, (dvpStreamFormat)dvpStreamFormat);
                if (dvpStatus.DVP_STATUS_OK != nRet)
                {
                    throw new Exception($"Set image format failed:{nRet:x8}");
                }

                dvpCameraInfo camerainfo = new dvpCameraInfo();
                nRet = DVPCamera.dvpGetCameraInfo(m_handle, ref camerainfo);

                SerialNumber = camerainfo.SerialNumber;
            //ch: 注册异常回调函数 | en:Register Exception Callback
           nRet = DVPCamera.dvpRegisterEventCallback(m_handle, pCallBackFunc, dvpEvent.EVENT_DISCONNECTED, IntPtr.Zero);
                if (nRet != dvpStatus.DVP_STATUS_OK)
                {
                    throw new Exception($"Register expection callback failed:{nRet}");
                }
                GC.KeepAlive(pCallBackFunc);

                //// ch:设置采集连续模式 | en:Set Continues Aquisition Mode 
                if (IsContinueMode)
                {
                    // ch:设置触发模式为off || en:set trigger mode as off
                    nRet = DVPCamera.dvpSetTriggerState(m_handle, false);
                    if (dvpStatus.DVP_STATUS_OK != nRet)
                    {
                        throw new Exception("Set TriggerMode failed!");
                    }
                }
                else
                {
                    // ch:设置触发模式为on || en:set trigger mode as on
                    nRet = DVPCamera.dvpSetTriggerState(m_handle, true);
                    if (dvpStatus.DVP_STATUS_OK != nRet)
                    {
                        throw new Exception("Set TriggerMode failed!");
                    }

                    // 硬触发
                    if (IsHardwareTrigger)
                    {
                        // ch:触发源选择:1 - Line1; | en:Trigger source select:1 - Line1;
                        nRet = DVPCamera.dvpSetTriggerSource(m_handle, dvpTriggerSource.TRIGGER_SOURCE_LINE1);
                        if (dvpStatus.DVP_STATUS_OK != nRet)
                        {
                            throw new Exception("Set Line1 Trigger failed!");
                        }

                        // ch:注册回调函数 | en:Register image callback 
                        ImageCallback = new DVPCamera.dvpStreamCallback(ImageCallbackFunc);
                        nRet = DVPCamera.dvpRegisterStreamCallback(m_handle, ImageCallback, dvpStreamEvent.STREAM_EVENT_PROCESSED, IntPtr.Zero);
                        if (dvpStatus.DVP_STATUS_OK != nRet)
                        {
                            throw new Exception("Register image callback failed!");
                        }
                    }
                    else // 软触发
                    {
                        nRet = DVPCamera.dvpSetTriggerSource(m_handle, dvpTriggerSource.TRIGGER_SOURCE_SOFTWARE);
                        if (dvpStatus.DVP_STATUS_OK != nRet)
                        {
                            throw new Exception("Set Software Trigger failed!");
                        }
                    }

                    // ch:开启抓图 || en: start grab image
                    nRet = DVPCamera.dvpStart(m_handle);
                    if (dvpStatus.DVP_STATUS_OK != nRet)
                    {
                        throw new Exception($"Start grabbing failed:{nRet:x8}");
                    }
                    //// 曝光
                    if (Exposure != 0)
                    {
                        SetExposure(Exposure);
                    }
                    //// 增益
                    if (Gain >= 0)
                    {
                        SetGain(Gain);
                    }
                    //全画幅
                    if (!IsAllPicEnabled)
                    {
                        SetPictureRoi((int)ROIX, (int)ROIY, (int)ROIW, (int)ROIH);
                    }
                    

                    //// 设置 触发延迟
                    if (TriggerDelay > 0)
                    {
                        nRet = DVPCamera.dvpSetTriggerDelay(m_handle, TriggerDelay);
                        if (nRet != dvpStatus.DVP_STATUS_OK)
                        {
                            throw new Exception("Set TriggerDelay failed!");
                        }
                    }

                    //// 信号消抖
                    if (LineDebouncerTime > 0)
                    {
                        nRet = DVPCamera.dvpSetTriggerJitterFilter(m_handle, LineDebouncerTime);
                        if (nRet != dvpStatus.DVP_STATUS_OK)
                        {
                            throw new Exception($"LineDebouncerTime set failed:{nRet}");
                        }
                    }

                    //IIConfig.PropertyChanged -= IIConfig_PropertyChanged;
                    //IIConfig.PropertyChanged += IIConfig_PropertyChanged;
                    Connected = true;

                }
                return true;
            }
            catch
            {
                Connected = false;
                return false;
            }

        }


        /// <summary>
        /// 回调函数
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="_event"></param>
        /// <param name="pContext"></param>
        /// <param name="param"></param>
        /// <param name="refVariant"></param>
        /// <returns></returns>
        public int cbExceptiondelegate(uint handle, dvpEvent _event, IntPtr pContext, int param, ref dvpVariant refVariant)
        {

            if (_event == dvpEvent.EVENT_DISCONNECTED)
            {
              
            }


            return dvpStatus.DVP_STATUS_OK.ToInt();
        }

        private void IIConfig_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            //if (e.PropertyName == "IsHardwareTrigger" && !IIConfig.IsContinueMode)
            //{
            //    // ch:停止抓图 | en:Stop grab image
            //    nRet = DVPCamera.dvpStop(m_handle);
            //    if (nRet != dvpStatus.DVP_STATUS_OK)
            //    {
            //        throw new Exception($"Stop grabbing failed{nRet:x8}");
            //    }

            //    // 硬触发
            //    if (IIConfig.IsHardwareTrigger)
            //    {
            //        // ch:触发源选择:1 - Line1; | en:Trigger source select:1 - Line1;
            //        nRet = DVPCamera.dvpSetTriggerSource(m_handle, dvpTriggerSource.TRIGGER_SOURCE_LINE1);
            //        if (dvpStatus.DVP_STATUS_OK != nRet)
            //        {
            //            throw new Exception("Set Line1 Trigger failed!");
            //        }

            //        // ch:注册回调函数 | en:Register image callback 
            //        ImageCallback = new DVPCamera.dvpStreamCallback(ImageCallbackFunc);
            //        nRet = DVPCamera.dvpRegisterStreamCallback(m_handle, ImageCallback, dvpStreamEvent.STREAM_EVENT_PROCESSED, IntPtr.Zero);
            //        if (dvpStatus.DVP_STATUS_OK != nRet)
            //        {
            //            throw new Exception("Register image callback failed!");
            //        }
            //    }
            //    else // 软触发
            //    {
            //        nRet = DVPCamera.dvpSetTriggerSource(m_handle, dvpTriggerSource.TRIGGER_SOURCE_SOFTWARE);
            //        if (dvpStatus.DVP_STATUS_OK != nRet)
            //        {
            //            throw new Exception("Set Software Trigger failed!");
            //        }
            //    }

            //    // ch:开启抓图 || en: start grab image
            //    nRet = DVPCamera.dvpStart(m_handle);
            //    if (dvpStatus.DVP_STATUS_OK != nRet)
            //    {
            //        throw new Exception($"Start grabbing failed:{nRet:x8}");
            //    }
            //    // 曝光
            //    if (IIConfig.DefaultExposure != 0)
            //    {
            //        SetExposure(IIConfig.DefaultExposure);
            //    }
            //    // 增益
            //    if (IIConfig.Gain >= 0)
            //    {
            //        SetGain(IIConfig.Gain);
            //    }

            //    // 设置 触发延迟
            //    if (IIConfig.TriggerDelay > 0)
            //    {
            //        nRet = DVPCamera.dvpSetTriggerDelay(m_handle, IIConfig.TriggerDelay);
            //        if (nRet != dvpStatus.DVP_STATUS_OK)
            //        {
            //            throw new Exception("Set TriggerDelay failed!");
            //        }
            //    }

            //    // 信号消抖
            //    if (IIConfig.LineDebouncerTime > 0)
            //    {
            //        nRet = DVPCamera.dvpSetTriggerJitterFilter(m_handle, IIConfig.LineDebouncerTime);
            //        if (nRet != dvpStatus.DVP_STATUS_OK)
            //        {
            //            throw new Exception($"LineDebouncerTime set failed:{nRet}");
            //        }
            //    }
            //}
        }

        /// <summary>
        /// 设置曝光值
        /// </summary>
        /// <param name="exposure">曝光值</param>
        /// <exception cref="Exception"></exception>
        private void SetExposure(double exposure)
        {
            // 关闭自动曝光
            nRet = DVPCamera.dvpSetAeOperation(m_handle, dvpAeOperation.AE_OP_OFF);
            if (nRet != dvpStatus.DVP_STATUS_OK)
            {
                throw new Exception($"Exposure set failed:{nRet}");
            }
            // 设置曝光值
            nRet = DVPCamera.dvpSetExposure(m_handle, exposure);
            if (nRet != dvpStatus.DVP_STATUS_OK)
            {
                throw new Exception($"Exposure set failed:{nRet}");
            }
        }



        /// <summary>
        /// 设置增益
        /// </summary>
        /// <param name="gain"></param>
        /// <exception cref="Exception"></exception>
        private void SetGain(float gain)
        {
            // 设置增益
            nRet = DVPCamera.dvpSetAnalogGain(m_handle, gain);

            if (nRet != dvpStatus.DVP_STATUS_OK)
            {
                throw new Exception($"Gain set failed:{nRet}");
            }
        }
        private void SetPictureRoi(int x, int y, int W, int H)
        {
            dvpRegion dvpR = new dvpRegion();

            dvpR.X = x;
            dvpR.Y = y;
            dvpR.W = W;
            dvpR.H = H;
            // 设置增益
            nRet = DVPCamera.dvpSetRoi(m_handle, dvpR);

            if (nRet != dvpStatus.DVP_STATUS_OK)
            {
                throw new Exception($"SetRoi set failed:{nRet}");
            }
        }

        public int ImageCallbackFunc(uint handle, dvpStreamEvent _event, IntPtr pContext, ref dvpFrame refFrame, IntPtr pBuffer)
        {
            Mat cvImage = new Mat();

            try
            {

                Interlocked.Increment(ref SnapshotCount);


                int nWidth = refFrame.iWidth;
                int nHeight = refFrame.iHeight;

                // 根据图像格式创建Mat
                switch (refFrame.format)
                {
                    case dvpImageFormat.FORMAT_RGB24:
                        cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC3, pBuffer);
                        Cv2.CvtColor(cvImage, cvImage, ColorConversionCodes.RGB2BGR);
                        break;

                    case dvpImageFormat.FORMAT_BGR24:
                        cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC3, pBuffer);
                        break;

                    case dvpImageFormat.FORMAT_MONO:
                        cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC1, pBuffer);
                        break;

                    default:
                        cvImage = Mat.FromPixelData(nHeight, nWidth, MatType.CV_8UC1, pBuffer);
                        break;
                }

                Mat smat = cvImage.Clone();
                Mat rotated = new Mat(); // 显式创建输出对象

                switch (RotateImage)
                {
                    case 90:
                        Cv2.Rotate(smat, rotated, RotateFlags.Rotate90Clockwise);
                        break;
                    case 180:
                        Cv2.Rotate(smat, rotated, RotateFlags.Rotate180);
                        break;
                    case 270:
                        Cv2.Rotate(smat, rotated, RotateFlags.Rotate90Counterclockwise);
                        break;
                    default:
                        rotated = smat.Clone(); // 无旋转时保持原图
                        break;
                }

                var imageSet = new MatSet
                {

                    _mat = rotated,

                };
                InitialImageSet(imageSet);

                var outImgSet = CopyImageSet(imageSet);
                OnHImageOutput?.Invoke(DateTime.Now, this, outImgSet);

                //存图
                DisplayAndSaveOriginImage(imageSet.Id, SnapshotCount);




            }
            catch (Exception ex)
            {

            }
            finally
            {
                cvImage?.Dispose();
            }
            return 0;
        }
        public void InitialImageSet(MatSet set)
        {
            //if (saveOption != null)
            //{
            //    set.ImageSaveOption = saveOption.Copy();
            //}

            //set.IsOriginSaved = !set.ImageSaveOption.IsSaveOriginImage;
            //set.IsFitSaved = !set.ImageSaveOption.IsSaveFitImage;
            //set.IsAddtionalSaved = string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType);
            set.CameraId = this.CameraName;

            set.ImageTime = DateTime.Now;
            _imageSetList[set.Id] = set;
        }

        public virtual async void DisplayAndSaveOriginImage(string imgSetId, int _counter)
        {
            MatSet set = _imageSetList.Values.FirstOrDefault(u => u.Id == imgSetId);

            if (set != null && set._mat != null)
            {
                await Task.Run(() =>
                {
                    Bitmap? showImage = null;

                    try
                    {
                        showImage = set._mat.ToBitmap();
                    }
                    catch (Exception)
                    {
                        //释放 himage
                        ClearImageSet(set);
                        return;
                    }

                    //  showImage.Save("D:/test333.bmp");
                    // Marshal.Copy(pbyteImageBuffer, 0, (IntPtr)lAddrImage, (int)dwBufferSize);
                    // Bitmap saveImage = showImage?.CopyBitmap();
                    // saveImage.Save("d://TEST444.BMP");
                    // OnShowImageUpdated?.Invoke(this, showImage, imgSetId);
                    if (IsSavePicEnabled && showImage != null)
                    {
                        string fullname = Path.Combine(ImageSaveDirectory, $"{CameraName}_{_counter:D7}_{set.Id}.{set._imageFormat.ToString().ToLower()}");
                        ImageSaveAsync(fullname, showImage);
                    }

                    //释放 himage
                    ClearImageSet(set);
                });
            }
        }
        static object _imageSetLock = new object();
        public void ClearImageSet(MatSet set)
        {
            try
            {
                bool flag = false;
                lock (_imageSetLock)
                {
                    flag = _imageSetList.TryRemove(set.Id, out set);
                    if (flag)
                    {
                        set.Dispose();
                    }
                    //LogAsync(DateTime.Now, $"{Name}移除图片信息{(flag ? "成功" : "失败")},当前缓存数量:{_imageSetList.Count}", "");
                }
            }
            catch (Exception ex)
            {
                LogAsync(DateTime.Now, LogLevel.Exception, $"清理图片缓存异常,当前缓存数量{_imageSetList.Count},{ex.GetExceptionMessage()}");
            }
        }
        public ImageSaveHelper ImageSaveHelper { get; set; } = new ImageSaveHelper();
        public virtual void ImageSaveAsync(string fullName, Bitmap map)
        {
            if (!IsSavePicEnabled)
            {
                map?.Dispose();
                return;
            }

            ImageSaveSet imageSaveSet = new ImageSaveSet()
            {
                FullName = fullName,
                SaveImage = map,

            };

            ImageSaveHelper.ImageSaveAsync(imageSaveSet);
        }
        public override bool CameraDisConnect()
        {
            try
            {

                // 1. 停止采集(如果正在运行)
                dvpStreamState streamState = new dvpStreamState();
                nRet = DVPCamera.dvpGetStreamState(m_handle, ref streamState);
                if (streamState == dvpStreamState.STATE_STARTED)
                {
                    // 先停止采集流
                    nRet = DVPCamera.dvpStop(m_handle);
                    if (nRet != dvpStatus.DVP_STATUS_OK)
                    {
                        throw new Exception($"停止采集失败,错误码:0x{nRet:X8}");
                    }
                }

                // 2. 设置触发源为软件触发(此时设备已停止)
                nRet = DVPCamera.dvpSetTriggerState(m_handle, false);
                if (nRet != dvpStatus.DVP_STATUS_OK)
                {
                    throw new Exception($"设置软件触发失败,错误码:0x{nRet:X8}");
                }

                // 3. 注销事件回调
                nRet = DVPCamera.dvpUnregisterEventCallback(m_handle, pCallBackFunc, dvpEvent.EVENT_DISCONNECTED, IntPtr.Zero);
                if (nRet != dvpStatus.DVP_STATUS_OK)
                {
                    throw new Exception($"注销事件回调失败,错误码:0x{nRet:X8}");
                }

                // 4. 关闭设备
                nRet = DVPCamera.dvpClose(m_handle);
                if (nRet != dvpStatus.DVP_STATUS_OK)
                {
                    throw new Exception($"关闭设备失败,错误码:0x{nRet:X8}");
                }

                m_handle = 0;
                return true;
            }
            catch
            {
                return false;
            }

        }

        public void Snapshot()
        {
            DVPCamera.dvpTriggerFire(m_handle);

        }

        public void LogAsync(LogMsg msg)
        {
            msg.MsgSource = CameraName;
            msg.ThreadId = Thread.CurrentThread.ManagedThreadId;

            //OnLog?.BeginInvoke(msg, null, null);
            OnLog?.Invoke(msg);

            //if (InitialConfig.IsEnableLog)
            {
                LoggerHelper.LogAsync(msg);
            }
        }
        public void LogAsync(DateTime dt, LogLevel logLevel, string msg)
        {
            LogAsync(new LogMsg(dt, logLevel, msg));
        }
    }
}