using Theriapolis.Core.Entities;
using Theriapolis.Core.Tactical;
using Theriapolis.Core.Time;

namespace Theriapolis.Core.Persistence;

/// <summary>
/// All save-worthy state outside the seed-derivable world. Phase 4 fills the
/// player, clock, chunk deltas, and world-tile deltas; the other fields are
/// reserved for Phase 5/6 so adding them later doesn't require a schema bump.
/// </summary>
public sealed class SaveBody
{
    public PlayerActorState Player { get; set; } = new();
    public WorldClockState  Clock  { get; set; } = new();

    /// <summary>
    /// Phase 5: full character snapshot (clade, species, class, abilities,
    /// HP, inventory). Null on Phase-4 saves; the loader treats null as a
    /// migration-failed signal and refuses the save.
    /// </summary>
    public PlayerCharacterState? PlayerCharacter { get; set; }

    /// <summary>
    /// Phase 5 M5: per-chunk NPC roster delta (which spawn indices have died).
    /// Empty on a fresh save; populated as the player kills NPCs.
    /// </summary>
    public NpcRosterState NpcRoster { get; set; } = new();

    /// <summary>
    /// Phase 5 M5: present only when the player saved mid-combat. On load,
    /// PlayScreen re-creates the encounter from this snapshot and pushes
    /// CombatHUDScreen directly without going through the title.
    /// </summary>
    public EncounterState? ActiveEncounter { get; set; }

    /// <summary>Per-chunk player-modification overlay.</summary>
    public Dictionary<ChunkCoord, ChunkDelta> ModifiedChunks { get; set; } = new();

    /// <summary>Sparse per-world-tile changes (e.g. burned settlement).</summary>
    public List<WorldTileDelta> ModifiedWorldTiles { get; set; } = new();

    // ── Reserved for later phases ────────────────────────────────────────
    // Empty containers so save schema doesn't need a migration when each
    // subsystem comes online.
    public Dictionary<string, int> Flags      { get; set; } = new();
    /// <summary>v5 placeholder. Phase 6 M2 superseded by <see cref="ReputationState"/>.</summary>
    public Dictionary<int, int>    Factions   { get; set; } = new();
    /// <summary>v5 placeholder. Phase 6 M4 superseded by <see cref="QuestEngineState"/>.</summary>
    public List<int>               QuestState { get; set; } = new();
    /// <summary>v5 placeholder. Phase 6 M2 superseded by <see cref="ReputationState"/>.</summary>
    public Dictionary<string, int> Reputation { get; set; } = new();
    public List<int>               DiscoveredPoiIds { get; set; } = new();

    /// <summary>
    /// Phase 6 M2 — full reputation snapshot (faction standings, per-NPC
    /// personal dispositions, recent ledger). Empty on a fresh game; the
    /// V5→V6 migration leaves this empty too (Phase-5 saves never
    /// accumulated rep state).
    /// </summary>
    public ReputationSnapshot ReputationState { get; set; } = new();

    /// <summary>
    /// Phase 6 M4 — quest engine snapshot. Empty before any quest
    /// activates. Named <c>QuestEngineState</c> to avoid colliding with
    /// the v5 placeholder <see cref="QuestState"/> dictionary.
    /// </summary>
    public QuestSnapshot QuestEngineState { get; set; } = new();
}

/// <summary>One world-tile cell that diverged from worldgen baseline.</summary>
public readonly struct WorldTileDelta
{
    public readonly ushort X;
    public readonly ushort Y;
    public readonly byte   NewBiome;
    public readonly ushort NewFeatures;
    public WorldTileDelta(int x, int y, byte biome, ushort features)
    {
        X = (ushort)x; Y = (ushort)y; NewBiome = biome; NewFeatures = features;
    }
}
