using Theriapolis.Core.Util;

namespace Theriapolis.Core.Entities;

/// <summary>
/// Player actor. Phase 4 keeps the field set deliberately small — just enough
/// to position, save, and reload a single human-controlled character. Stats,
/// inventory, and class data are added in Phase 5.
/// </summary>
public sealed class PlayerActor : Actor
{
    public string Name { get; set; } = "Wanderer";

    /// <summary>Highest settlement tier the player has actually visited (1 = capital).</summary>
    public int HighestTierReached { get; set; } = 5;

    /// <summary>Set of discovered settlement / PoI ids. Drives slot-picker labels and Phase 7+ map UI.</summary>
    public HashSet<int> DiscoveredPoiIds { get; } = new();

    /// <summary>Snapshot used by SaveCodec; mutated by RestoreState.</summary>
    public PlayerActorState CaptureState() => new()
    {
        Id                 = Id,
        Name               = Name,
        PositionX          = Position.X,
        PositionY          = Position.Y,
        FacingAngleRad     = FacingAngleRad,
        SpeedWorldPxPerSec = SpeedWorldPxPerSec,
        HighestTierReached = HighestTierReached,
        DiscoveredPoiIds   = DiscoveredPoiIds.ToArray(),
    };

    public void RestoreState(PlayerActorState s)
    {
        Name               = s.Name;
        Position           = new Vec2(s.PositionX, s.PositionY);
        FacingAngleRad     = s.FacingAngleRad;
        SpeedWorldPxPerSec = s.SpeedWorldPxPerSec;
        HighestTierReached = s.HighestTierReached;
        DiscoveredPoiIds.Clear();
        foreach (int id in s.DiscoveredPoiIds) DiscoveredPoiIds.Add(id);
    }
}

/// <summary>
/// Plain serializable snapshot of a <see cref="PlayerActor"/>.
/// Kept as a struct of primitive fields so the persistence layer doesn't need
/// MessagePack attributes on the live object — keeps Core dependency-free for
/// modules that don't yet care about saves.
/// </summary>
public sealed class PlayerActorState
{
    public int      Id;
    public string   Name = "";
    public float    PositionX;
    public float    PositionY;
    public float    FacingAngleRad;
    public float    SpeedWorldPxPerSec;
    public int      HighestTierReached;
    public int[]    DiscoveredPoiIds = Array.Empty<int>();
}
