using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Broadcast;
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 readonly DateTimeOffset T0 = new(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);

    [Fact]
    public async Task AddVariant_AutoNames_WhenBlank()
    {
        var fixture = new TestDb();
        var channel = Channel.Create("c", "c", T0);
        var template = channel.BumperTemplates[0];
        await using (var seed = fixture.New())
        {
            seed.Channels.Add(channel);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        await using var db = fixture.New();
        var result = await new AddBumperTextVariantCommandHandler(db).Handle(
            new AddBumperTextVariantCommand(channel.Id, template.Id, "  "),
            CancellationToken.None
        );
        Assert.True(result.IsSuccess);
        await db.SaveChangesAsync(CancellationToken.None);

        await using var verify = fixture.New();
        var stored = await verify
            .Channels.Include(c => c.BumperTemplates)
                .ThenInclude(t => t.Variants)
            .FirstAsync(c => c.Id == channel.Id);
        var variants = stored.BumperTemplates[0].Variants;
        Assert.Equal(2, variants.Count);
        Assert.Contains(variants, v => v.Name == "Текст 2");
    }

    [Fact]
    public async Task AddVariant_UnknownTemplate_ReturnsNotFound()
    {
        var fixture = new TestDb();
        var channel = Channel.Create("c", "c", T0);
        await using (var seed = fixture.New())
        {
            seed.Channels.Add(channel);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        await using var db = fixture.New();
        var result = await new AddBumperTextVariantCommandHandler(db).Handle(
            new AddBumperTextVariantCommand(channel.Id, Guid.NewGuid(), "x"),
            CancellationToken.None
        );
        Assert.Equal(ChannelErrors.BumperTemplateNotFound, result.Error);
    }

    [Fact]
    public async Task UpdateVariant_ChangesFields()
    {
        var fixture = new TestDb();
        var channel = Channel.Create("c", "c", T0);
        var template = channel.BumperTemplates[0];
        var variant = template.Variants[0];
        await using (var seed = fixture.New())
        {
            seed.Channels.Add(channel);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        await using var db = fixture.New();
        var result = await new UpdateBumperTextVariantCommandHandler(db).Handle(
            new UpdateBumperTextVariantCommand(
                channel.Id,
                template.Id,
                variant.Id,
                "Custom",
                BumperTextKind.Free,
                "NOW",
                "NEXT",
                "line1",
                "line2",
                BumperTrigger.Both,
                7
            ),
            CancellationToken.None
        );
        Assert.True(result.IsSuccess);
        await db.SaveChangesAsync(CancellationToken.None);

        await using var verify = fixture.New();
        var stored = await verify
            .Channels.Include(c => c.BumperTemplates)
                .ThenInclude(t => t.Variants)
            .FirstAsync(c => c.Id == channel.Id);
        var v = stored.BumperTemplates[0].Variants[0];
        Assert.Equal("Custom", v.Name);
        Assert.Equal(BumperTextKind.Free, v.Kind);
        Assert.Equal(7, v.Weight);
        Assert.Equal(BumperTrigger.Both, v.Trigger);
    }

    [Fact]
    public async Task RemoveVariant_CannotRemoveLast_ButRemovesExtra()
    {
        var fixture = new TestDb();
        var channel = Channel.Create("c", "c", T0);
        var template = channel.BumperTemplates[0];
        var only = template.Variants[0];
        var extra = template.AddVariant("Text 2");
        await using (var seed = fixture.New())
        {
            seed.Channels.Add(channel);
            await seed.SaveChangesAsync(CancellationToken.None);
        }

        await using var db = fixture.New();
        var handler = new RemoveBumperTextVariantCommandHandler(db);

        var okRemove = await handler.Handle(
            new RemoveBumperTextVariantCommand(channel.Id, 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 RemoveBumperTextVariantCommandHandler(db2).Handle(
            new RemoveBumperTextVariantCommand(channel.Id, template.Id, only.Id),
            CancellationToken.None
        );
        Assert.Equal(ChannelErrors.CannotRemoveLastBumperTextVariant, lastGuard.Error);
    }
}
