using UnityEngine;
using System;
using System.Collections;
using UnityEngine.SceneManagement;
using UnityEngine.UI;


public enum GameState
{
    MainMenu,
    Tutorial,
    Loading,
    Playing,
    Paused,
    GameOver,
    Victory
}

public class GameManager : MonoBehaviour
{
    public static GameManager Instance{get;private set;} // Singleton Pattern for GameManager
    [Header("Config")]
    [SerializeField] private string firstLevelSceneName = "Level 0";
    [SerializeField] private string mainMenuSceneName = "TUM-MainMenu";
    [SerializeField] private string tutorialSceneName = "Tutorial";
    [SerializeField] public GameState CurrentState = GameState.MainMenu;
    
    [Header("Loading UI")]
    [SerializeField] private CanvasGroup loadingCanvas;   // assign a canvasgroup on your loading UI
    [SerializeField] private Image loadingProgressBarFill;   // optional
    [SerializeField] private float minLoadingScreenTime = 0.3f;
    private Coroutine loadRoutine;
    private bool isLoading;
    public event Action<GameState> OnGameStateChanged;
    
    private void Awake()
    {
        if(Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
        HideLoadingImmediate();
        SceneManager.sceneLoaded += OnSceneLoaded;
        if (SceneManager.GetActiveScene().name.Equals(firstLevelSceneName))
        {
            //set player prefs
            PlayerPrefs.SetInt("numberIdx", 0);
            PlayerPrefs.SetFloat("fillAmount", 0);
        }
    }
    private void OnDestroy()
    {
        if(Instance == this)
        {
            SceneManager.sceneLoaded -= OnSceneLoaded;
        }
    }
    
    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        if (scene.name == firstLevelSceneName || scene.name.StartsWith("Level_"))
        {
            SetState(GameState.Playing);
        }
    }
    // Public API
    public void StartGame()
    {
        LoadLevel(firstLevelSceneName);
    }

    public void StartTutorial()
    {
        CurrentState = GameState.Tutorial;
        LoadLevel(tutorialSceneName);
    }
    
    public void LoadLevel(string sceneName) => LoadSceneWithLoading(sceneName, GameState.Playing);

    public void ReloadCurrentLevel()
    {
        SetState(GameState.Loading);
        Time.timeScale = 1f;
        Scene scene = SceneManager.GetActiveScene();
        LoadLevel(scene.name);
    }
    
    public void GoToMainMenu()
    {
        SetState(GameState.MainMenu);
        Time.timeScale = 1f;
        LoadLevel(mainMenuSceneName);
    }

    public void PauseGame()
    {
        if (CurrentState != GameState.Playing && CurrentState != GameState.Tutorial)
            return;
        SetState(GameState.Paused);
        Time.timeScale = 0f;
    }

    public void ResumeGame()
    {
        if (CurrentState != GameState.Paused)
            return;
        
        if (SceneManager.GetActiveScene().name.Equals(tutorialSceneName))
        {
            SetState(GameState.Tutorial);
        }
        else
        {
            SetState(GameState.Playing);
        }

        Time.timeScale = 1f;
    }
    
    private void LoadSceneWithLoading(string sceneName, GameState? forceState = null)
    {
        if (isLoading) return;
        isLoading = true;
        Time.timeScale = 1f;

        if (loadRoutine != null)
            StopCoroutine(loadRoutine);

        loadRoutine = StartCoroutine(LoadSceneAsyncRoutine(sceneName, forceState));
    }
    
    private IEnumerator LoadSceneAsyncRoutine(string sceneName, GameState? forceState)
    {
        SetState(GameState.Loading);
        ShowLoading();

        float t = 0f;

        var op = SceneManager.LoadSceneAsync(sceneName);
        op.allowSceneActivation = false;

        while (!op.isDone)
        {
            
            t += Time.unscaledDeltaTime;

            // Unity loads 0..0.9 then waits for activation
            float normalized = Mathf.Clamp01(op.progress / 0.9f);

            if (loadingProgressBarFill != null)
                loadingProgressBarFill.fillAmount = normalized;
            //Debug.Log("load amount" + loadingProgressBarFill.fillAmount);
            // Wait until loaded AND screen shown minimum time
            if (op.progress >= 0.9f && t >= minLoadingScreenTime)
                op.allowSceneActivation = true;

            yield return null;
        }

        // After activation, sceneLoaded callback will set Playing for levels
        if (forceState.HasValue)
            SetState(forceState.Value);

        HideLoading();
        loadRoutine = null;
        isLoading = false;
    }

    private void ShowLoading()
    {
        if (loadingCanvas == null) return;
        loadingCanvas.alpha = 1f;
        loadingCanvas.blocksRaycasts = true;
        loadingCanvas.interactable = true;
        if (loadingProgressBarFill != null) loadingProgressBarFill.fillAmount = 0f;
    }

    private void HideLoading()
    {
        if (loadingCanvas == null) return;
        loadingCanvas.alpha = 0f;
        loadingCanvas.blocksRaycasts = false;
        loadingCanvas.interactable = false;
    }

    private void HideLoadingImmediate() => HideLoading();

    public void GameOver()
    {
        Time.timeScale = 0f;
        SetState(GameState.GameOver);
    }

    public void Victory()
    {
        Time.timeScale = 0f;
        SetState(GameState.Victory);
    }
    
    public void ExitGame()
    {
        #if UNITY_EDITOR
                UnityEditor.EditorApplication.isPlaying = false;
        #else
                Application.Quit();
        #endif
    }
    //Internal 

    private void SetState(GameState newState)
    {
        if (CurrentState == newState)
        {
            return;
        }

        CurrentState = newState;
        OnGameStateChanged?.Invoke(newState);
    }
}
