namespace TeleWave.Domain.Broadcast;

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

    public Guid Id { get; private set; }
    public Guid ChannelId { get; private set; }

    /// <summary>Порядковый номер (0 — дефолтный блок). Используется ротацией и как признак дефолта.</summary>
    public int Position { get; private set; }

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

    // ── Оформление блока (цвета — в нотации 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";

    public bool IsDefault => Position == 0;

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

    private const string DefaultVariantName = "Текст 1";

    private BumperTemplate() { }

    internal static BumperTemplate Create(Guid channelId, int position, string name)
    {
        var template = new BumperTemplate
        {
            Id = Guid.NewGuid(),
            ChannelId = channelId,
            Position = position,
            Name = name,
            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, DefaultVariantName, 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>Обновить имя и цвета блока. Цвета — в нотации ffmpeg (0xRRGGBB или имя).</summary>
    public void UpdateStyle(
        string name,
        string backgroundColor,
        string backgroundColor2,
        string accentColor,
        string textColor
    )
    {
        Name = name;
        BackgroundColor = backgroundColor;
        BackgroundColor2 = backgroundColor2;
        AccentColor = accentColor;
        TextColor = textColor;
    }

    /// <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++;
    }
}
