namespace Theriapolis.Core.Rules.Reputation;

/// <summary>
/// Phase 6 M2 — append-only event log surfaced by the reputation screen
/// ("why does so-and-so hate me?"). Bounded to a reasonable tail so the
/// save file stays small even after a 100-hour playthrough.
///
/// Phase 6 M5 layers propagation on top: each entry will be re-walked
/// per game-day to fan out into other settlements with distance/time
/// decay.
/// </summary>
public sealed class RepLedger
{
    public const int MaxEntries = 256;

    private readonly List<RepEvent> _entries = new();
    private int _nextSeq = 1;

    public IReadOnlyList<RepEvent> Entries => _entries;
    public int Count => _entries.Count;

    /// <summary>
    /// Append <paramref name="ev"/> to the ledger. If <see cref="RepEvent.SequenceId"/>
    /// is 0, a fresh monotone id is assigned; otherwise the supplied id
    /// is preserved (used by the save-restore path).
    /// </summary>
    public RepEvent Append(RepEvent ev)
    {
        if (ev.SequenceId == 0)
            ev = ev with { SequenceId = _nextSeq++ };
        else if (ev.SequenceId >= _nextSeq)
            _nextSeq = ev.SequenceId + 1;
        _entries.Add(ev);
        if (_entries.Count > MaxEntries) _entries.RemoveAt(0);
        return ev;
    }

    public void Clear()
    {
        _entries.Clear();
        _nextSeq = 1;
    }

    /// <summary>Largest <see cref="RepEvent.SequenceId"/> issued so far. 0 = empty ledger.</summary>
    public int HighestSequenceId => _nextSeq - 1;

    /// <summary>Most recent N events affecting <paramref name="factionId"/>.</summary>
    public IEnumerable<RepEvent> ForFaction(string factionId, int count = 8)
    {
        int yielded = 0;
        for (int i = _entries.Count - 1; i >= 0 && yielded < count; i--)
        {
            if (string.Equals(_entries[i].FactionId, factionId, System.StringComparison.OrdinalIgnoreCase))
            {
                yielded++;
                yield return _entries[i];
            }
        }
    }

    /// <summary>Most recent N events affecting <paramref name="roleTag"/>.</summary>
    public IEnumerable<RepEvent> ForRole(string roleTag, int count = 8)
    {
        int yielded = 0;
        for (int i = _entries.Count - 1; i >= 0 && yielded < count; i--)
        {
            if (string.Equals(_entries[i].RoleTag, roleTag, System.StringComparison.OrdinalIgnoreCase))
            {
                yielded++;
                yield return _entries[i];
            }
        }
    }
}
