using NUnit.Framework.Internal;
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.DnnModule;
using OpenCVForUnity.UnityUtils;
using OpenCVForUnity.UnityUtils.Helper;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.UI;
using Yoga;

public class YogaManager : MonoSingleton<YogaManager>
{
    private List<Point> _baseKeyPoints = new List<Point>();
    private Mat _rgbaMat;
    public Mat RgbaMat
    {
        get
        {
            return _rgbaMat;
        }

        set => _rgbaMat = value;
    }

    private Queue<(DateTime, List<Point>)> _estimateKeyPointsCache = new Queue<(DateTime, List<Point>)>();
    public Queue<(DateTime, List<Point>)> EstimateKeyPointsCache
    {
        get => _estimateKeyPointsCache;
    }

    private List<Point> _currEstimateKeyPoints;
    public List<Point> CurrEstimateKeyPoints { get => _currEstimateKeyPoints; set => _currEstimateKeyPoints = value; }

    public void AddCurrEstimateKeyPoints(List<Point> points)
    {
        _currEstimateKeyPoints = points;
        _estimateKeyPointsCache.Enqueue((DateTime.Now, points));
        if (_estimateKeyPointsCache.Count > YogaConfig.CurrEstimateKeyPointsMaxCount)
        {
            _estimateKeyPointsCache.Dequeue();
        }
    }

    private List<float[]> _personRectResult = new List<float[]>();
    public List<float[]> PersonRectResult { get => _personRectResult; set => _personRectResult = value; }

    public List<Point> BaseKeyPoints { get => _baseKeyPoints; set => _baseKeyPoints = value; }

    private int _currentCheckPointCount; //当前动作计数
    public int CurrentCheckPointCount { get => _currentCheckPointCount; }

    private int _currentCheckPointSuccessCount; //当前成功动作计数
    public int CurrentCheckPointSuccessCount { get => _currentCheckPointSuccessCount; }

    public int MaxCheckPointCount => LevelData.MaxCheckPointCount;

    private int _levelIndex = -1;    //用户选择界面选择的动作索引
    public int LevelIndex { get => _levelIndex; internal set => _levelIndex = value; }

    private Dictionary<AvatarAction, PoseBase> _actions = new Dictionary<AvatarAction, PoseBase>();

    private bool _isSamplingRunning = false;


    public YogaData LevelData
    {
        get
        {
            if (_levelData == null)
            {
                LogPrint.Warning("Action Not Load!", PrintLevel.Normal);
                InitData();
            }

            return _levelData;
        }

        set => _levelData = value;
    }
    private Estimator _currentEstimator;
    public Estimator CurrentEstimator { get => _currentEstimator; internal set => _currentEstimator = value; }

    private YogaData _levelData = null;
    private int _actionIndex = 0;
    private int _comboTimes = 0;
    private bool? _samplingResult = null;
    private bool? _samplingYogaResult;

    public DateTime ActionStartTime { get; set; }
    public int ActionIndex { get => _actionIndex; internal set => _actionIndex = value; }
    public bool? SamplingResult { get => _samplingResult; }

    public void InitData()
    {
        _actions[AvatarAction.HeadTurnLeft] = new HeadTurnLeft();
        _actions[AvatarAction.HeadTurnRight] = new HeadTurnRight();
        _actions[AvatarAction.HeadTurnUp] = new HeadTurnUp();
        _actions[AvatarAction.HeadTurnDown] = new HeadTurnDown();
        _actions[AvatarAction.HandsUp] = new HandsUp();
        _actions[AvatarAction.HandsDown] = new HandsHold();

        _currentCheckPointCount = 0;
        _currentCheckPointSuccessCount = 0;
        _comboTimes = 0;

        //根据用户选择的动作索引,获取相应的资源
        LevelData = YogaDataLoader.LoadData(LevelIndex);
        EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentCheckPointSuccessCount, CurrentCheckPointCount);
    }
    private void OnEnable()
    {
        EventManager.Instance.AddEventListener(YogaEventType.UI_LevelFinished, ClearingSettlement);

        EventManager.Instance.AddEventListener(YogaEventType.Action_Success, OnActionSuccess);
        EventManager.Instance.AddEventListener(YogaEventType.Action_Fail, OnActionFailed);
        EventManager.Instance.AddEventListener(YogaEventType.Action_Evaluate, OnEvaluation);
        //extra event 
        EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceExactly, ExtraMoveDistanceExactly);
        EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceNotAccurate, ExtraMoveDistanceNotAccurate);
        EventManager.Instance.AddEventListener(YogaEventType.Action_SpeedTooSlow, ExtraSpeedTooSlow);
        EventManager.Instance.AddEventListener(YogaEventType.Action_SpeedTooFast, ExtraSpeedTooFast);
    }



    private void OnDisable()
    {
        EventManager.Instance.RemoveEventListener(YogaEventType.UI_LevelFinished, ClearingSettlement);

        EventManager.Instance.RemoveEventListener(YogaEventType.Action_Success, OnActionSuccess);
        EventManager.Instance.RemoveEventListener(YogaEventType.Action_Fail, OnActionFailed);
        EventManager.Instance.RemoveEventListener(YogaEventType.Action_StartSampling, OnSamplingStart);
        EventManager.Instance.RemoveEventListener(YogaEventType.Action_EndSampling, OnSamplingEnd);
        EventManager.Instance.RemoveEventListener(YogaEventType.Action_Evaluate, OnEvaluation);

        //extra event
        EventManager.Instance.RemoveEventListener(YogaEventType.Action_MoveDistanceExactly, ExtraMoveDistanceExactly);
        EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceNotAccurate, ExtraMoveDistanceNotAccurate);
        EventManager.Instance.RemoveEventListener(YogaEventType.Action_SpeedTooSlow, ExtraSpeedTooSlow);
        EventManager.Instance.RemoveEventListener(YogaEventType.Action_SpeedTooFast, ExtraSpeedTooFast);
    }

    #region UI相关
    private void OnActionSuccess()
    {
        _currentCheckPointSuccessCount++;
        _currentCheckPointCount++;
        //是否为连续正确动作

        UpdateData();
    }
    private void OnActionFailed()
    {
        _currentCheckPointCount++;
        UpdateData();
    }

    private void UpdateData()
    {
        if (CurrentCheckPointCount > MaxCheckPointCount)//如果超过最大数,则停止检测,跳转到下一个动作/下一个动作引导/奖励界面
        {
            LogPrint.Warning("CurrentActionCount > MaxActionCount", PrintLevel.Normal);
            ClearingSettlement();
        }

        EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentCheckPointSuccessCount, CurrentCheckPointCount, MaxCheckPointCount);//args[0] = successCount args[1] = excutedCount args[2] = totalCount
    }

    /// <summary>
    /// 跳转结算界面
    /// </summary>
    public void ClearingSettlement()
    {
        //跳转到奖励界面
        UIManager.Instance.CloseCurrent(); //关闭当前界面并停止检测
        UIManager.Instance.ShowPanel<ClearingSettlementUI>(false, CurrentCheckPointSuccessCount, MaxCheckPointCount);//args[0] = successCount args[1] = totalCount 
        _estimateKeyPointsCache.Clear();
    }
    #endregion

    #region 动作检测相关


    //采样质量评估
    public bool? SampleQualityEvaluation(AvatarAction actionType, DateTime startTime, DateTime endTime)
    {
        //获取时间间隔内的所有点及向量变化
        var framePoints = _estimateKeyPointsCache.Where(x => x.Item1 >= startTime && x.Item1 <= endTime).ToList();
        if (framePoints == null)
        {
            LogPrint.Warning("No point has been estimated!");
            framePoints = new List<(DateTime, List<Point>)>();
        }

        //循环遍历所有的点,检测是否符合最低点数要求
        var checkedPoints = new List<(DateTime, List<Point>)>();
        for (int i = 0; i < framePoints.Count; i++)
        {
            var p = framePoints[i];
            if (!ActionCheckPoints(p.Item2))
                continue;
            checkedPoints.Add(p);
        }

        if (checkedPoints.Count < 2) //0级实现逻辑
        {
            return NeedMoreData(actionType, startTime, endTime);
        }
        else
        {
            return _actions[actionType].AnalyzingAction(checkedPoints);
        }
    }

    //需要更多数据
    private bool? NeedMoreData(AvatarAction actionType, DateTime startTime, DateTime endTime)
    {
        //获取1秒后时间间隔内的所有点及向量变化
        var points = _estimateKeyPointsCache.Where(x => x.Item1 >= startTime.AddSeconds(1) && x.Item1 <= endTime.AddSeconds(1)).ToList();
        if (points == null)
        {
            //提示摆正姿势
            LogPrint.Warning("No point has been estimated!");
            return null;
        }
        //检测动作是否正确
        return _actions[actionType].AnalyzingAction(points, true);
    }
    #endregion

    #region 事件监听


    private void OnSamplingStart()
    {
        //获取开始时间标记戳
        ActionStartTime = DateTime.Now;
        _isSamplingRunning = true;
    }

    private void OnSamplingEnd(params object[] args)
    {
        _isSamplingRunning = false;
        if (args == null || args.Length == 0)
        {
            LogPrint.Error("GetActionBasePoint args is null. Please check animation event trigger configuration.");
            return;
        }
        try
        {
            AvatarAction actionType = (AvatarAction)args.FirstOrDefault();
            var startTime = ActionStartTime;
            _samplingResult = SampleQualityEvaluation(actionType, ActionStartTime, DateTime.Now);
            //只有hold动作检测
            if (actionType == AvatarAction.Hold)
            {
                _samplingYogaResult = _samplingResult;
            }
        }
        catch (Exception e)
        {
            LogPrint.Exception(e);
        }
    }

    private void OnEvaluation()
    {
        if (_samplingYogaResult == null || _samplingYogaResult == false)
        {
            _samplingYogaResult = null;
            EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
            return;
        }

        EventManager.Instance.Dispatch(YogaEventType.Action_Success);
        _comboTimes++;
        if (_comboTimes >= 3)
        {
            AudioManager.Instance.PlayCVInQueue("WellDone");
        }
        else if (_comboTimes == 2)
        {
            AudioManager.Instance.PlayCVInQueue("Nice");
        }
        else
        {
            AudioManager.Instance.PlayCVInQueue("Good");
        }
        _samplingYogaResult = null;
    }
    /// extra
    private void ExtraMoveDistanceExactly()
    {
        AudioManager.Instance.PlayCVInQueue("ExactlyCorrect");
    }
    private void ExtraMoveDistanceNotAccurate()
    {
        AudioManager.Instance.PlayCVInQueue("NotAccurate");
    }

    private void ExtraSpeedTooFast()
    {
        AudioManager.Instance.PlayCVInQueue("SpeedTooFast");
    }

    private void ExtraSpeedTooSlow()
    {
        AudioManager.Instance.PlayCVInQueue("SpeedTooSlow");
    }
    #endregion


    public bool ActionCheckPoints(List<Point> points)
    {
        if (points == null || points.Count == 0)
        {
            LogPrint.Log("ActionCheckPoints points is null");
            return false;
        }

        //for (int i = 0; i < points.Count; i++)
        //{
        //    Point p = points[i];
        //    if (p != new Point(-1, -1))
        //        LogPrint.Warning($"ActionPoints p({i}): {i.tagName()}, value: {p.x},{p.y}");
        //}

        foreach (var p in LevelData.MustPoints)
        {
            if (!p.IsValid(points)) //有一个点不符合 返回false
            {
                //LogPrint.Log($"ActionCheckPoints failed, {p} is not valid");
                return false;
            }
        }

        //不设的情况下,不检测
        if (LevelData.AnyPoints != null && LevelData.AnyPoints.Count > 0)
        {
            foreach (var p in LevelData.AnyPoints)
            {
                if (p.IsValid(points)) //有一个点符合 返回true
                {
                    return true;
                }
            }
            return false; //没有一个点符合 返回false
        }

        return true;
    }
}