namespace TeleWave.Domain.Broadcast;

/// <summary>
/// Канал линейного эфира. Что и когда идёт в эфире, определяет шаблон сетки (<see cref="TemplateId"/>,
/// см. <c>Domain/Programming</c>); канал хранит только собственные свойства: время, номер, аварийный
/// филлер и настройки зрительской части.
///
/// Заставок на канале нет: блоки заставок общие (см. <see cref="BumperTemplate"/>), а условия их
/// показа — во врезках стыка.
/// </summary>
public class Channel
{
    public Guid Id { get; private set; }
    public string Name { get; private set; } = string.Empty;
    public string Slug { get; private set; } = string.Empty;
    public bool IsEnabled { get; private set; }

    /// <summary>Точка отсчёта эфирной ленты (UTC) — база для MEDIA-SEQUENCE на этапе раздачи.</summary>
    public DateTimeOffset EpochUtc { get; private set; }

    /// <summary>
    /// Номер канала — на телевизоре канал это номер, а не карточка в сетке. Переключение по номерам
    /// включается глобальным флагом настроек сайта; null — номер не задан.
    /// </summary>
    public int? Number { get; private set; }

    /// <summary>
    /// Смещение времени канала от UTC в минутах (по умолчанию 180 — московское). Фиксированный
    /// оффсет, а не IANA-зона: с переводом часов сутки становятся 23- или 25-часовыми, и сетке
    /// понадобилось бы отдельное правило подрезки. Появятся каналы в зонах с DST — перейдём на IANA.
    /// </summary>
    public int UtcOffsetMinutes { get; private set; }

    /// <summary>
    /// Начало вещательных суток в времени канала (по умолчанию 06:00). Ночной блок с 00:00 до 06:00
    /// относится к предыдущему дню: «ночь с пятницы на субботу» — это пятница.
    /// </summary>
    public TimeOnly DayStartTime { get; private set; }

    /// <summary>Активный шаблон сетки канала (один на канал).</summary>
    public Guid? TemplateId { get; private set; }

    public const int DefaultUtcOffsetMinutes = 180;
    public static readonly TimeOnly DefaultDayStartTime = new(6, 0);

    /// <summary>Ассет-заглушка на случай пустого расписания (аварийная подстраховка).</summary>
    public Guid? FillerAssetId { get; private set; }

    // ── Зрительская часть (см. 6.8). Всё рисуется на клиенте поверх <video>, ffmpeg не трогает,
    //    и всё по умолчанию выключено: канал без логотипа и без шума — законная конфигурация. ──

    /// <summary>Логотип-оверлей: ссылка на реестр изображений или null (логотипа нет).</summary>
    public Guid? LogoImageId { get; private set; }

    public LogoCorner LogoCorner { get; private set; }

    /// <summary>Прозрачность логотипа, 0..1.</summary>
    public double LogoOpacity { get; private set; } = 0.8;

    /// <summary>Показывать ли часы поверх картинки.</summary>
    public bool ShowClock { get; private set; }

    /// <summary>Сила аналогового фильтра, 0..1 (0 — выключен).</summary>
    public double AnalogFilterStrength { get; private set; }

    public DateTimeOffset CreatedAt { get; private set; }

    private Channel() { }

    public static Channel Create(string name, string slug, DateTimeOffset epochUtc) =>
        new()
        {
            Id = Guid.NewGuid(),
            Name = name,
            Slug = slug,
            IsEnabled = true,
            EpochUtc = epochUtc,
            LogoOpacity = 0.8,
            UtcOffsetMinutes = DefaultUtcOffsetMinutes,
            DayStartTime = DefaultDayStartTime,
            CreatedAt = DateTimeOffset.UtcNow,
        };

    public void UpdateSettings(string name, bool isEnabled, Guid? fillerAssetId)
    {
        Name = name;
        IsEnabled = isEnabled;
        FillerAssetId = fillerAssetId;
    }

    /// <summary>Оверлеи и фильтр зрительской части. Всё опционально; силы зажимаются в 0..1.</summary>
    public void UpdateViewerSettings(
        Guid? logoImageId,
        LogoCorner logoCorner,
        double logoOpacity,
        bool showClock,
        double analogFilterStrength
    )
    {
        LogoImageId = logoImageId;
        LogoCorner = logoCorner;
        LogoOpacity = Math.Clamp(logoOpacity, 0.0, 1.0);
        ShowClock = showClock;
        AnalogFilterStrength = Math.Clamp(analogFilterStrength, 0.0, 1.0);
    }

    /// <summary>Привязать активный шаблон сетки.</summary>
    public void SetTemplate(Guid? templateId) => TemplateId = templateId;

    /// <summary>
    /// Настройки времени канала: номер, смещение от UTC и начало вещательных суток. Смещение
    /// ограничено сутками — за пределами этого диапазона сетка потеряла бы связь с календарём.
    /// </summary>
    public void UpdateTimeSettings(int? number, int utcOffsetMinutes, TimeOnly dayStartTime)
    {
        Number = number is > 0 ? number : null;
        UtcOffsetMinutes = Math.Clamp(utcOffsetMinutes, -12 * 60, 14 * 60);
        DayStartTime = dayStartTime;
    }
}
