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

public class CastBarHandler : MonoBehaviour
{
    #region Singleton
    private static CastBarHandler _instance;

    // Public reference to the singleton instance
    public static CastBarHandler Instance
    {
        get
        {
            // If the instance doesn't exist, try to find it in the scene
            if (_instance == null)
            {
                _instance = FindObjectOfType<CastBarHandler>();

                // If it's still null, create a new GameObject and add the component
                if (_instance == null)
                {
                    GameObject singletonObject = new GameObject(typeof(CastBarHandler).Name);
                    _instance = singletonObject.AddComponent<CastBarHandler>();
                }
            }
            return _instance;
        }
    }
    #endregion

    public GameObject castBar;
    public Image imageToFill;

    public float timer;
    public float currentCastTime;
    public float currentChannelTime;
    public BaseAbility currentAbility;
    float startFill;
    float endFill;

    public UnityEvent<bool> OnCastingStateChanged = new UnityEvent<bool>();

    Action currentlyWaitingAbilityExecution;
    Action currentlyChannelingAbilityExecution;

    private void Awake()
    {
        if (_instance != null && _instance != this)
        {
            Destroy(gameObject);
            return;
        }

        // If this is the first instance, set it as the singleton
        _instance = this;
        DontDestroyOnLoad(gameObject);

    }

    private void Start()
    {
        ToggleCastBarVisibility(false);
    }

    public void ShowCastBar(BaseAbility ability, Action abilityExecution)
    {
        currentlyWaitingAbilityExecution = abilityExecution;
        currentAbility = ability;
        currentCastTime = ability.castTime;
        StartCoroutine(FillImageOverTime(ability.castTime + 0.01f));
    }
    public void ShowChannelingBar(BaseAbility ability, Action abilityChannelExecution)
    {
        currentlyChannelingAbilityExecution = abilityChannelExecution;
        currentAbility = ability;
        currentChannelTime = ability.castTime;
        StartCoroutine(DecayImageOverTime(((ChanneledAbility)ability).duration + 0.01f));
    }

    IEnumerator FillImageOverTime(float castTime)
    {
        ToggleCastBarVisibility(true);

        timer = 0f;
        startFill = 0f;
        endFill = 1f;

        imageToFill.fillAmount = startFill;

        while (timer < castTime)
        {
            float fillAmount = Mathf.Lerp(startFill, endFill, timer / castTime);
            imageToFill.fillAmount = fillAmount;
            timer += Time.deltaTime;
            yield return null;
        }

        // Ensure fillAmount is exactly 1 at the end
        imageToFill.fillAmount = endFill;

        ToggleCastBarVisibility(false);
    }

    IEnumerator DecayImageOverTime(float channelTime)
    {
        ToggleCastBarVisibility(true);

        timer = 0f;
        startFill = 1f;
        endFill = 0f;

        imageToFill.fillAmount = startFill;

        while (timer < channelTime)
        {
            float fillAmount = Mathf.Lerp(startFill, endFill, timer / channelTime);
            imageToFill.fillAmount = fillAmount;
            timer += Time.deltaTime;
            yield return null;
        }

        // Ensure fillAmount is exactly 1 at the end
        imageToFill.fillAmount = endFill;

        ToggleCastBarVisibility(false);
    }

    private void ToggleCastBarVisibility(bool isVisible)
    {
        castBar.SetActive(isVisible);
        OnCastingStateChanged.Invoke(isVisible);
    }

    public void CancelChannelingOnButtonReleased()
    {
        StopAllCoroutines();

        ToggleCastBarVisibility(false);
    }

    public void ExecuteQueuedCastOnAnimationEvent()
    {
        //Debug.Log("$$Executing queued melee before null check");
        if (currentlyWaitingAbilityExecution == null) return;
        //Debug.Log("$$Executing queued melee after check");
        currentlyWaitingAbilityExecution.Invoke();
    }
}
