//#define USE_MULTI_THREAD

using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using DH.Commons.Enums;


namespace DH.Devices.Vision
{

    /// <summary>
    /// 实例分割 maskrcnn
    /// </summary>
    public class SimboInstanceSegmentation : SimboVisionMLBase
    {
        public override bool Load(MLInit mLInit)
        {
            bool res = false;
            try
            {


                Model = MLEngine.InitModel(mLInit.ModelFile,
                    mLInit.InferenceDevice,
                    mLInit.InputNodeName,
                    1, 3,
                    mLInit.InferenceWidth,
                    mLInit.InferenceHeight,5);
                res = true;

#if USE_MULTI_THREAD

                IsCreated = true;
                if (IsCreated)
                {
                    if (_runHandleBefore == null)
                    {
                        _runHandleBefore = new AutoResetEvent(false);
                    }

                    if (_runHandleAfter == null)
                    {
                        _runHandleAfter = new ManualResetEvent(false);
                    }

                    if (_runTask == null)
                    {
                        _runTask = Task.Factory.StartNew(() =>
                        {
                            while (IsCreated)
                            {
                                _runHandleBefore.WaitOne();

                                if (IsCreated)
                                {
                                    _result = RunInferenceFixed(_req);
                                    _runHandleAfter.Set();
                                }
                            }
                        }, TaskCreationOptions.LongRunning);
                    }
                }
#endif
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return res;
        }



#if USE_MULTI_THREAD
        MLRequest _req = null;
        MLResult _result = null;


        public bool IsCreated { get; set; } = false;
        Task _runTask = null;
        AutoResetEvent _runHandleBefore = new AutoResetEvent(false);
        ManualResetEvent _runHandleAfter = new ManualResetEvent(false);
        object _runLock = new object();
#endif

        [HandleProcessCorruptedStateExceptions]
        public override MLResult RunInference(MLRequest req)
        {
#if USE_MULTI_THREAD
            MLResult mlResult = null;
            lock (_runLock)
            {
                _result = new MLResult();

                _req = req;

                _runHandleAfter.Reset();
                _runHandleBefore.Set();
                _runHandleAfter.WaitOne();

                mlResult = _result;
            }

            return mlResult;
#else
            return RunInferenceFixed(req);
#endif




        }


        private void ConvertJsonResult(string json,  ref MLResult result)
        {
            // json = "{\"FastDetResult\":[{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.654843,\"rect\":[175,99,110,594]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.654589,\"rect\":[2608,19,104,661]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.654285,\"rect\":[1275,19,104,662]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.620762,\"rect\":[1510,95,107,600]},{\"cls_id\":0,\"cls\":\"liewen\",\"fScore\":0.617812,\"rect\":[2844,93,106,602]}]}";
            //
            Console.WriteLine("检测结果JSON:" + json);
#pragma warning disable CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型 
            SegResult detResult = JsonConvert.DeserializeObject<SegResult>(json);
#pragma warning restore CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型 
            if (detResult == null)
            {
                return;
            }

            int iNum = detResult.SegmentResult.Count;
#pragma warning disable CS0219 // 变量已被赋值,但从未使用过它的值
            int IokNum = 0;
#pragma warning restore CS0219 // 变量已被赋值,但从未使用过它的值
            for (int ix = 0; ix < iNum; ix++)
            {
                var det = detResult.SegmentResult[ix];

                var rect = det.rect;
                DetectionResultDetail detectionResultDetail = new DetectionResultDetail();
                detectionResultDetail.LabelNo = det.classId;
                //todo: 标签名相对应
                detectionResultDetail.LabelDisplay = det.classname;
                detectionResultDetail.Rect = new Rectangle(rect[0], rect[1], rect[2], rect[3]);
                detectionResultDetail.Score = det.fScore;
                detectionResultDetail.LabelName = det.classname;
                detectionResultDetail.Area = det.area;
                detectionResultDetail.InferenceResult = ResultState.DetectNG;
               
                    result.ResultDetails.Add(detectionResultDetail);
                

            }

        }




        [HandleProcessCorruptedStateExceptions]
        public MLResult RunInferenceFixed(MLRequest req)
        {
            MLResult mlResult = new MLResult();
            Mat originMat = new Mat();
            Mat detectMat = new Mat();

#pragma warning disable CS0168 // 声明了变量,但从未使用过
            try
            {
                if (req.mImage == null)
                {
                    mlResult.IsSuccess = false;
                    mlResult.ResultMessage = "异常:mat为null,无法执行推理!";
                    return mlResult;
                }

                // resize
                detectMat = req.mImage;//1ms



                int iWidth = detectMat.Cols;
                int iHeight = detectMat.Rows;

                // 如果是单通道图像,转换为三通道 RGB 格式
                if (detectMat.Channels() == 1)
                {
                    // 将灰度图像转换为RGB格式(三通道)

                    Cv2.CvtColor(detectMat, originMat, ColorConversionCodes.GRAY2BGR);

                }
                else if (detectMat.Channels() == 3)
                {
                    // 如果已经是三通道(BGR),则直接转换为RGB

                    Cv2.CvtColor(detectMat, originMat, ColorConversionCodes.BGR2RGB);

                }

                //输入数据转化为字节
                var inputByte = new byte[originMat.Total() * 3];//这里必须乘以通道数,不然数组越界,也可以用w*h*c,差不多
                Marshal.Copy(originMat.Data, inputByte, 0, inputByte.Length);

                byte[] labellist = new byte[40960];    //新建字节数组:label1_str label2_str 

                byte[] outputByte = new byte[originMat.Total() * 3];

                Stopwatch sw = new Stopwatch();
                sw.Start();
                unsafe
                {

                    mlResult.IsSuccess = MLEngine.seg_ModelPredict(Model, inputByte, iWidth, iHeight, 3,
                        req.in_lable_path, req.confThreshold, req.iouThreshold, req.confThreshold, req.segmentWidth, ref outputByte[0], ref labellist[0]);
                    //mlResult.IsSuccess = true;
                }
                sw.Stop();

                if (mlResult.IsSuccess)
                {
                    mlResult.ResultMessage = $"深度学习推理成功,耗时:{sw.ElapsedMilliseconds} ms";

                    //将字节数组转换为字符串
                    mlResult.ResultMap = originMat.ToBitmap();//4ms
                    string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length);


                    Console.WriteLine("strGet:", strGet);


                    ConvertJsonResult(strGet, ref mlResult);

                   

                    //解析json字符串

                    return mlResult;
                }
                else
                {
                    mlResult.ResultMessage = $"异常:深度学习执行推理失败!";
                    return mlResult;
                }
            }
            catch (Exception ex)
            {
                mlResult.ResultMessage = $"深度学习执行推理异常";
                return mlResult;
            }
            finally
            {
              
                originMat?.Dispose();
#pragma warning disable CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型 
                originMat = null;
#pragma warning restore CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型 


                // GC.Collect();
            }
#pragma warning restore CS0168 // 声明了变量,但从未使用过
        }

       }
}