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


public class GameStateChangedEvent : UnityEvent<GameState, GameState>
{
    
}

public enum GameState
{
    Menu,
    Play,
    GameOver,
    GameOverMenu
}

public class GameStateManager : PersistentManager<GameStateManager>
{
    private bool isLoading;

    private GameState gameState = GameState.Menu;

    public GameState GameState { get { return gameState; } }

    [SerializeField]
    private Image TransitionImage;

    private const float FADE_DURATION = 0.5f;

    public GameStateChangedEvent OnGameStateChangedEvent = new GameStateChangedEvent();

    public GameState InitialState;

    protected override void Awake()
    {
        if(GameStateManager.Instance != null)
        {
            Destroy(this.gameObject);
        }
        else
        {
            base.Awake();
            SetGameState(InitialState);
        }
    }

    private IEnumerator FadeCanvasToBlackCoroutine()
    {
        if(TransitionImage != null)
        {
            float x = 0.0f;

            while(x < 1.0f)
            {
                x += ((1.0f / FADE_DURATION) * Time.deltaTime);
                if(x > 1.0f)
                {
                    x = 1.0f;
                }

                Color c = TransitionImage.color;
                c.a = x;
                TransitionImage.color = c;

                yield return new WaitForEndOfFrame();
            }
        }
    }

    private IEnumerator FadeCanvasToTransparentCoroutine()
    {
        if(TransitionImage != null)
        {
            float x = 0.0f;
            while(x < 1.0f)
            {
                x += ((1.0f / FADE_DURATION) * Time.deltaTime);
                if(x > 1.0f)
                {
                    x = 1.0f;
                }

                Color c = TransitionImage.color;
                c.a = x * -1.0f;
                TransitionImage.color = c;

                yield return new WaitForEndOfFrame();
            }
        }
    }

    private IEnumerator loadGameSceneCoroutine()
    {
        StartCoroutine(FadeCanvasToBlackCoroutine());
        yield return new WaitForSeconds(FADE_DURATION);

        AsyncOperation asyncOperation = SceneManager.LoadSceneAsync("test");
        while(!asyncOperation.isDone)
        {
            yield return new WaitForSeconds(0.1f);
        }
        
        yield return new WaitForSeconds(1.0f);
        
        this.updateGameStateAndFireEvents(GameState.Play);

        StartCoroutine(FadeCanvasToTransparentCoroutine());

        isLoading = false;
    }

    private void updateGameStateAndFireEvents(GameState newState)
    {
        GameState oldGameStae = this.gameState;
        this.gameState = newState;
        OnGameStateChangedEvent.Invoke(this.gameState, oldGameStae);
    }

    private IEnumerator playGameOverAnimationAndSwitchScene()
    {
        this.updateGameStateAndFireEvents(GameState.GameOver);

        yield return new WaitForSeconds(1.5f);

        AudioManager.Instance.GetAudioSource(AudioClip.Explosion).Play();
        Player.Instance.Explosion.Play();
        
        yield return new WaitForSeconds(0.4f);

        PersistantStorage.Instance.Score = Player.Instance.Score;

        this.SetGameState(GameState.GameOverMenu);
    }

    public void SetGameState(GameState gameState)
    {
        if(gameState == GameState.Play)
        {
            if(!isLoading)
            {
                isLoading = true;
                StartCoroutine(loadGameSceneCoroutine());
            }
        }

        if(gameState == GameState.GameOver)
        {
            StartCoroutine(playGameOverAnimationAndSwitchScene());
        }

        if(gameState == GameState.GameOverMenu)
        {
            SceneManager.LoadScene("GameOverMenu");
            this.updateGameStateAndFireEvents(GameState.GameOverMenu);
        }

        if(gameState == GameState.Menu)
        {
            SceneManager.LoadScene("Menu");
            this.updateGameStateAndFireEvents(GameState.Menu);
        }
    }
}