namespace TeleWave.Domain.Broadcast;

/// <summary>Оформление блока заставки: имя, шрифт и палитра (цвета — в нотации ffmpeg: 0xRRGGBB или имя).</summary>
public sealed record BumperStyle(
    string Name,
    BumperFont Font,
    string BackgroundColor,
    string BackgroundColor2,
    string AccentColor,
    string TextColor
);

/// <summary>
/// Блок ТВ-заставки: свой звук + своё оформление (шрифт, цвета, опциональная фон-картинка) + набор
/// подблоков (<see cref="Variants"/>) с разным текстом и правилом показа. Длительность заставки — по
/// длине звука (выравнивается на сегмент при рендере).
///
/// Блок общий для всех каналов, как группа: файлы звука и фона и так лежат по идентификатору блока,
/// канал в них никогда не участвовал. Поэтому же шрифт живёт здесь, а не на канале — иначе два
/// канала с разным шрифтом делили бы один отрендеренный ассет.
/// </summary>
public class BumperTemplate
{
    private readonly List<BumperTextVariant> _variants = [];

    public Guid Id { get; private set; }

    public string Name { get; private set; } = string.Empty;

    public BumperFont Font { get; private set; }

    // ── Оформление блока (цвета — в нотации ffmpeg: 0xRRGGBB или имя) ──
    public string BackgroundColor { get; private set; } = DefaultBackgroundColor;
    public string BackgroundColor2 { get; private set; } = DefaultBackgroundColor2;
    public string AccentColor { get; private set; } = DefaultAccentColor;
    public string TextColor { get; private set; } = DefaultTextColor;

    /// <summary>Фон-картинка блока — ссылка на запись реестра изображений или null (тогда фон градиент).</summary>
    public Guid? BackgroundImageId { get; private set; }

    /// <summary>Расширение загруженного звука (с точкой) или null — тогда синтезируется джингл.</summary>
    public string? AudioExtension { get; private set; }

    /// <summary>Длина загруженного звука в секундах (замер ffprobe) или null, если звука нет.</summary>
    public double? AudioDurationSeconds { get; private set; }

    /// <summary>Версия блока (звук/фон/оформление). Входит в сигнатуру рендера — правка пересобирает заставки.</summary>
    public int Revision { get; private set; }

    public DateTimeOffset CreatedAt { get; private set; }

    public const string DefaultBackgroundColor = "0x0b1020";
    public const string DefaultBackgroundColor2 = "0x1e293b";
    public const string DefaultAccentColor = "0x38bdf8";
    public const string DefaultTextColor = "white";

    /// <summary>Подблоки (текст-варианты); порядок — по <see cref="BumperTextVariant.Position"/>.</summary>
    public IReadOnlyList<BumperTextVariant> Variants => _variants;

    private BumperTemplate() { }

    /// <summary>Создаёт блок с одним пустым подблоком — текст в него кладёт вызывающий (пресетом).</summary>
    public static BumperTemplate Create(string name, string variantName)
    {
        var template = new BumperTemplate
        {
            Id = Guid.NewGuid(),
            Name = name.Trim(),
            Font = BumperFont.Sans,
            BackgroundColor = DefaultBackgroundColor,
            BackgroundColor2 = DefaultBackgroundColor2,
            AccentColor = DefaultAccentColor,
            TextColor = DefaultTextColor,
            BackgroundImageId = null,
            AudioExtension = null,
            AudioDurationSeconds = null,
            Revision = 0,
            CreatedAt = DateTimeOffset.UtcNow,
        };
        template._variants.Add(
            BumperTextVariant.Create(template.Id, 0, variantName, BumperTrigger.OnShowChange)
        );
        return template;
    }

    public BumperTextVariant AddVariant(string name)
    {
        var nextPosition = _variants.Count == 0 ? 0 : _variants.Max(v => v.Position) + 1;
        var variant = BumperTextVariant.Create(Id, nextPosition, name, BumperTrigger.OnShowChange);
        _variants.Add(variant);
        return variant;
    }

    public BumperTextVariant? FindVariant(Guid variantId) =>
        _variants.FirstOrDefault(v => v.Id == variantId);

    /// <summary>Удалить подблок. Последний подблок удалить нельзя (нужен хотя бы один) — вернёт false.</summary>
    public bool RemoveVariant(Guid variantId)
    {
        if (_variants.Count <= 1)
            return false;
        var variant = _variants.FirstOrDefault(v => v.Id == variantId);
        if (variant is null)
            return false;
        _variants.Remove(variant);
        return true;
    }

    /// <summary>
    /// Обновить имя, шрифт и цвета блока. Меняет ревизию: оформление входит в сигнатуру рендера,
    /// иначе смена шрифта оставила бы в эфире заставки, набранные прежним.
    /// </summary>
    public void UpdateStyle(BumperStyle style)
    {
        Name = style.Name.Trim();
        Font = style.Font;
        BackgroundColor = style.BackgroundColor;
        BackgroundColor2 = style.BackgroundColor2;
        AccentColor = style.AccentColor;
        TextColor = style.TextColor;
        Revision++;
    }

    /// <summary>Отметить загруженный звук (extension — с точкой, нижний регистр) и его длину. Меняет ревизию.</summary>
    public void SetAudio(string extension, double durationSeconds)
    {
        AudioExtension = extension;
        AudioDurationSeconds = durationSeconds > 0 ? durationSeconds : null;
        Revision++;
    }

    public void ClearAudio()
    {
        if (AudioExtension is null && AudioDurationSeconds is null)
            return;
        AudioExtension = null;
        AudioDurationSeconds = null;
        Revision++;
    }

    /// <summary>Привязать фон-картинку блока (ссылка на реестр изображений). Меняет ревизию.</summary>
    public void SetBackgroundImage(Guid imageId)
    {
        BackgroundImageId = imageId;
        Revision++;
    }

    public void ClearBackgroundImage()
    {
        if (BackgroundImageId is null)
            return;
        BackgroundImageId = null;
        Revision++;
    }
}
