using System.Collections.Generic;
using UnityEngine;

namespace CombatLibrary.CombatLibrary.CombatCore.Utility
{
    public struct ACurve
    {
        public List<CurveInfo> CurveInfos;
        public CurveType CurveType;

        public ACurve(CurveInfo[] curveInfos)
        {
            CurveInfos = new List<CurveInfo>();
            CurveInfos.AddRange(curveInfos);
            CurveType = CurveType.HYT;
        }


        public float Evaluate(float t)
        {
            if (CurveInfos == null)
            {
                return t;
            }

            if (CurveInfos.Count < 2)
            {
                return t;
            }

            switch (CurveType)
            {
                case CurveType.HYT:
                    return HYT(t);
                    break;
                case CurveType.BSL:
                    return BSL(t);
                    break;
            }

            return 0;
        }

        public Vector2 EvaluateForVector2(float t)
        {
            if (CurveInfos == null)
            {
                return new Vector2();
            }

            if (CurveInfos.Count < 2)
            {
                return new Vector2();
            }

            switch (CurveType)
            {
                // case CurveType.HYT:
                //     // return HYT(t);
                //     break;
                case CurveType.BSL:
                    return BSLForVector2(t);
                    break;
            }

            return new Vector2();
        }

        private Vector2 BSLForVector2(float t)
        {
            CurveInfo c1 = default;
            CurveInfo c2 = default;
            for (int i = 0; i < CurveInfos.Count; i++)
            {
                if (CurveInfos[i].BSLt > t)
                {
                    int lindex = i - 1;
                    if (lindex < 0)
                    {
                        CurveInfo endInfo = CurveInfos[i];
                        Vector2 endPos = new Vector2((float)endInfo.t, (float)endInfo.v);
                        return endPos;
                    }

                    c1 = CurveInfos[i - 1];
                    c2 = CurveInfos[i];
                    break;
                }
            }

            if (c2.t==0)
            {
                CurveInfo endInfo = CurveInfos[^1];
                Vector2 endPos = new Vector2(endInfo.t, endInfo.v);
                return endPos;
            }


            Vector2 pos1 = new Vector2((float)c1.t, (float)c1.v);
            Vector2 pos2 = new Vector2((float)c1.it, (float)c1.ot);
            Vector2 pos4 = new Vector2((float)c2.t, (float)c2.v);
            Vector2 pos3 = new Vector2((float)c2.it, (float)c2.ot);
            // float v11 = (float) c1.t;
            // float v12 = (float) c1.v;
            // float t11 = (float) c1.it;
            // float t12 = (float) c1.ot;
            //
            // float v21 = (float) c2.t;
            // float v22 = (float) c2.v;
            // float t21 = (float) c2.it;
            // float t22 = (float) c2.ot;

            Vector2 a = Vector2.Lerp(pos1, pos2, t);
            Vector2 b = Vector2.Lerp(pos2, pos3, t);
            Vector2 c = Vector2.Lerp(pos3, pos4, t);
            Vector2 d = Vector2.Lerp(a, b, t);
            Vector2 e = Vector2.Lerp(b, c, t);
            Vector2 f = Vector2.Lerp(d, e, t);
            return f;
        }

        private float BSL(float t)
        {
            CurveInfo c1 = default;
            CurveInfo c2 = default;
            for (int i = 0; i < CurveInfos.Count; i++)
            {
                if (CurveInfos[i].t > t)
                {
                    int lindex = i - 1;
                    if (lindex < 0)
                    {
                        return (float)CurveInfos[i].v;
                    }

                    c1 = CurveInfos[i - 1];
                    c2 = CurveInfos[i];
                    break;
                }
            }

            if (c2.t == 0)
            {
                return (float)CurveInfos[^1].v;
            }


            Vector2 pos1 = new Vector2((float)c1.t, (float)c1.v);
            Vector2 pos2 = new Vector2((float)c1.it, (float)c1.ot);
            Vector2 pos4 = new Vector2((float)c2.t, (float)c2.v);
            Vector2 pos3 = new Vector2((float)c2.it, (float)c2.ot);
            // float v11 = (float) c1.t;
            // float v12 = (float) c1.v;
            // float t11 = (float) c1.it;
            // float t12 = (float) c1.ot;
            //
            // float v21 = (float) c2.t;
            // float v22 = (float) c2.v;
            // float t21 = (float) c2.it;
            // float t22 = (float) c2.ot;

            Vector2 a = Vector2.Lerp(pos1, pos2, t);
            Vector2 b = Vector2.Lerp(pos2, pos3, t);
            Vector2 c = Vector2.Lerp(pos3, pos4, t);
            Vector2 d = Vector2.Lerp(a, b, t);
            Vector2 e = Vector2.Lerp(b, c, t);
            Vector2 f = Vector2.Lerp(d, e, t);
            return f.y;
        }

        private float HYT(float t)
        {
            CurveInfo c1 = default;
            CurveInfo c2 = default;
            for (int i = 0; i < CurveInfos.Count; i++)
            {
                if (CurveInfos[i].t > t)
                {
                    int lindex = i - 1;
                    if (lindex < 0)
                    {
                        return (float)CurveInfos[i].v;
                    }

                    c1 = CurveInfos[i - 1];
                    c2 = CurveInfos[i];
                    break;
                }
            }

            if (c2.t == 0)
            {
                return (float)CurveInfos[^1].v;
            }

            float ct = (float)c2.t - c1.t;
            t = (t - c1.t) / ct;
            float ot = c1.ot * ct;
            float it = c2.it * ct;

            float t2 = t * t;
            float t3 = t2 * t;

            float a = (2 * t3 - 3 * t2 + 1);
            float b = t3 - 2 * t2 + t;
            float c = t3 - t2;
            float d = -2 * t3 + 3 * t2;

            return a * c1.v + b * ot + c * it + d * c2.v;
        }
    }
}