using System.Text.Json.Serialization;

namespace Theriapolis.Core.Data;

/// <summary>
/// Immutable class definition loaded from classes.json. Phase 5 reads
/// every field — including the full level table — but only level-1
/// features have runtime effect; higher-level entries are forward-compat
/// scaffolding for the level-up flow shipped in Phase 5.5 / 6.
/// </summary>
public sealed record ClassDef
{
    [JsonPropertyName("id")]
    public string Id { get; init; } = "";

    [JsonPropertyName("name")]
    public string Name { get; init; } = "";

    /// <summary>Hit die size: 6 / 8 / 10 / 12.</summary>
    [JsonPropertyName("hit_die")]
    public int HitDie { get; init; } = 8;

    /// <summary>Primary ability key(s) (STR / DEX / CON / INT / WIS / CHA).</summary>
    [JsonPropertyName("primary_ability")]
    public string[] PrimaryAbility { get; init; } = Array.Empty<string>();

    /// <summary>Saving-throw proficiencies.</summary>
    [JsonPropertyName("saves")]
    public string[] Saves { get; init; } = Array.Empty<string>();

    /// <summary>Armor proficiency tags: "light", "medium", "heavy", "shields".</summary>
    [JsonPropertyName("armor_proficiencies")]
    public string[] ArmorProficiencies { get; init; } = Array.Empty<string>();

    /// <summary>Weapon proficiency tags: "simple", "martial", "natural", or specific item ids.</summary>
    [JsonPropertyName("weapon_proficiencies")]
    public string[] WeaponProficiencies { get; init; } = Array.Empty<string>();

    /// <summary>Tool proficiency tags.</summary>
    [JsonPropertyName("tool_proficiencies")]
    public string[] ToolProficiencies { get; init; } = Array.Empty<string>();

    [JsonPropertyName("skills_choose")]
    public int SkillsChoose { get; init; } = 0;

    [JsonPropertyName("skill_options")]
    public string[] SkillOptions { get; init; } = Array.Empty<string>();

    /// <summary>
    /// Per-level entries. Level 1..20. Phase 5 only consults level 1, but
    /// the full table loads so the level-up flow doesn't need a schema bump.
    /// </summary>
    [JsonPropertyName("level_table")]
    public ClassLevelEntry[] LevelTable { get; init; } = Array.Empty<ClassLevelEntry>();

    /// <summary>Description of each named feature referenced from level_table.</summary>
    [JsonPropertyName("feature_definitions")]
    public Dictionary<string, ClassFeatureDef> FeatureDefinitions { get; init; } = new();

    /// <summary>Allowed subclass ids (cross-reference into subclasses.json).</summary>
    [JsonPropertyName("subclass_ids")]
    public string[] SubclassIds { get; init; } = Array.Empty<string>();

    /// <summary>
    /// Items handed to a level-1 character of this class at creation time.
    /// <see cref="Rules.Character.CharacterBuilder"/> adds each entry to the
    /// inventory and, if <see cref="StartingKitItem.AutoEquip"/> is true,
    /// equips it into <see cref="StartingKitItem.EquipSlot"/>.
    /// </summary>
    [JsonPropertyName("starting_kit")]
    public StartingKitItem[] StartingKit { get; init; } = Array.Empty<StartingKitItem>();
}

/// <summary>
/// One row in <see cref="ClassDef.StartingKit"/>: the item id, quantity, and
/// optional auto-equip target. ItemId must resolve against items.json.
/// </summary>
public sealed record StartingKitItem
{
    [JsonPropertyName("item_id")]
    public string ItemId { get; init; } = "";

    [JsonPropertyName("qty")]
    public int Qty { get; init; } = 1;

    /// <summary>If true, the item is equipped into <see cref="EquipSlot"/> at creation.</summary>
    [JsonPropertyName("auto_equip")]
    public bool AutoEquip { get; init; } = false;

    /// <summary>"main_hand" / "off_hand" / "body" / "helm" / "cloak" / "boots" / "adaptive_pack" / etc.</summary>
    [JsonPropertyName("equip_slot")]
    public string EquipSlot { get; init; } = "";
}

public sealed record ClassLevelEntry
{
    [JsonPropertyName("level")]
    public int Level { get; init; } = 1;

    [JsonPropertyName("prof")]
    public int ProficiencyBonus { get; init; } = 2;

    /// <summary>Feature ids unlocked at this level. Resolves into <see cref="ClassDef.FeatureDefinitions"/>.</summary>
    [JsonPropertyName("features")]
    public string[] Features { get; init; } = Array.Empty<string>();
}

public sealed record ClassFeatureDef
{
    [JsonPropertyName("name")]
    public string Name { get; init; } = "";

    [JsonPropertyName("description")]
    public string Description { get; init; } = "";

    /// <summary>"passive", "active", "choice", "bonus_action", "reaction", "stub".</summary>
    [JsonPropertyName("kind")]
    public string Kind { get; init; } = "passive";

    [JsonPropertyName("uses_per_short_rest")]
    public int? UsesPerShortRest { get; init; }

    [JsonPropertyName("uses_per_long_rest")]
    public int? UsesPerLongRest { get; init; }

    /// <summary>For "choice" features: the available pick ids.</summary>
    [JsonPropertyName("options")]
    public string[]? Options { get; init; }
}
