using TeleWave.Domain.Library;
using TeleWave.Domain.Programming;

namespace TeleWave.Application.Programming.Templates.Generate;

/// <summary>Архетип сетки. Значения пишутся в запросы клиентом, поэтому переименованию не подлежат.</summary>
public enum GridProfileKind
{
    Mixed = 0,
    Animation = 1,
    Sitcom = 2,
    Music = 3,
    Movies = 4,
    Kids = 5,
}

/// <summary>
/// Полоса вещательных суток — «утренний блок», «прайм», «ночь». Описывает, чем полосу закрывать и
/// каким куском: длина слота, сколько единиц он берёт за выход и по какой стратегии выбирает.
///
/// Времена — часы канала (не UTC и не смещения): профиль пишется так, как его читает человек,
/// а перевод в смещения от начала вещательных суток делает планировщик.
/// </summary>
/// <param name="BlockMinutes">Целевая длина одного слота внутри полосы; 0 — полоса одним слотом.</param>
/// <param name="UnitsPerBlock">Сколько единиц берёт слот за выход; 0 — сколько влезет в бюджет.</param>
/// <param name="MinAudience">Нижняя граница рейтинга: так задаются ночные взрослые блоки.</param>
public sealed record GridBand(
    TimeOnly From,
    TimeOnly To,
    Daypart Daypart,
    string Title,
    ShowKind? PreferKind = null,
    ShowAudience? MaxAudience = null,
    ShowAudience? MinAudience = null,
    int BlockMinutes = 120,
    int UnitsPerBlock = 0,
    SlotStrategyType Strategy = SlotStrategyType.Sequential,
    int CooldownDays = 0,
    SlotKind SlotKind = SlotKind.Content,
    int RepeatDaysAgo = 1,
    TimeOnly RepeatFrom = default,
    /// <summary>Раскладывать по дням недели с чередованием групп — для прайма, где нужен разный контент.</summary>
    bool Rotate = false
)
{
    /// <summary>Длина полосы в минутах; полоса через полночь считается вперёд, а не назад.</summary>
    public int LengthMinutes
    {
        get
        {
            var length = (int)(To.ToTimeSpan() - From.ToTimeSpan()).TotalMinutes;
            return length > 0 ? length : length + GridCoverage.MinutesInDay;
        }
    }
}

/// <summary>
/// Сезонный слой профиля: как выглядят сутки в праздничный период. Слой ложится поверх основного
/// и действует только в свои даты — на настоящем ТВ праздничная сетка ровно этим и является,
/// отдельной программой на неделю, а не правкой обычной.
/// </summary>
public sealed record GridSeason(string Name, AnnualRange Range, IReadOnlyList<GridBand> Bands);

/// <summary>
/// Готовый профиль сетки: как выглядят вещательные сутки у канала такого типа. Профили списаны
/// с реальных каналов намеренно — «как у 2×2» админ проверяет по памяти, а «универсальный
/// алгоритм раскладки» проверить нельзя никак.
///
/// <see cref="Weekend"/> пуст — выходные идут по будним полосам.
/// </summary>
public sealed record GridProfile(
    GridProfileKind Kind,
    string Name,
    string Reference,
    string Description,
    IReadOnlyList<GridBand> Weekdays,
    IReadOnlyList<GridBand> Weekend,
    /// <summary>Праздничная сетка профиля (null — сезонного слоя у профиля нет).</summary>
    GridSeason? Season = null
);
