using FontStashSharp;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Theriapolis.Game.CodexUI.Core;

namespace Theriapolis.Game.CodexUI.Widgets;

/// <summary>
/// Selectable card. The clade / species / class / background pickers each
/// render a grid of these. Visual states track the React design:
///   - Default: rule-coloured 1-px border, parchment fill.
///   - Hover:   gilded border, subtle gild halo overlay.
///   - Selected: seal-red border + inner glow + corner wax-seal accent.
///
/// Click toggles selection by calling <see cref="OnClick"/>; the parent step
/// owns the "what is selected" state and rebuilds. The card's content tree
/// is whatever <see cref="Content"/> child is supplied — typically a small
/// Column with name + meta + chips.
/// </summary>
public sealed class CodexCard : CodexWidget
{
    public CodexWidget? Content { get; set; }
    public bool IsSelected { get; set; }
    public System.Action? OnClick { get; set; }
    public Texture2D? CornerSigil { get; set; }
    public string? CornerLetter { get; set; }   // overlay glyph drawn on the sigil placeholder

    private readonly CodexAtlas _atlas;
    private bool _hovered;
    private const int Pad = CodexDensity.CardPad;

    public CodexCard(CodexAtlas atlas, CodexWidget? content = null, bool selected = false, System.Action? onClick = null)
    {
        _atlas = atlas;
        Content = content;
        if (content is not null) content.Parent = this;
        IsSelected = selected;
        OnClick = onClick;
    }

    protected override Point MeasureCore(Point available)
    {
        if (Content is null) return new Point(System.Math.Min(CodexDensity.CardWidth, available.X), 80);
        var inner = new Point(available.X - Pad * 2, available.Y - Pad * 2);
        var s = Content.Measure(inner);
        return new Point(s.X + Pad * 2, s.Y + Pad * 2);
    }

    protected override void ArrangeCore(Rectangle bounds)
    {
        Content?.Arrange(new Rectangle(
            bounds.X + Pad, bounds.Y + Pad,
            bounds.Width  - Pad * 2,
            bounds.Height - Pad * 2));
    }

    public override void Update(GameTime gt, CodexInput input)
    {
        _hovered = ContainsPoint(input.MousePosition);
        if (_hovered && input.LeftJustReleased) OnClick?.Invoke();
        Content?.Update(gt, input);
    }

    public override void Draw(SpriteBatch sb, GameTime gt)
    {
        // Body fill — parchment shade
        sb.Draw(_atlas.Pixel, Bounds, CodexColors.Bg2);
        // Subtle top-down lift overlay (2-px gradient strip) to match `linear-gradient(180deg, rgba(255,250,235,0.05), transparent 30%)`.
        sb.Draw(_atlas.Pixel, new Rectangle(Bounds.X, Bounds.Y, Bounds.Width, 2), new Color(255, 250, 235, 18));

        // Border colour by state.
        Color border = IsSelected ? CodexColors.Seal : (_hovered ? CodexColors.Gild : CodexColors.Rule);
        int thickness = IsSelected ? 2 : 1;
        DrawBorder(sb, Bounds, border, thickness);

        if (IsSelected)
        {
            // Inner glow strip — 1px inside the border.
            DrawBorder(sb, new Rectangle(Bounds.X + thickness, Bounds.Y + thickness, Bounds.Width - thickness * 2, Bounds.Height - thickness * 2),
                       new Color(border.R, border.G, border.B, (byte)40), 1);
            // Corner wax-seal accent
            int sealSize = 28;
            sb.Draw(_atlas.WaxSeal, new Rectangle(Bounds.Right - sealSize / 2 - 4, Bounds.Y - sealSize / 2 + 4, sealSize, sealSize), Color.White);
        }
        else if (_hovered)
        {
            sb.Draw(_atlas.Pixel, Bounds, new Color(CodexColors.Gild.R, CodexColors.Gild.G, CodexColors.Gild.B, (byte)10));
        }

        Content?.Draw(sb, gt);
    }

    private void DrawBorder(SpriteBatch sb, Rectangle r, Color c, int t)
    {
        sb.Draw(_atlas.Pixel, new Rectangle(r.X, r.Y, r.Width, t), c);
        sb.Draw(_atlas.Pixel, new Rectangle(r.X, r.Bottom - t, r.Width, t), c);
        sb.Draw(_atlas.Pixel, new Rectangle(r.X, r.Y, t, r.Height), c);
        sb.Draw(_atlas.Pixel, new Rectangle(r.Right - t, r.Y, t, r.Height), c);
    }
}

/// <summary>
/// 7-step horizontal stepper at the top of the wizard. Each step exposes a
/// locked / active / complete state with the matching marker (✕ / Roman /
/// ✓). Clicking a non-locked step navigates there.
/// </summary>
public sealed class CodexStepper : CodexWidget
{
    public string[] Names { get; }
    public int Current { get; set; }
    public bool[] Complete { get; set; }
    public bool[] Locked { get; set; }
    public System.Action<int>? OnPick { get; set; }

    private readonly CodexAtlas _atlas;
    private readonly SpriteFontBase _romanFont = CodexFonts.DisplayMedium;
    private readonly SpriteFontBase _labelFont = CodexFonts.MonoTagSmall;

    public CodexStepper(string[] names, CodexAtlas atlas)
    {
        Names = names;
        Complete = new bool[names.Length];
        Locked = new bool[names.Length];
        _atlas = atlas;
    }

    protected override Point MeasureCore(Point available) => new(available.X, 64);
    protected override void ArrangeCore(Rectangle bounds) { }

    private static readonly string[] Roman = new[] { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };

    public override void Update(GameTime gt, CodexInput input)
    {
        if (!input.LeftJustReleased) return;
        int colW = Bounds.Width / Names.Length;
        for (int i = 0; i < Names.Length; i++)
        {
            var cell = new Rectangle(Bounds.X + i * colW, Bounds.Y, colW, Bounds.Height);
            if (cell.Contains(input.MousePosition) && !Locked[i] && i != Current) { OnPick?.Invoke(i); return; }
        }
    }

    public override void Draw(SpriteBatch sb, GameTime gt)
    {
        // Opaque parchment background so the stepper masks any body
        // scroll-overflow that drew under it.
        sb.Draw(_atlas.Pixel, Bounds, CodexColors.Bg);
        // Top + bottom rule
        sb.Draw(_atlas.Pixel, new Rectangle(Bounds.X, Bounds.Y, Bounds.Width, 1), CodexColors.Rule);
        sb.Draw(_atlas.Pixel, new Rectangle(Bounds.X, Bounds.Bottom - 1, Bounds.Width, 1), CodexColors.Rule);
        sb.Draw(_atlas.Pixel, Bounds, new Color(0, 0, 0, 6));

        int colW = Bounds.Width / Names.Length;
        for (int i = 0; i < Names.Length; i++)
        {
            var cell = new Rectangle(Bounds.X + i * colW, Bounds.Y, colW, Bounds.Height);
            // Vertical separator between cells.
            if (i < Names.Length - 1)
                sb.Draw(_atlas.Pixel, new Rectangle(cell.Right - 1, cell.Y + 4, 1, cell.Height - 8),
                        new Color(CodexColors.Rule.R, CodexColors.Rule.G, CodexColors.Rule.B, (byte)128));

            bool isCurrent = i == Current;
            bool isComplete = Complete[i] && !isCurrent;
            bool isLocked = Locked[i];
            // Numeral / mark
            string mark = isLocked ? "✕" : (isComplete ? "✓" : Roman[i]);
            Color numColor = isLocked ? CodexColors.InkMute
                            : isComplete ? CodexColors.Seal
                            : isCurrent ? CodexColors.Ink
                            : CodexColors.InkMute;

            var ms = _romanFont.MeasureString(mark);
            float numX = cell.X + (cell.Width - ms.X) / 2f;
            float numY = cell.Y + 12;
            _romanFont.DrawText(sb, mark, new Vector2(numX, numY), numColor);

            // Step name
            var ls = _labelFont.MeasureString(Names[i]);
            float lx = cell.X + (cell.Width - ls.X) / 2f;
            float ly = cell.Y + cell.Height - _labelFont.LineHeight - 8;
            Color labelColor = isLocked ? new Color(CodexColors.InkMute.R, CodexColors.InkMute.G, CodexColors.InkMute.B, (byte)115)
                              : isCurrent ? CodexColors.Ink : CodexColors.InkMute;
            _labelFont.DrawText(sb, Names[i].ToUpperInvariant(), new Vector2(lx, ly), labelColor);

            if (isCurrent)
                sb.Draw(_atlas.Pixel, new Rectangle((int)(cell.X + cell.Width * 0.14f), cell.Bottom - 2, (int)(cell.Width * 0.72f), 2), CodexColors.Gild);
        }
    }
}
