namespace Theriapolis.Core.Persistence;

/// <summary>
/// Plain-data snapshot of a <see cref="Rules.Character.Character"/> for
/// the save layer. Kept as primitive fields + arrays so the persistence
/// codec doesn't pull MessagePack attributes onto the live model.
///
/// Items / equipped slots reference content by id (string); the loader
/// re-resolves them against the current <see cref="Data.ItemDef"/> set
/// after world content reloads.
/// </summary>
public sealed class PlayerCharacterState
{
    public string CladeId      { get; set; } = "";
    public string SpeciesId    { get; set; } = "";
    public string ClassId      { get; set; } = "";
    public string BackgroundId { get; set; } = "";

    // Final ability scores (post clade + species mods).
    public byte STR { get; set; }
    public byte DEX { get; set; }
    public byte CON { get; set; }
    public byte INT { get; set; }
    public byte WIS { get; set; }
    public byte CHA { get; set; }

    public int Level     { get; set; } = 1;
    public int Xp        { get; set; } = 0;
    public int MaxHp     { get; set; }
    public int CurrentHp { get; set; }
    public int ExhaustionLevel { get; set; } = 0;

    // Phase 5 M6 additions — backward-compat handled by EndOfStream check in SaveCodec.ReadCharacter.
    public string FightingStyle     { get; set; } = "";
    public int    RageUsesRemaining { get; set; } = 2;

    // Phase 6 M3 — coin balance (Fangs are Theriapolis's universal currency).
    public int    CurrencyFang      { get; set; } = 0;

    // Phase 6.5 M0 — levelling state.
    /// <summary>
    /// Subclass id chosen at level 3 (or whatever
    /// <see cref="C.SUBCLASS_SELECTION_LEVEL"/> is). Empty pre-L3.
    /// </summary>
    public string SubclassId        { get; set; } = "";

    /// <summary>Feature ids learned across all level-ups, in unlock order.</summary>
    public string[] LearnedFeatureIds { get; set; } = Array.Empty<string>();

    /// <summary>Append-only per-level-up history (deltas, not post-state).</summary>
    public LevelUpRecordState[] LevelUpHistory { get; set; } = Array.Empty<LevelUpRecordState>();

    // Phase 6.5 M4 — hybrid-character genealogy. Null for purebred PCs.
    public HybridStateSnapshot? Hybrid { get; set; }

    /// <summary>Skill ids stored as enum byte values for compactness.</summary>
    public byte[] SkillProficiencies { get; set; } = Array.Empty<byte>();

    /// <summary>Active conditions stored as enum byte values.</summary>
    public byte[] Conditions { get; set; } = Array.Empty<byte>();

    /// <summary>Inventory stacks — references to ItemDef.Id with quantity + condition + optional equip slot.</summary>
    public InventoryItemState[] Inventory { get; set; } = Array.Empty<InventoryItemState>();
}

/// <summary>
/// Phase 6.5 M0 — one entry in <see cref="PlayerCharacterState.LevelUpHistory"/>.
/// Plain-data round-trip of <see cref="Rules.Character.LevelUpRecord"/>.
/// </summary>
public sealed class LevelUpRecordState
{
    public int Level { get; set; }
    public int HpGained { get; set; }
    public bool HpWasAveraged { get; set; }
    public int HpHitDieResult { get; set; }
    /// <summary>Empty when no subclass was chosen at this level (i.e. anything but L3).</summary>
    public string SubclassChosen { get; set; } = "";
    /// <summary>ASI ability ids stored as enum byte values; same length as <see cref="AsiValues"/>.</summary>
    public byte[] AsiKeys { get; set; } = Array.Empty<byte>();
    public int[]  AsiValues { get; set; } = Array.Empty<int>();
    public string[] FeaturesUnlocked { get; set; } = Array.Empty<string>();
}

/// <summary>
/// Phase 6.5 M4 — flat round-trip record for <see cref="Rules.Character.HybridState"/>.
/// </summary>
public sealed class HybridStateSnapshot
{
    public string SireClade   { get; set; } = "";
    public string SireSpecies { get; set; } = "";
    public string DamClade    { get; set; } = "";
    public string DamSpecies  { get; set; } = "";
    /// <summary>0 = Sire, 1 = Dam (matches <see cref="Rules.Character.ParentLineage"/> byte values).</summary>
    public byte   DominantParent { get; set; } = 0;
    public bool   PassingActive  { get; set; } = false;
    /// <summary>Per-NPC discovery list — populated in Phase 6.5 M5.</summary>
    public int[]  NpcsWhoKnow    { get; set; } = Array.Empty<int>();
    /// <summary>Active scent-mask tier (Phase 6.5 M5). 0 = none.</summary>
    public byte   ActiveMaskTier { get; set; } = 0;
}

/// <summary>One stack in <see cref="PlayerCharacterState.Inventory"/>.</summary>
public sealed class InventoryItemState
{
    public string ItemId    { get; set; } = "";
    public int    Qty       { get; set; } = 1;
    public int    Condition { get; set; } = 100;
    /// <summary>Null if this stack is bagged. Otherwise the EquipSlot enum byte value.</summary>
    public byte?  EquippedAt { get; set; }
}
