using Theriapolis.Core.Rules.Character;
using Theriapolis.Core.Util;

namespace Theriapolis.Core.Entities;

/// <summary>
/// Base actor record. Position is in world-pixel space and is meaningful in
/// both the world-map view and the tactical view (see Section 5 of the
/// implementation plan — one canonical coordinate system).
///
/// Phase 5 adds the optional <see cref="Character"/> attachment carrying all
/// gameplay state (stats, inventory, HP, conditions). The renderer layer
/// stays ignorant of the gameplay layer — Camera2D doesn't need to know HP.
/// </summary>
public class Actor
{
    /// <summary>Stable id assigned by <see cref="ActorManager"/>.</summary>
    public int Id { get; init; }

    /// <summary>World-pixel position. Reused at both zoom scales.</summary>
    public Vec2 Position { get; set; }

    /// <summary>Facing angle in radians (0 = east, π/2 = south).</summary>
    public float FacingAngleRad { get; set; }

    /// <summary>Continuous-time travel speed on the world map, in world pixels per real second.</summary>
    public float SpeedWorldPxPerSec { get; set; } = C.PLAYER_TRAVEL_PX_PER_SEC;

    /// <summary>
    /// Phase 5: gameplay state. Null when this actor isn't combat-capable
    /// (cosmetic NPCs, future-phase additions). PlayerActor and NpcActor
    /// always carry one.
    /// </summary>
    public Character? Character { get; set; }

    /// <summary>Whose side this actor is on. Drives encounter triggering and AI targeting.</summary>
    public Allegiance Allegiance { get; set; } = Allegiance.Neutral;

    /// <summary>
    /// True if this actor still has positive HP (or is downed but not dead).
    /// Subclasses (e.g. <see cref="NpcActor"/>) override to use direct HP
    /// fields instead of a <see cref="Character"/> reference.
    /// </summary>
    public virtual bool IsAlive => Character is null ? true : Character.IsAlive;
}
