using System;
using System.Collections;
using Intrepid.Gameplay.Codex.UI.Components;
using Intrepid.Gameplay.Codex.UI.Controllers;
using Intrepid.Utilities;
using UnityEngine;

namespace Intrepid.Gameplay.Entities.Player.ActionBelt.UI
{
    public class CodexActionBeltSlotControllerUI : CodexControllerUI
    {
        [GroupConfigurations, SerializeField] private float animationDuration = 0.5f;
        [GroupConfigurations, SerializeField] private float animationSpeed = 4.5f;
        [GroupConfigurations, SerializeField] private float scaleEmphasis = 0.90f;
        [GroupConfigurations, SerializeField] private float moveIntensity = 25f;

        [GroupInjections, SerializeField] private CodexPanelComponentUI panel;
        [GroupInjections, SerializeField] private CodexIconComponentUI icon;
        
        private RectTransform RectTransform { get; set; }
        private Vector2 MainPosition { get; set; }
        private Vector3 MainLocalScale { get; set; }
        
        private Coroutine EmphasisRoutine { get; set; }
        private Coroutine BumpRoutine { get; set; }

        protected override void Awake()
        {
            base.Awake();
            RectTransform = GetComponent<RectTransform>();
            MainPosition = RectTransform.anchoredPosition;
            MainLocalScale = transform.localScale;
        }

        private static string MapActionCategoryIDLE(ActionCategory actionCategory)
        {
            return actionCategory switch
            {
                ActionCategory.General => "General IDLE",
                ActionCategory.Terminal => "Terminal IDLE",
                _ => throw new ArgumentOutOfRangeException(nameof(actionCategory), actionCategory, null)
            };
        }

        public void Activate(ActionCategory actionCategory)
        {
            panel.gameObject.SetActive(true);
            icon.gameObject.SetActive(true);
            icon.ChangeAnimation(MapActionCategoryIDLE(actionCategory));
        }
        
        public void Deactivate()
        {
            panel.gameObject.SetActive(false);
            icon.gameObject.SetActive(false);
        }

        public void Emphasis()
        {
            if (EmphasisRoutine is not null)
            {
                StopCoroutine(EmphasisRoutine);
            }
            EmphasisRoutine = StartCoroutine(EmphasisCoroutine());
        }

        public void Bump(Vector2 direction)
        {
            if (BumpRoutine is not null)
            {
                StopCoroutine(BumpRoutine);
            }
            BumpRoutine = StartCoroutine(BumpCoroutine(direction));
        }
        
        private IEnumerator EmphasisCoroutine()
        {
            transform.localScale = MainLocalScale * scaleEmphasis;

            float elapsed = 0;
            while (elapsed < animationDuration)
            {
                var t = Mathf.Clamp01(elapsed / animationDuration);
                transform.localScale = Vector3.Lerp(MainLocalScale * scaleEmphasis, MainLocalScale, t);
                yield return null;
                elapsed += Timer.UnscaledTime * animationSpeed;
            }
            
            transform.localScale = MainLocalScale;
            EmphasisRoutine = null;
        }

        private IEnumerator BumpCoroutine(Vector2 direction)
        {
            var start = MainPosition;
            var end = MainPosition + direction * moveIntensity;

            var elapsed = 0f;

            while (elapsed < animationDuration)
            {
                var t = Mathf.Clamp01(elapsed / animationDuration);
                var eased = 1f - Mathf.Pow(1f - t, 3f);

                RectTransform.anchoredPosition = Vector2.Lerp(start, end, eased);

                yield return null;
                elapsed += Time.unscaledDeltaTime * animationSpeed;
            }

            elapsed = 0f;

            while (elapsed < animationDuration)
            {
                var t = Mathf.Clamp01(elapsed / animationDuration);
                var eased = 1f - Mathf.Pow(1f - t, 3f);

                RectTransform.anchoredPosition = Vector2.Lerp(end, start, eased);

                yield return null;
                elapsed += Time.unscaledDeltaTime * animationSpeed;
            }

            RectTransform.anchoredPosition = MainPosition;
            BumpRoutine = null;
        }

        public void BumpUp()
        {
            Emphasis();
            Bump(Vector2.up);
        }

        public void BumpDown()
        {
            Emphasis();
            Bump(Vector2.down);
        }
        
        public void BumpLeft()
        {
            Emphasis();
            Bump(Vector2.left);
        }

        public void BumpRight()
        {
            Emphasis();
            Bump(Vector2.right);
        }
    }
}