using JamRoulette;
using UnityEngine;

/// <summary>
/// A starting point for a Jam Roulette microgame. Drop it on any GameObject in your
/// first scene and press Play: it runs a full round on its own in the editor, with
/// placeholder Win/Lose buttons standing in for gameplay.
///
/// To make it yours, fill in the settings in the Inspector, then replace the bodies
/// of the methods marked TODO. Every SDK hook is wired up here; delete the ones you
/// don't need.
/// </summary>
public class MicrogameTemplate : MonoBehaviour
{
    [Header("Shown on the wrapper's splash")]
    [Tooltip("The one-line instruction shown huge on the splash, e.g. \"Dodge!\"")]
    [SerializeField] private string prompt = "Do the thing!";

    [Tooltip("mouse, click, keyboard, arrows, wasd, space, touch, gamepad, or any short label")]
    [SerializeField] private string interaction = "mouse";

    [Header("Round rules")]
    [Tooltip("Round length in seconds. Clamped to 5–10.")]
    [Range(5f, 10f)]
    [SerializeField] private float gameTime = 5f;

    [Tooltip("Does surviving to the buzzer count as a win? If false, running out of time loses.")]
    [SerializeField] private bool winOnTimeOut;

    [Header("Placeholder UI")]
    [Tooltip("Draws the debug overlay and Win/Lose buttons. Turn off once you have real gameplay.")]
    [SerializeField] private bool showPlaceholder = true;

    private enum Phase { Booting, Waiting, Playing, Ended }

    private Phase _phase = Phase.Booting;
    private float _timeLeft;
    private string _status = "Booting…";

    private void Awake()
    {
        // Subscribe before Register, so no event is missed.
        Microgame.SplashShown += OnSplashShown;
        Microgame.LoadingEnded += OnLoadingEnded;
        Microgame.CountdownStarted += OnCountdownStarted;
        Microgame.CountdownEnded += OnCountdownEnded;
        Microgame.GameStarted += OnGameStarted;
        Microgame.GameUpdated += OnGameUpdated;
        Microgame.GameEnded += OnGameEnded;
    }

    private void OnDestroy()
    {
        // The events are static, so they outlive this object.
        Microgame.SplashShown -= OnSplashShown;
        Microgame.LoadingEnded -= OnLoadingEnded;
        Microgame.CountdownStarted -= OnCountdownStarted;
        Microgame.CountdownEnded -= OnCountdownEnded;
        Microgame.GameStarted -= OnGameStarted;
        Microgame.GameUpdated -= OnGameUpdated;
        Microgame.GameEnded -= OnGameEnded;
    }

    private void Start()
    {
        // TODO: load anything slow here (Addressables, procedural levels…) and only
        // call Register once it's ready. The wrapper boots you hidden while the previous
        // game is still playing, so take your time, but don't start gameplay yet.
        SetUpLevel();

        Microgame.Register(prompt, interaction, gameTime, winOnTimeOut);
        _phase = Phase.Waiting;
        _status = "Registered, waiting for gameStart";
    }

    // ── Your game ────────────────────────────────────────────────────────────────

    /// <summary>Build the level in its starting state. The player can't see it yet.</summary>
    private void SetUpLevel()
    {
        // TODO: spawn the player, place obstacles, pick a random target…
    }

    /// <summary>Gameplay begins: unfreeze everything and accept input.</summary>
    private void BeginPlay()
    {
        // TODO: enable player input, start enemies moving, play music…
    }

    /// <summary>Gameplay is over: stop everything where it is. The result shows for 1s.</summary>
    private void Freeze(GameOverCondition? condition)
    {
        // TODO: disable input, stop movement, play a win or lose sting…
    }

    /// <summary>Call this from gameplay when the player has done what the prompt asked.</summary>
    public void PlayerWon()
    {
        if (!Microgame.IsPlaying) return;
        // false: the round runs on to the timer, so the player still sees their win.
        // Pass true to end the round right away instead.
        Microgame.SetGameState(GameOverCondition.Win, immediatelyEnd: false);
    }

    /// <summary>Call this from gameplay when the player has failed.</summary>
    public void PlayerLost()
    {
        if (!Microgame.IsPlaying) return;
        // true: there's nothing left to do, so cut straight to the result.
        // With false you could still overturn it; the last call before the buzzer wins.
        Microgame.SetGameState(GameOverCondition.Lose, immediatelyEnd: true);
    }

    // Errors are handled for you: any Debug.LogError or uncaught exception ends the
    // round as GameOverCondition.Error, so the wrapper moves on instead of hanging.

    // ── SDK events ───────────────────────────────────────────────────────────────

    // Only fires inside the wrapper. title is your game's name from the jam page.
    private void OnSplashShown(Microgame.SplashInfo info)
    {
        _status = $"Splash: {info.title} — \"{info.prompt}\" ({info.interaction}, {info.gameTime}s)";
    }

    // Only fires inside the wrapper. You're still hidden behind the splash.
    private void OnLoadingEnded()
    {
        _status = "Loading screen gone";
    }

    // Only fires inside the wrapper. Good moment to start music or warm up effects.
    private void OnCountdownStarted()
    {
        _status = "3… 2… 1…";
    }

    // Only fires inside the wrapper. gameStart follows immediately.
    private void OnCountdownEnded()
    {
        _status = "Go!";
    }

    private void OnGameStarted(float roundLength)
    {
        _phase = Phase.Playing;
        _timeLeft = roundLength;
        _status = "Playing";
        BeginPlay();
    }

    // Every frame of the round. Drive a timer bar, speed up as time runs out…
    private void OnGameUpdated(float timeLeft)
    {
        _timeLeft = timeLeft;
    }

    // condition is null when the player skipped.
    private void OnGameEnded(GameOverCondition? condition)
    {
        _phase = Phase.Ended;
        _status = condition.HasValue ? $"Round over: {condition.Value}" : "Skipped";
        Freeze(condition);
    }

    // ── Placeholder UI (delete once you have real gameplay) ──────────────────────

    // IMGUI works with both the old Input Manager and the new Input System.
    private void OnGUI()
    {
        if (!showPlaceholder) return;

        GUILayout.BeginArea(new Rect(16, 16, 360, 220), GUI.skin.box);
        GUILayout.Label(Microgame.IsWrapped ? "Inside the wrapper" : "Standalone (no wrapper)");
        GUILayout.Label(_status);
        if (_phase == Phase.Playing) GUILayout.Label($"Time left: {_timeLeft:0.0}s");

        GUI.enabled = _phase == Phase.Playing;
        if (GUILayout.Button("Win (round runs on)")) PlayerWon();
        if (GUILayout.Button("Lose (ends now)")) PlayerLost();
        if (GUILayout.Button("Throw an error")) Debug.LogError("Something broke");
        GUI.enabled = true;
        GUILayout.EndArea();
    }
}
