using Godot;
using Godot.Collections;
using Mr.BrickAdventures.scripts.components;

namespace Mr.BrickAdventures.Autoloads;

/// <summary>
/// Game orchestrator - handles scene transitions and game flow.
/// State lives in GameStateStore; query it directly for reads/writes.
/// </summary>
public partial class GameManager : Node
{
    [Export] public Array<PackedScene> LevelScenes { get; set; } = [];

    public PlayerController Player
    {
        get => GetPlayer();
        private set => _player = value;
    }

    private PlayerController _player;
    private SpeedRunManager SpeedRunManager => SpeedRunManager.Instance;
    private GameStateStore Store => GameStateStore.Instance;

    public static GameManager Instance { get; private set; }

    public override void _Ready()
    {
        Instance = this;
        EventBus.Instance.PlayerSpawned += OnPlayerSpawned;
    }

    public override void _ExitTree()
    {
        if (Instance == this) Instance = null;
        if (EventBus.Instance != null)
            EventBus.Instance.PlayerSpawned -= OnPlayerSpawned;
    }

    private void OnPlayerSpawned(PlayerController player)
    {
        _player = player;
        player.TreeExiting += () => { if (_player == player) _player = null; };
    }

    #region Game Flow

    public void StartNewGame()
    {
        Store?.ResetAll();
        SpeedRunManager?.StartTimer();
        GetTree().ChangeSceneToPacked(LevelScenes[0]);
        SaveSystem.Instance.SaveGame();
        EventBus.EmitGameStarted();
    }

    public void ContinueGame()
    {
        var save = SaveSystem.Instance;
        if (!save.LoadGame())
        {
            GD.PrintErr("Failed to load game. Starting a new game instead.");
            StartNewGame();
            return;
        }

        var idx = Store?.Player.CurrentLevel ?? 0;
        if (idx < LevelScenes.Count)
        {
            GetTree().ChangeSceneToPacked(LevelScenes[idx]);
            EventBus.EmitGameContinued();
        }
        else
        {
            GD.PrintErr("No levels unlocked to continue.");
        }
    }

    public void RestartGame()
    {
        Store?.ResetAll();
        GetTree().ChangeSceneToPacked(LevelScenes[0]);
        SaveSystem.Instance.SaveGame();
    }

    public void OnLevelComplete()
    {
        if (Store == null) return;

        var levelIndex = Store.Player.CurrentLevel;
        Store.MarkLevelComplete(levelIndex);
        Store.CommitSessionCoins();
        Store.CommitSessionSkills();

        var completionTime = SpeedRunManager?.GetCurrentLevelTime() ?? 0.0;
        EventBus.EmitLevelCompleted(levelIndex, GetTree().CurrentScene, completionTime);

        Store.ResetSession();
        TryToGoToNextLevel();
        SaveSystem.Instance.SaveGame();
    }

    public void TryToGoToNextLevel()
    {
        if (Store == null) return;

        var next = Store.Player.CurrentLevel + 1;
        if (next < LevelScenes.Count && Store.IsLevelUnlocked(next))
        {
            Store.Player.CurrentLevel = next;
            GetTree().ChangeSceneToPacked(LevelScenes[next]);
            EventBus.EmitLevelStarted(next, GetTree().CurrentScene);
        }
    }

    public void PauseGame()
    {
        Engine.TimeScale = 0;
        EventBus.EmitGamePaused();
    }

    public void ResumeGame()
    {
        Engine.TimeScale = 1;
        EventBus.EmitGameResumed();
    }

    public void QuitGame() => GetTree().Quit();

    #endregion

    #region Player Lookup

    public PlayerController GetPlayer()
    {
        if (_player != null && IsInstanceValid(_player)) return _player;
        _player = null;
        return null;
    }

    #endregion
}
