using Microsoft.Xna.Framework;
using Theriapolis.Core.Data;
using Theriapolis.Game.CodexUI.Core;
using Theriapolis.Game.CodexUI.Screens;
using Theriapolis.Game.CodexUI.Widgets;
using Theriapolis.Game.UI;

namespace Theriapolis.Game.CodexUI.Steps;

/// <summary>
/// Step III — Calling. Two-column grid of class cards. Cards recommended
/// for the chosen clade get a small "★ Suits Clade" badge. Level-1
/// features render as inline trait chips with hover popovers.
/// </summary>
public static class StepClass
{
    public static CodexWidget Build(CodexCharacterCreationScreen s, CodexAtlas atlas, CodexHoverPopover popover)
    {
        var col = new Column { Spacing = 14 };
        col.Add(StepCommon.PageIntro(
            "Folio III — Of Vocations",
            "Choose your Calling",
            "Eight callings exist within the Covenant. Each shapes how you fight, treat, parley, or unmake the world."));

        var grid = new Grid { Columns = 2 };
        foreach (var c in s.Classes) grid.Add(BuildCard(s, atlas, popover, c));
        col.Add(grid);
        return col;
    }

    private static CodexWidget BuildCard(CodexCharacterCreationScreen s, CodexAtlas atlas, CodexHoverPopover popover, ClassDef c)
    {
        var content = new Column { Spacing = 8 };

        var titleRow = new Row { Spacing = 8, VAlignChildren = VAlign.Middle };
        titleRow.Add(new CodexLabel(c.Name, CodexFonts.DisplayMedium, CodexColors.Ink));
        bool suits = s.Clade is not null && CodexCopy.IsSuited(c.Id, s.Clade.Id);
        if (suits) titleRow.Add(new RecBadge(atlas));
        content.Add(titleRow);

        content.Add(new CodexLabel(
            $"D{c.HitDie} · PRIMARY {string.Join("/", c.PrimaryAbility)} · SAVES {string.Join("/", c.Saves)}",
            CodexFonts.MonoTagSmall, CodexColors.InkMute));

        // Level-1 features as trait chips
        var lvl1 = System.Array.Find(c.LevelTable, e => e.Level == 1);
        if (lvl1 is not null)
        {
            var chips = new WrapRow();
            foreach (var k in lvl1.Features)
            {
                if (k == "asi" || k == "subclass_select" || k == "subclass_feature") continue;
                if (!c.FeatureDefinitions.TryGetValue(k, out var fd)) continue;
                chips.Add(new HoverableChip(atlas, popover, fd.Name, fd.Name, fd.Description, fd.Kind?.ToUpperInvariant(), ChipKind.Trait));
            }
            content.Add(chips);
        }

        content.Add(new CodexLabel(
            $"PICKS {c.SkillsChoose} SKILL{(c.SkillsChoose > 1 ? "S" : "")} · ARMOR: {string.Join(", ", c.ArmorProficiencies)}",
            CodexFonts.MonoTagSmall, CodexColors.InkMute));

        return new CodexCard(atlas, content, s.Class == c,
            onClick: () =>
            {
                // If switching class, drop any previously-picked skills
                // that aren't on the new class's option list — but never
                // auto-pick. The Sign step must stay locked until the
                // user explicitly visits the Skills folio.
                if (s.Class != c)
                {
                    s.Class = c;
                    var allowed = new System.Collections.Generic.HashSet<string>(c.SkillOptions, System.StringComparer.OrdinalIgnoreCase);
                    var bgLocked = new System.Collections.Generic.HashSet<string>(
                        s.Background?.SkillProficiencies ?? System.Array.Empty<string>(),
                        System.StringComparer.OrdinalIgnoreCase);
                    s.ChosenSkills.RemoveWhere(sk =>
                    {
                        string raw = sk.ToString().ToLowerInvariant();
                        return !allowed.Contains(raw) || bgLocked.Contains(raw);
                    });
                }
                s.InvalidateLayout();
            });
    }
}

internal sealed class RecBadge : CodexWidget
{
    private readonly CodexAtlas _atlas;
    private readonly FontStashSharp.SpriteFontBase _font = CodexFonts.MonoTagSmall;
    private const string Text = "★ SUITS CLADE";

    public RecBadge(CodexAtlas atlas) { _atlas = atlas; }

    protected override Point MeasureCore(Point available)
    {
        var s = _font.MeasureString(Text);
        return new Point((int)s.X + 12, (int)System.MathF.Ceiling(_font.LineHeight) + 6);
    }
    protected override void ArrangeCore(Microsoft.Xna.Framework.Rectangle bounds) { }

    public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch sb, Microsoft.Xna.Framework.GameTime gt)
    {
        var fill = new Microsoft.Xna.Framework.Color(CodexColors.Gild.R, CodexColors.Gild.G, CodexColors.Gild.B, (byte)20);
        sb.Draw(_atlas.Pixel, Bounds, fill);
        sb.Draw(_atlas.Pixel, new Microsoft.Xna.Framework.Rectangle(Bounds.X, Bounds.Y, Bounds.Width, 1), CodexColors.Gild);
        sb.Draw(_atlas.Pixel, new Microsoft.Xna.Framework.Rectangle(Bounds.X, Bounds.Bottom - 1, Bounds.Width, 1), CodexColors.Gild);
        sb.Draw(_atlas.Pixel, new Microsoft.Xna.Framework.Rectangle(Bounds.X, Bounds.Y, 1, Bounds.Height), CodexColors.Gild);
        sb.Draw(_atlas.Pixel, new Microsoft.Xna.Framework.Rectangle(Bounds.Right - 1, Bounds.Y, 1, Bounds.Height), CodexColors.Gild);
        var s = _font.MeasureString(Text);
        _font.DrawText(sb, Text,
                       new Microsoft.Xna.Framework.Vector2(Bounds.X + (Bounds.Width - s.X) / 2f,
                                                          Bounds.Y + (Bounds.Height - _font.LineHeight) / 2f),
                       CodexColors.Gild);
    }
}
