using System;
using System.Collections;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UIElements;

public class UIManager : MonoBehaviour
{
    [SerializeField]
    private Application _application = null;

    [SerializeField]
    private ApplicationChannel _applicationChannel = null;

    [SerializeField]
    private UIDocument _titlecardDocument = null;

	#region Titlecard

    private VisualElement _titleCardScreen = null;
    private const string NAME_TITLECARD_SCREEN = "TitleCardScreen";

    private VisualElement _startButton = null;
    private const string NAME_START_BUTTON = "StartButton";

    private bool _hasClickedPlay = false;

    private void InitializeTitlecard()
    {
        _titleCardScreen = _titlecardDocument.rootVisualElement.Query<VisualElement>(
            NAME_TITLECARD_SCREEN
        );
        _startButton = _titlecardDocument.rootVisualElement.Query<VisualElement>(NAME_START_BUTTON);
        _startButton.RegisterCallback<ClickEvent>(CallbackStartButton);
    }

    private void SetOnTitlecard()
    {
        _titleCardScreen.style.display = DisplayStyle.Flex;
        _clearGameScreen.style.display = DisplayStyle.None;
        _hasClickedPlay = false;
    }

    private void CallbackStartButton(ClickEvent clickEvent)
    {
        if (!_hasClickedPlay)
        {
            _hasClickedPlay = true;

            FadeIn(() =>
            {
                _titleCardScreen.style.display = DisplayStyle.None;
                _application.LoadGameScene(
                    true,
                    () =>
                    {
                        FadeOut();
                    }
                );
            });
        }
    }

	#endregion

    #region Fade In - Fade Out screen

    private VisualElement _fadeScreen = null;

    private const string NAME_FADE_SCREEN = "FadeScreen";

    public float fadeInDuration = 0.5f;

    private void InitializeFadeScreen()
    {
        _fadeScreen = _titlecardDocument.rootVisualElement.Query<VisualElement>(NAME_FADE_SCREEN);
        _fadeScreen.style.display = DisplayStyle.None;
    }

    [ContextMenu("Fade In")]
    private Tween FadeIn(Action action = null)
    {
        _fadeScreen.style.opacity = 0f;
        _fadeScreen.style.display = DisplayStyle.Flex;

        return DOVirtual
            .Float(
                0f,
                1f,
                fadeInDuration,
                (float value) =>
                {
                    _fadeScreen.style.opacity = value;
                }
            )
            .SetEase(Ease.Linear)
            .OnComplete(() =>
            {
                action?.Invoke();
            });
    }

    [ContextMenu("Fade Out")]
    private Tween FadeOut(Action action = null)
    {
        _fadeScreen.style.opacity = 1f;

        return DOVirtual
            .Float(
                1f,
                0f,
                fadeInDuration,
                (float value) =>
                {
                    _fadeScreen.style.opacity = value;
                }
            )
            .SetEase(Ease.Linear)
            .OnComplete(() =>
            {
                _fadeScreen.style.opacity = 0f;
                _fadeScreen.style.display = DisplayStyle.None;
                action?.Invoke();
            });
    }

    // public void FadeInAndOut(
    //     float intervalDuration = 0f,
    //     Action intervalCallback = null,
    //     Action completeCallback = null
    // )
    // {
    //     Sequence sequence = DOTween.Sequence();

    //     sequence
    //         .Append(FadeIn())
    //         .AppendInterval(intervalDuration)
    //         .AppendCallback(() =>
    //         {
    //             intervalCallback();
    //         })
    //         .Append(FadeOut())
    //         .AppendCallback(() =>
    //         {
    //             completeCallback();
    //         });
    // }

    #endregion


    #region Clear Game Screen

    [Header("Clear Game Screen")]
    [SerializeField]
    private float _waitCreditScreen = 2f;

    private VisualElement _clearGameScreen = null;
    private const string NAME_CLEAR_GAME_SCREEN = "ClearGameScreen";
    private VisualElement _clearGameNextButton = null;
    private const string NAME_CLEAR_GAME_NEXT_BUTTON = "ClearGameNextButton";

    public void InitializeClearGameScreen()
    {
        _clearGameScreen = _titlecardDocument.rootVisualElement.Query<VisualElement>(
            NAME_CLEAR_GAME_SCREEN
        );
    }

    [ContextMenu("CallbackClearGameScreen")]
    private void CallbackClearGameScreen()
    {
        StartCoroutine("Test");
    }

    IEnumerator Test()
    {
        bool isWaiting = true;
        FadeIn(() => isWaiting = false);
        while (isWaiting)
            yield return null;

        isWaiting = true;
        _application.UnloadGameScene(() => isWaiting = false);
        while (isWaiting)
            yield return null;

        _clearGameScreen.style.display = DisplayStyle.Flex;
        FadeOut(BackToTitleScreen);
    }

    public void BackToTitleScreen()
    {
        StartCoroutine("BackToTitleScreenCoroutine");
    }

    public IEnumerator BackToTitleScreenCoroutine()
    {
        yield return new WaitForSeconds(_waitCreditScreen);

        FadeIn(() =>
        {
            SetOnTitlecard();
            FadeOut();
        });
    }

    #endregion

	#region MonoBehaviour

    private void Start()
    {
        InitializeFadeScreen();
        InitializeTitlecard();
        InitializeClearGameScreen();

        SetOnTitlecard();

        if (_applicationChannel != null)
            _applicationChannel.onClearedGame += CallbackClearGameScreen;
    }

    private void OnDestroy()
    {
        if (_applicationChannel != null)
            _applicationChannel.onClearedGame -= CallbackClearGameScreen;
    }

	#endregion
}
