using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Broadcast.Bumpers;
using TeleWave.Application.Tests.Support;
using TeleWave.Domain.Broadcast;
using Xunit;

namespace TeleWave.Application.Tests.Broadcast;

public class BumperVariantHandlersTests
{
    private static BumperTemplate NewTemplate() => BumperTemplate.Create("Блок", "Текст 1");

    private static BumperLineDto Line(string text) =>
        new(BumperLineStyle.Title, BumperLineColor.Text, text);

    [Fact]
    public async Task AddVariant_StartsFromDefaultPreset()
    {
        var fixture = new TestDb();
        var template = NewTemplate();
        await using (var seed = fixture.New())
        {
            seed.BumperTemplates.Add(template);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        await using var db = fixture.New();
        var result = await new AddBumperVariantCommandHandler(db).Handle(
            new AddBumperVariantCommand(template.Id, "Текст 2"),
            CancellationToken.None
        );
        Assert.True(result.IsSuccess);
        await db.SaveChangesAsync(CancellationToken.None);

        await using var verify = fixture.New();
        var stored = await verify
            .BumperTemplates.Include(t => t.Variants)
            .FirstAsync(t => t.Id == template.Id);
        Assert.Equal(2, stored.Variants.Count);
        var added = stored.Variants.First(v => v.Name == "Текст 2");
        // Пустой подблок в редакторе выглядит поломанным — новый начинается с «Сейчас/Далее».
        Assert.Equal(4, added.Lines.Count);
        Assert.Contains(added.Lines, l => l.Text == "{next.title}");
    }

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

        var result = await new AddBumperVariantCommandHandler(db).Handle(
            new AddBumperVariantCommand(Guid.NewGuid(), "x"),
            CancellationToken.None
        );

        Assert.Equal(BumperErrors.TemplateNotFound, result.Error);
    }

    [Fact]
    public async Task UpdateVariant_ReplacesLinesAndFields()
    {
        var fixture = new TestDb();
        var template = NewTemplate();
        var variant = template.Variants[0];
        await using (var seed = fixture.New())
        {
            seed.BumperTemplates.Add(template);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        await using var db = fixture.New();
        var result = await new UpdateBumperVariantCommandHandler(db).Handle(
            new UpdateBumperVariantCommand(
                template.Id,
                variant.Id,
                new BumperVariantInput(
                    "Custom",
                    BumperTrigger.Both,
                    BumperBackground.Template,
                    7,
                    [
                        new BumperLineDto(
                            BumperLineStyle.Label,
                            BumperLineColor.Accent,
                            "ДАЛЕЕ В {next.time}"
                        ),
                        Line("{next.title}"),
                    ]
                )
            ),
            CancellationToken.None
        );
        Assert.True(result.IsSuccess);
        await db.SaveChangesAsync(CancellationToken.None);

        await using var verify = fixture.New();
        var stored = await verify
            .BumperTemplates.Include(t => t.Variants)
            .FirstAsync(t => t.Id == template.Id);
        var v = stored.Variants[0];
        Assert.Equal("Custom", v.Name);
        Assert.Equal(BumperTrigger.Both, v.Trigger);
        Assert.Equal(BumperBackground.Template, v.Background);
        Assert.Equal(7, v.Weight);
        Assert.Equal(2, v.Lines.Count);
        Assert.Equal("ДАЛЕЕ В {next.time}", v.Lines[0].Text);
    }

    [Fact]
    public async Task UpdateVariant_UnknownPlaceholder_IsRejected()
    {
        var fixture = new TestDb();
        var template = NewTemplate();
        var variant = template.Variants[0];
        await using (var seed = fixture.New())
        {
            seed.BumperTemplates.Add(template);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        await using var db = fixture.New();
        var result = await new UpdateBumperVariantCommandHandler(db).Handle(
            new UpdateBumperVariantCommand(
                template.Id,
                variant.Id,
                new BumperVariantInput(
                    "Custom",
                    BumperTrigger.Both,
                    BumperBackground.Template,
                    1,
                    [Line("Далее {next.tittle}")]
                )
            ),
            CancellationToken.None
        );

        // В эфире опечатка превратилась бы в пустоту, и заметить это было бы уже некому.
        Assert.Equal("Bumpers.UnknownPlaceholders", result.Error.Code);
    }

    [Fact]
    public async Task RemoveVariant_CannotRemoveLast_ButRemovesExtra()
    {
        var fixture = new TestDb();
        var template = NewTemplate();
        var only = template.Variants[0];
        var extra = template.AddVariant("Текст 2");
        await using (var seed = fixture.New())
        {
            seed.BumperTemplates.Add(template);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        await using var db = fixture.New();
        var okRemove = await new RemoveBumperVariantCommandHandler(db).Handle(
            new RemoveBumperVariantCommand(template.Id, extra.Id),
            CancellationToken.None
        );
        Assert.True(okRemove.IsSuccess);
        await db.SaveChangesAsync(CancellationToken.None);

        await using var db2 = fixture.New();
        var lastGuard = await new RemoveBumperVariantCommandHandler(db2).Handle(
            new RemoveBumperVariantCommand(template.Id, only.Id),
            CancellationToken.None
        );
        Assert.Equal(BumperErrors.CannotRemoveLastVariant, lastGuard.Error);
    }
}
