using OpenCVForUnity.CoreModule;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public abstract class PoseBase
{
    public Dictionary<string, Point> GetVaildPoints(List<Point> points, List<string> pointName)
    {
        var retVal = new Dictionary<string, Point>();

        foreach (var name in pointName)
        {
            if (points[YogaConfig.BODY_PARTS[name]] != new Point(-1, -1))
            {
                retVal.Add(name, points[YogaConfig.BODY_PARTS[name]]);
            }
        }
        return retVal;
    }
    public virtual Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint) { return Vector2.zero; }

    //public abstract void SpeedCheck(double v);
    public abstract bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level);
    public abstract void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan);

    /// <summary>
    /// 侦测两帧之间的平均矢量
    /// </summary>
    /// <param name="firstPoints">起始帧</param>
    /// <param name="lastPoints">结束帧</param>
    /// <param name="startPoint">必须为必要点</param>
    /// <param name="endPoint">必须为必要点</param>
    /// <returns></returns>
    protected Vector2 GetTwoPointAverageVector(List<Point> firstPoints, List<Point> lastPoints, string startPoint, string endPoint)
    {
        Vector2 startEyeV = new Vector2((float)startPoint.p(firstPoints).x - (float)endPoint.p(firstPoints).x, (float)startPoint.p(firstPoints).y - (float)endPoint.p(firstPoints).y);
        Vector2 endEyeV = new Vector2((float)startPoint.p(lastPoints).x - (float)endPoint.p(lastPoints).x, (float)startPoint.p(lastPoints).y - (float)endPoint.p(lastPoints).y);
        return endEyeV - startEyeV;
    }

    /// <summary>
    /// 对全身多点进行平均矢量计算
    /// </summary>
    /// <param name="startPoint"></param>
    /// <param name="endPoint"></param>
    /// <param name="movePoint"></param>
    /// <returns></returns>
    protected Vector2 GetAverageVector(List<Point> startPoint, List<Point> endPoint, string movePoint)
    {
        List<Vector2> vectors = new List<Vector2>();
        for (int i = 0; i < endPoint.Count; i++)
        {
            string tagName = i.tagName();

            //自身不计算
            if (movePoint.Equals(tagName) || movePoint.Equals(tagName))
                continue;
            //动点位不计算
            if (IsMovePoint(tagName))
                continue;

            if (!tagName.IsValid(startPoint) || !tagName.IsValid(endPoint))
                continue;
            //动点-静点
            Vector2 startEyeV = new Vector2((float)movePoint.p(startPoint).x - (float)tagName.p(startPoint).x, (float)movePoint.p(startPoint).y - (float)tagName.p(startPoint).y);
            Vector2 endEyeV = new Vector2((float)movePoint.p(endPoint).x - (float)tagName.p(endPoint).x, (float)movePoint.p(endPoint).y - (float)tagName.p(endPoint).y);
            vectors.Add(endEyeV - startEyeV);
        }
        //计算平均矢量
        Vector2 averageV = new Vector2(0, 0);
        foreach (var v in vectors)
        {
            averageV += v;
        }
        averageV /= vectors.Count;

        return averageV;
    }

    /// <summary>
    /// 确定该点位是否为运动时会跟着动的点位
    /// 内部重写,写明该动作的所有动点
    /// </summary>
    /// <param name="tagName">点位名称</param>
    /// <returns>是否为动点</returns>
    protected abstract bool IsMovePoint(string tagName);

    /// <summary>
    /// 动作检测
    /// </summary>
    /// <param name="points"></param>
    /// <param name="isDataReGather"></param>
    public virtual bool? AnalyzingAction(List<(DateTime, List<Point>)> points, bool isDataReGather = false)
    {
        if (points.Count < 2) // 0级实现逻辑 不做操作
            return null;

        var distance = Vector2.zero;
        TimeSpan totalTimeSpan = TimeSpan.MinValue;
        for (int i = 0; i < points.Count - 1; i++)
        {
            var p1 = points[i].Item2;
            var p2 = points[i + 1].Item2;

            var vector = GetBasicVectorDirection(p1, p2);
            distance += vector;
            //if (vector.magnitude > 0.1f) //如果矢量长度大于0.1f,说明有运动
            //{
            //    TimeSpan timeSpan = points[i + 1].Item1 - points[i].Item1;

            //    if (totalTimeSpan == TimeSpan.MinValue)
            //        totalTimeSpan = timeSpan;
            //    else
            //        totalTimeSpan += timeSpan;
            //}
            TimeSpan timeSpan = points[i + 1].Item1 - points[i].Item1;
            totalTimeSpan = timeSpan;
        }
        LogPrint.Log($"distance: {distance}, totalTimeSpan: {totalTimeSpan}", PrintLevel.Normal);

        int level = 0;
        if (points.Count > 3 && !isDataReGather) //1级实现逻辑
        {
            level = 1;
        }
        if (points.Count > 10 && !isDataReGather) //2级实现逻辑
        {
            level = 2;
        }

        //动作方位是否正确
        return MovementValidation(distance, totalTimeSpan, level);
    }

    /// <summary>
    /// 帮助方法,用于提供基础的检测,动作方位是否正确
    /// </summary>
    /// <param name="distance"></param>
    /// <param name="totalTimeSpan"></param>
    /// <param name="direction"></param>
    /// <param name="level"></param>
    protected bool? BasicMovementValidation(Vector2 distance, TimeSpan totalTimeSpan, Vector2 direction, int level)
    {
        if (totalTimeSpan.TotalMilliseconds / 1000 < 0.05f)
        {
            LogPrint.Error("TimeSpan too short");
            return null;
        }
        var angle = Vector2.SignedAngle(direction, distance);
        LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
        if (MathF.Abs(angle) < 50 && distance.magnitude > 10f)
        {
            //EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
            return true;
        }
        else
        {
            LogPrint.Warning($"Angle:{angle}, magnitude:{distance.magnitude}", PrintLevel.Important);
            //EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
            return false;
        }

        //if (level < 1)
        //    return;

        //暂时关闭距离检测,因为距离检测不准确

        //LogPrint.Log($"distance  x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
        //if (distance.magnitude > 80f || distance.magnitude < 20f)
        //    EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
        //else
        //    EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);

        //if (level < 2)
        //    return;

        //暂时关闭速度检测,因为速度检测不准确

        //var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
        //LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
        //if (speed > 20f)
        //    EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
        //else if (speed < 8f)
        //    EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
    }
}