using Microsoft.Extensions.Options;
using NSubstitute;
using TeleWave.Application.Broadcast.Bumpers;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Streaming;
using TeleWave.Application.Tests.Support;
using TeleWave.Domain.Broadcast;
using TeleWave.Domain.Images;
using TeleWave.Domain.Library;
using TeleWave.Domain.Media;
using Xunit;

namespace TeleWave.Application.Tests.Broadcast;

/// <summary>
/// Восстановление спецификации для фонового рендерера. Текст берётся из кэша как есть: время показа
/// и пара соседей задним числом не восстанавливаются, а ffmpeg запускается уже после записи ленты.
/// </summary>
public class BumperSpecLoaderTests
{
    private static readonly IReadOnlyList<BumperRenderLine> Lines =
    [
        new(BumperLineStyle.Label, BumperLineColor.Accent, "СЕЙЧАС"),
        new(BumperLineStyle.Title, BumperLineColor.Text, "Симпсоны"),
    ];

    private static BumperSpecLoader NewLoader(
        Infrastructure.Persistence.AppDbContext db,
        IBumperTemplateStorage? storage = null,
        IImageStore? images = null,
        IMediaStorage? media = null
    ) =>
        new(
            db,
            storage ?? Substitute.For<IBumperTemplateStorage>(),
            images ?? Substitute.For<IImageStore>(),
            media ?? Substitute.For<IMediaStorage>(),
            Options.Create(new BumperOptions()),
            Options.Create(new StreamingOptions { SegmentSeconds = 5 })
        );

    [Fact]
    public async Task Load_UnknownAsset_ReturnsNull()
    {
        var fixture = new TestDb();
        await using var db = fixture.New();

        Assert.Null(await NewLoader(db).LoadAsync(Guid.NewGuid(), CancellationToken.None));
    }

    [Fact]
    public async Task Load_RestoresRenderedTextAndPaths()
    {
        var fixture = new TestDb();
        var template = BumperTemplate.Create("Блок", "Текст 1");
        template.UpdateStyle(
            new BumperStyle("Блок", BumperFont.Serif, "0x111111", "0x222222", "0x333333", "white")
        );
        template.SetAudio(".mp3", 12);
        var background = Image.Create(ImageCategory.BumperBackground, ".png", "bg.png");
        template.SetBackgroundImage(background.Id);

        var poster = Image.Create(ImageCategory.ShowPoster, ".jpg", "poster.jpg");
        var show = Show.Create("Терминатор", ShowKind.Single);
        show.ApplyMetadata("tmdb", "1", null, 1991, poster.Id);

        var asset = MediaAsset.RegisterGenerated("Блок: СЕЙЧАС / Симпсоны");
        var cache = BumperAsset.Create(
            template.Id,
            template.Variants[0].Id,
            "sig",
            BumperRenderedText.ToJson(Lines),
            show.Id,
            asset.Id
        );

        await using (var seed = fixture.New())
        {
            seed.BumperTemplates.Add(template);
            seed.Images.AddRange(background, poster);
            seed.Shows.Add(show);
            seed.MediaAssets.Add(asset);
            seed.BumperAssets.Add(cache);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        var storage = Substitute.For<IBumperTemplateStorage>();
        storage.AudioPath(template.Id, ".mp3").Returns("/media/bumpers/audio.mp3");
        var images = Substitute.For<IImageStore>();
        images.ResolvePath(background.Id, ".png").Returns("/media/images/bg.png");
        images.ResolvePath(poster.Id, ".jpg").Returns("/media/images/poster.jpg");

        await using var db = fixture.New();
        var spec = await NewLoader(db, storage, images).LoadAsync(asset.Id, CancellationToken.None);

        Assert.NotNull(spec);
        Assert.Equal(Lines, spec.Lines);
        Assert.Equal("/media/bumpers/audio.mp3", spec.MusicFile);
        Assert.Equal("/media/images/bg.png", spec.BackgroundFile);
        Assert.Equal("/media/images/poster.jpg", spec.PosterFile);
        Assert.Equal("0x333333", spec.AccentColor);
        // Длина звука 12 с выравнивается вверх до кратности сегменту (5 с).
        Assert.Equal(15, spec.DurationSeconds);
    }

    [Fact]
    public async Task Load_TemplateGone_ReturnsNull()
    {
        var fixture = new TestDb();
        var asset = MediaAsset.RegisterGenerated("Заставка");
        var cache = BumperAsset.Create(
            Guid.NewGuid(),
            Guid.NewGuid(),
            "sig",
            BumperRenderedText.ToJson(Lines),
            null,
            asset.Id
        );

        await using (var seed = fixture.New())
        {
            seed.MediaAssets.Add(asset);
            seed.BumperAssets.Add(cache);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        await using var db = fixture.New();
        // Блок удалили, пока ассет ждал рендера — рендерить нечем, и это не авария.
        Assert.Null(await NewLoader(db).LoadAsync(asset.Id, CancellationToken.None));
    }
}
