using Theriapolis.Core.Data;

namespace Theriapolis.Core.Rules.Reputation;

/// <summary>
/// Phase 6 M2 — top-level aggregate of every reputation track owned by
/// the player. Hangs off PlayScreen as a parallel-to-Character record
/// (deliberate separation: <c>Character</c> is what the player is,
/// <c>PlayerReputation</c> is what the world thinks of them).
///
/// Round-trips through <see cref="Persistence.ReputationSnapshot"/>.
/// </summary>
public sealed class PlayerReputation
{
    public FactionStanding Factions { get; } = new();
    public Dictionary<string, PersonalDisposition> Personal { get; } = new(System.StringComparer.OrdinalIgnoreCase);
    public RepLedger Ledger { get; } = new();

    /// <summary>Get-or-create the per-NPC personal disposition record for <paramref name="roleTag"/>.</summary>
    public PersonalDisposition PersonalFor(string roleTag)
    {
        if (!Personal.TryGetValue(roleTag, out var p))
        {
            p = new PersonalDisposition { RoleTag = roleTag };
            Personal[roleTag] = p;
        }
        return p;
    }

    /// <summary>
    /// Submit a reputation event. Updates faction standing (with opposition
    /// cascade), the addressed NPC's personal disposition, and the ledger.
    /// </summary>
    public void Submit(RepEvent ev, IReadOnlyDictionary<string, FactionDef> factions)
    {
        if (!string.IsNullOrEmpty(ev.FactionId) && ev.Magnitude != 0)
            Factions.Apply(ev.FactionId, ev.Magnitude, factions);

        if (!string.IsNullOrEmpty(ev.RoleTag))
            PersonalFor(ev.RoleTag).Apply(ev);

        Ledger.Append(ev);
    }
}
