namespace TeleWave.Domain.Programming.Planning;

/// <summary>
/// Показы, добавленные этим же прогоном. Остывание и потолок повторов считаются по ленте, а она на
/// момент сборки входа содержит только прошлое: горизонт в неделю строится одним прогоном, и без
/// этого счётчика оба правила не видели бы ничего из того, что сами же и поставили.
///
/// Ключ — шоу, как и в снимке из базы: у коллекции остывание общее по всем частям, поэтому элемент
/// спрашивает историю сразу по всем своим шоу.
/// </summary>
public sealed class RunPlayHistory
{
    private readonly Dictionary<Guid, List<DateTimeOffset>> _byShow = [];

    public void Record(Guid showId, DateTimeOffset startsAtUtc)
    {
        if (!_byShow.TryGetValue(showId, out var plays))
            _byShow[showId] = plays = [];

        plays.Add(startsAtUtc);
    }

    /// <summary>Когда элемент последний раз выходил в этом прогоне; null — ещё не выходил.</summary>
    public DateTimeOffset? LastPlayed(PlanningElement element)
    {
        DateTimeOffset? last = null;
        foreach (var showId in ShowsOf(element))
        {
            if (!_byShow.TryGetValue(showId, out var plays) || plays.Count == 0)
                continue;

            var latest = plays.Max();
            if (last is null || latest > last)
                last = latest;
        }

        return last;
    }

    /// <summary>Сколько раз элемент выходил в этом прогоне начиная с момента.</summary>
    public int CountSince(PlanningElement element, DateTimeOffset from)
    {
        var count = 0;
        foreach (var showId in ShowsOf(element))
            if (_byShow.TryGetValue(showId, out var plays))
                count += plays.Count(play => play >= from);

        return count;
    }

    /// <summary>
    /// Шоу элемента берутся из его единиц: у коллекции их столько же, сколько частей, и это ровно
    /// тот набор, по которому историю собирает и оркестратор.
    /// </summary>
    private static IEnumerable<Guid> ShowsOf(PlanningElement element) =>
        element.Units.Select(unit => unit.ShowId).Distinct();
}
