using System.Collections.Generic;
using UnityEngine;
using ZIM.Unity;
using Color = UnityEngine.Color;

namespace ZIM
{
    public class InfraredSpot
    {
        // 达到该数量才完成初始化
        //static int InitCount = 5;
        static int MaxVerifyFailLimit = 20;
        public static float MinVerifyLength = 240;

        // 返回null代表没有点，范围在[0, 1]内
        public Vector2? ScreenUV
        {
            get
            {
                if (ScreenLocation.HasValue)
                {
                    return screenMap.UVNormalize(ScreenLocation.Value);
                }
                else
                {
                    return null;
                }
            }
        }
        // 范围在摄像机的Size内
        public Vector2? CameraLocation { 
            get
            {
                if (ScreenLocation.HasValue)
                {
                    return screenMap.TransformToCamera(ScreenLocation.Value);
                }
                else
                    return null;
            }
        }
        public Vector2? Predict { get; set; }        // 为null时代表未初始化
        public InfraredMatch Match { get; private set; }

        public bool Disappear;

        //PixelSpotArea verifyArea;
        int verifyFailLimit;

        List<PixelSpotArea> spots;
        SimpleLocationEstimation estimation;
        Vector2? ScreenLocation;
        ScreenMap screenMap;

        public InfraredSpot(ScreenMap screenMap, InfraredMatch match)
        {
            this.screenMap = screenMap;
            MinVerifyLength = screenMap.UVSize.y / 5;
            Match = match;
            spots = new List<PixelSpotArea>();
            Reset();
        }

        public void Reset() {
            spots.Clear();
            estimation = new SimpleLocationEstimation(0.5f);
            ScreenLocation = null;
            Predict = null;
            Disappear = false;
            //verifyArea = null;
            verifyFailLimit = MaxVerifyFailLimit;
        }

        public bool Verify(List<PixelSpotArea> areas, Dictionary<InfraredMatch, PixelSpotArea> matchedArea)
        {
            if (Predict == null)    // 未初始化
                return false;      

            PixelSpotArea select = null;
            var minLength = float.MaxValue;
            var predict = Predict.Value;
            foreach (var i in areas)
            {
                var len = (i.Center - predict).magnitude;
                if ( len < MinVerifyLength) 
                {
                    if (len < minLength) 
                    {
                        select = i;
                        minLength = len;
                    }
                }
            }

            if (select == null)
            {
                //Debug.Log(verifyFailLimit);
                verifyFailLimit--;
                if (verifyFailLimit == 0) 
                    Reset();
                return false;
            }

            //verifyArea = select;
            matchedArea[Match] = select;
            return true;
        }

        //public void UpdateByVerifyArea()
        //{
        //    Update(verifyArea);
        //}

        // 为null时采用预测点
        public void Update(PixelSpotArea area)
        {
            if (area == null)
            {
                //throw new System.Exception("[InfraredSpot] Update Wrong");
                UpdateByPredict();
                return;
            }

            var predict = estimation.Update(area.Center);
            //ScreenLocation = area.Center;
            ScreenLocation = area.Center * 0.8f + predict * 0.2f;
            spots.Add(area);
            if (spots.Count > 15) 
            {
                Predict = predict;
                spots.RemoveAt(0);
            }
        }

        void UpdateByPredict()
        {
            if (spots.Count != 0)
            {
                if (Predict == null)         // 还未初始化，直接Reset
                    Reset();
                else
                {
                    // 采用预测点，但超出屏幕则Reset
                    if (screenMap.UVInScreen(Predict.Value))
                    {
                        ScreenLocation = Predict;
                        var newP = estimation.Update(Predict.Value);
                        Predict = newP;
                    }
                    else
                        Reset();
                }
            }
        }
    }
}
