using Godot;
using Theriapolis.GodotHost.UI;

namespace Theriapolis.GodotHost.Scenes.Steps;

/// <summary>
/// Step VIII — Sign. Direct port of <c>StepReview</c> in
/// <c>src/steps.jsx</c>: name entry plus the Confirm button that
/// composes the final character and emits the handoff signal per
/// GODOT_PORTING_GUIDE.md §11.
///
/// The full per-step review already lives in the Aside summary, so
/// this step focuses on what's new at this stage: the name input
/// and the Confirm action. Bottom of the page mirrors the React
/// prototype — single big primary button.
/// </summary>
public partial class StepReview : VBoxContainer, IStep
{
    /// <summary>Fired when Confirm is pressed and every step validates.
    /// The parent Wizard catches this and persists the draft + advances
    /// the harness; the rest of the game-side handoff lands in a future
    /// milestone (intro scene, world load, etc.).</summary>
    [Signal] public delegate void CharacterConfirmedEventHandler(CharacterDraft draft);

    private CharacterDraft _draft = null!;
    private LineEdit _nameField = null!;
    private Button _confirmBtn = null!;
    private Label _confirmStatus = null!;

    public void Bind(CharacterDraft draft)
    {
        _draft = draft;
        _draft.Changed += () => Callable.From(Refresh).CallDeferred();
        Build();
    }

    public string? Validate() => WizardValidation.Validate(7, _draft);

    private void Build()
    {
        AddThemeConstantOverride("separation", 18);

        var intro = new VBoxContainer();
        intro.AddThemeConstantOverride("separation", 6);
        AddChild(intro);
        intro.AddChild(new Label { Text = "FOLIO VIII · SIGN", ThemeTypeVariation = "Eyebrow" });
        intro.AddChild(new Label { Text = "Sign the Codex",    ThemeTypeVariation = "H2" });
        intro.AddChild(new Label
        {
            Text = "Review the right-rail summary, then sign your name. "
                 + "The name you sign here is the one the world will speak.",
            AutowrapMode = TextServer.AutowrapMode.WordSmart,
        });

        // Name field.
        var nameBlock = new VBoxContainer();
        nameBlock.AddThemeConstantOverride("separation", 6);
        AddChild(nameBlock);
        nameBlock.AddChild(new Label { Text = "NAME", ThemeTypeVariation = "Eyebrow" });
        _nameField = new LineEdit
        {
            PlaceholderText = "Enter your character's name...",
            Text = _draft.CharacterName,
            CustomMinimumSize = new Vector2(360, 0),
        };
        _nameField.TextChanged += OnNameChanged;
        nameBlock.AddChild(_nameField);

        // Confirm action — disabled until every step validates.
        var actionBlock = new VBoxContainer();
        actionBlock.AddThemeConstantOverride("separation", 8);
        AddChild(actionBlock);

        _confirmStatus = new Label
        {
            Text = "",
            AutowrapMode = TextServer.AutowrapMode.WordSmart,
        };
        actionBlock.AddChild(_confirmStatus);

        _confirmBtn = new Button
        {
            Text = "Confirm & Begin",
            CustomMinimumSize = new Vector2(220, 0),
            ThemeTypeVariation = "PrimaryButton",
        };
        _confirmBtn.Pressed += OnConfirmPressed;
        actionBlock.AddChild(_confirmBtn);

        Refresh();
    }

    private void OnNameChanged(string newText)
    {
        // Patch only when the field actually differs from the draft —
        // otherwise the Changed signal would refresh us in a loop.
        if (newText == _draft.CharacterName) return;
        _draft.Patch(new Godot.Collections.Dictionary { { "character_name", newText } });
    }

    private void Refresh()
    {
        if (_nameField is null) return;
        // Sync the field if external state changed without going through
        // the LineEdit (e.g. loading a saved draft someday).
        if (_nameField.Text != _draft.CharacterName)
            _nameField.Text = _draft.CharacterName;

        int firstUnmet = WizardValidation.FirstIncomplete(_draft);
        bool allValid = firstUnmet == -1;
        _confirmBtn.Disabled = !allValid;
        if (allValid)
        {
            _confirmStatus.Text = $"Ready: {_draft.CharacterName} stands at the threshold.";
        }
        else if (firstUnmet == 7)
        {
            _confirmStatus.Text = "Enter a name to sign.";
        }
        else
        {
            _confirmStatus.Text = $"Some folios remain — see Folio {Roman(firstUnmet + 1)}.";
        }
    }

    private void OnConfirmPressed()
    {
        if (WizardValidation.FirstIncomplete(_draft) != -1) return;

        // Persist the draft so a future load path can pick it up.
        const string SavePath = "user://character.tres";
        var err = ResourceSaver.Save(_draft, SavePath);
        if (err != Error.Ok)
            GD.PushWarning($"[review] ResourceSaver.Save failed: {err}");
        else
            GD.Print($"[review] Saved character draft to {SavePath}");

        GD.Print($"[review] Confirmed: {Summarise(_draft)}");

        EmitSignal(SignalName.CharacterConfirmed, _draft);

        _confirmBtn.Disabled = true;
        _confirmStatus.Text = $"{_draft.CharacterName} steps into Theriapolis.";
    }

    private static string Summarise(CharacterDraft d)
    {
        string lineage = d.IsHybrid
            ? $"hybrid {d.SireCladeId}/{d.SireSpeciesId} × {d.DamCladeId}/{d.DamSpeciesId} (dom={d.DominantParent})"
            : $"{d.CladeId}/{d.SpeciesId}";
        return $"{d.CharacterName} — {lineage}, {d.ClassId}/{d.SubclassId}, bg={d.BackgroundId}, "
             + $"skills=[{string.Join(",", d.ChosenSkills)}]";
    }

    private static string Roman(int n) => n switch
    {
        1 => "I",  2 => "II", 3 => "III", 4 => "IV",
        5 => "V",  6 => "VI", 7 => "VII", 8 => "VIII",
        _ => n.ToString(),
    };
}
