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;





public class SegResult
{
    public List<Result> SegmentResult;
    public class Result
    {

        public double fScore;
        public int classId;
        public string classname;

        public double area;
        public List<int> rect;


    }

}



/// <summary>
/// 实例分割 maskrcnn
/// </summary>
public class SimboObjectDetection
{


    IntPtr Model;

    public bool Load(string ModelFile, string InferenceDevice, string InputNodeName, int InferenceWidth, int InferenceHeight)
    {
        bool res = false;
        try
        {


            Model = MLEngine.InitModel(ModelFile,
                InferenceDevice,
                InputNodeName,
                1, 3,
                InferenceWidth,
               InferenceHeight);
            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 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);
        SegResult detResult = JsonConvert.DeserializeObject<SegResult>(json);
        if (detResult == null)
        {
            return;
        }

        int iNum = detResult.SegmentResult.Count;
        int IokNum = 0;
        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.NG;

            result.ResultDetails.Add(detectionResultDetail);
        }
        result.ResultDetails.Sort((s1, s2) => s1.Rect.X.CompareTo(s2.Rect.X));


    }




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

        try
        {


            // resize
            originMat = req.currentMat;//1ms

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

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

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

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

            Stopwatch sw = new Stopwatch();
            sw.Start();
            unsafe
            {
                mlResult.IsSuccess = MLEngine.det_ModelPredict(Model,
                    inputByte,
                    iWidth, iHeight, 3,
                    req.out_node_name,
                    req.in_lable_path,
                    req.confThreshold, req.iouThreshold,
                    ref outputByte[0],
                    ref labellist[0]);
                //mlResult.IsSuccess = true;
            }
            sw.Stop();

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

                Mat maskWeighted = new Mat(iHeight, iWidth, MatType.CV_8UC3, outputByte);

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

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

                ConvertJsonResult(strGet, ref mlResult);

                maskWeighted?.Dispose();
                maskWeighted = null;

                // 解析json字符串
                return mlResult;
            }
            else
            {
                mlResult.ResultMessage = $"异常:深度学习执行推理失败!";
                return mlResult;
            }
        }
        catch (Exception ex)
        {
            //mlResult.ResultMessage = $"深度学习执行推理异常:{ex.GetExceptionMessage()}";
            return mlResult;
        }
        finally
        {

           // originMat?.Dispose();
           // originMat = null;


            // GC.Collect();
        }
    }


}