using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;


namespace SimplifyXR {

    public enum FlyType
    {
        FlyRight,
        FlyLeft,
        FlyTop,
        FlyBottom
    }

    public static class TransformExtensions
    {
        public static int GetAdjustedSiblingIndex(this Transform transform)
        {
            int index = transform.GetSiblingIndex();
            int adjustedIndex = index;
            for(int i = index; i >= 0; i--)
            {
                if (!transform.parent.GetChild(i)
                    .gameObject.activeSelf)
                {
                    adjustedIndex -= 1;
                }
            }
            return adjustedIndex;
        }
    }

    [RequireComponent(typeof(RectTransform))]
    public class FlyIn : MonoBehaviour
    {


        private Vector3 startRectPos;
        private RectTransform rectTransform;
        private Coroutine flyRoutine;
        private Coroutine fadeRoutine;

        [Header("Fly Variables")]
        public bool fadeIn;
        public FlyType flyInType;
        public float flyDistance;
        public AnimationCurve flyCurve;
        public float flyTime;
        public float delay;
        public bool resetOnEnable;

        [Header("Fly Events")]
        public UnityEvent OnFlyStart;
        public UnityEvent OnFlyEnd;

        private float DelayTime
        {
            get
            {
                return delay * this.gameObject.transform.GetAdjustedSiblingIndex();
            }             
        }


        // Start is called before the first frame update
        public void Awake()
        {
            rectTransform = this.GetComponent<RectTransform>();
            startRectPos = rectTransform.localPosition;
            //Fly();
        }

        public void OnEnable()
        {
            rectTransform = this.GetComponent<RectTransform>();
            if (resetOnEnable) startRectPos = rectTransform.localPosition;
            if (rectTransform != null)
            {
                Fly();
            }
        }

        private void Fly()
        {
            if (flyRoutine != null)
                StopCoroutine(FlyRoutine());
            rectTransform.localPosition = startRectPos;
            flyRoutine = StartCoroutine(FlyRoutine());

            if (fadeRoutine != null) StopCoroutine(FadeRoutine());
            if (fadeIn) fadeRoutine = StartCoroutine(FadeRoutine());
        }


        private Vector3 GetMoveVector3()
        {
            switch (flyInType)
            {
                case FlyType.FlyRight:
                    return new Vector3(1, 0, 0f);
                case FlyType.FlyLeft:
                    return new Vector3(-1, 0, 0f);
                case FlyType.FlyTop:
                    return new Vector3(0, 1, 0f);
                case FlyType.FlyBottom:
                    return new Vector3(0, -1, 0f);
                default:
                    return new Vector3(1, 0f, 0f);
            }
        }

        IEnumerator FadeRoutine()
        {
            var group = this.gameObject.GetOrAddNewComponent<CanvasGroup>();
            group.alpha = 0f;
            if (resetOnEnable) yield return new WaitForSeconds(0.1f);

            if (group != null)
                {
                    yield return new WaitForSeconds(DelayTime);

                    for (float i = 0; i < flyTime; i += Time.deltaTime)
                    {
                        group.alpha = flyCurve.Evaluate(i / flyTime);
                        yield return null;

                    }
                    group.alpha = 1f;
                }

        }


        IEnumerator FlyRoutine()
        {
            OnFlyStart?.Invoke();

            if (resetOnEnable)
            {
                yield return new WaitForSeconds(0.1f);
                startRectPos = rectTransform.localPosition;
            }

            Vector3 flyPos = (GetMoveVector3() * flyDistance)
             + startRectPos;
            rectTransform.localPosition = flyPos;

            yield return new WaitForSeconds(DelayTime);

            for(float i = 0; i < flyTime; i += Time.deltaTime)
            {
                rectTransform.localPosition = Vector3.Lerp(
                    flyPos,
                    startRectPos,
                    flyCurve.Evaluate(i / flyTime)
                    );
                yield return null;
            }
            rectTransform.localPosition = startRectPos;

            OnFlyEnd?.Invoke();
        }


    }


}




