using Godot;
using ReactorMaintenance.Godot.Data;
using ReactorMaintenance.Godot.Screens;

namespace ReactorMaintenance.Godot;

public partial class AppController : Control
{
    public override void _Ready()
    {
        ShowSplash();
    }

    public void ShowSplash()
    {
        ShowScreen<SplashScreen>("res://Scenes/SplashScreen.tscn", screen => screen.Started += ShowMainMenu);
    }

    public void ShowMainMenu()
    {
        ShowScreen<MainMenu>("res://Scenes/MainMenu.tscn", screen => screen.Configure(this, m_Session.HasContinue));
    }

    public void StartNewCampaign()
    {
        m_Session.StartNewCampaign();
        ShowCampaignIntro();
    }

    public void ContinueCampaign()
    {
        m_Session.ContinueCampaign();
        LoadCurrentLevel();
    }

    public void StartRandomLevel()
    {
        m_Session.StartRandomLevel();
        ShowScreen<GenerationScreen>("res://Scenes/GenerationScreen.tscn", screen => screen.Configure(this, m_Session.CurrentLevel));
    }

    public void ShowCampaignIntro()
    {
        ShowScreen<CampaignIntro>("res://Scenes/CampaignIntro.tscn", screen => screen.Configure(this, m_Session.CurrentLevel, m_Session.LevelNumber, m_Session.LevelCount));
    }

    public void LoadCurrentLevel()
    {
        m_Session.MarkCurrentLevelLoaded();
        ShowScreen<LevelScreen>("res://Scenes/LevelScreen.tscn", screen => screen.Configure(this, m_Session.CurrentLevel, m_Session.LevelNumber, m_Session.LevelCount));
    }

    public void RetryCurrentLevel()
    {
        LoadCurrentLevel();
    }

    public void CompleteCurrentLevel()
    {
        if (m_Session.IsRandomLevel)
        {
            StartRandomLevel();
            return;
        }

        if (m_Session.HasNextLevel)
        {
            m_Session.AdvanceToNextLevel();
            ShowCampaignIntro();
            return;
        }

        m_Session.CompleteCampaign();
        ShowGameWon();
    }

    public void ShowOptions()
    {
        ShowScreen<OptionsScreen>("res://Scenes/OptionsScreen.tscn", screen => screen.Configure(this));
    }

    public void ShowTutorial()
    {
        ShowScreen<TutorialScreen>("res://Scenes/TutorialScreen.tscn", screen => screen.Configure(this));
    }

    public void ShowGameOver()
    {
        ShowScreen<GameOverScreen>("res://Scenes/GameOverScreen.tscn", screen => screen.Configure(this, m_Session.CurrentLevel));
    }

    private void ShowGameWon()
    {
        ShowScreen<GameWonScreen>("res://Scenes/GameWonScreen.tscn", screen => screen.Configure(this, m_Session.LevelCount));
    }

    private void ShowScreen<TScreen>(string scenePath, Action<TScreen> configure) where TScreen : Control
    {
        m_CurrentScreen?.QueueFree();

        var packedScene = ResourceLoader.Load<PackedScene>(scenePath);
        var screen = packedScene.Instantiate<TScreen>();
        m_CurrentScreen = screen;
        AddChild(screen);
        configure(screen);
    }

    private readonly FrontendSession m_Session = new(CampaignRepository.LoadDefault());
    private Control? m_CurrentScreen;
}