using TeleWave.Domain.Broadcast;
using Xunit;

namespace TeleWave.Domain.Tests.Broadcast;

public class ChannelTests
{
    private static readonly DateTimeOffset Epoch = new(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);

    private static Channel NewChannel() => Channel.Create("News", "news", Epoch);

    [Fact]
    public void Create_SetsDefaults_AndSeedsDefaultBumperTemplate()
    {
        var channel = NewChannel();

        Assert.NotEqual(Guid.Empty, channel.Id);
        Assert.Equal("News", channel.Name);
        Assert.Equal("news", channel.Slug);
        Assert.True(channel.IsEnabled);
        Assert.Equal(Epoch, channel.EpochUtc);
        Assert.False(channel.BumpersEnabled);
        Assert.Equal(BumperSelection.WeightedRandom, channel.BumperSelection);
        Assert.Equal(Channel.DefaultUtcOffsetMinutes, channel.UtcOffsetMinutes);
        Assert.Equal(Channel.DefaultDayStartTime, channel.DayStartTime);

        var template = Assert.Single(channel.BumperTemplates);
        Assert.True(template.IsDefault);
        Assert.Equal(0, template.Position);
        Assert.Single(template.Variants); // дефолтный подблок
    }

    [Fact]
    public void UpdateSettings_ChangesFields()
    {
        var channel = NewChannel();
        var filler = Guid.NewGuid();

        channel.UpdateSettings("N2", false, true, filler);

        Assert.Equal("N2", channel.Name);
        Assert.False(channel.IsEnabled);
        Assert.True(channel.BumpersEnabled);
        Assert.Equal(filler, channel.FillerAssetId);
    }

    [Fact]
    public void UpdateBumperSettings_ChangesFontAndSelection()
    {
        var channel = NewChannel();

        channel.UpdateBumperSettings(BumperFont.Serif, BumperSelection.AlwaysFirst);

        Assert.Equal(BumperFont.Serif, channel.BumperFont);
        Assert.Equal(BumperSelection.AlwaysFirst, channel.BumperSelection);
    }

    [Theory]
    [InlineData(-1.0, 2.0, 0.0, 1.0)]
    [InlineData(0.4, 0.25, 0.4, 0.25)]
    public void UpdateViewerSettings_ClampsStrengths(
        double opacity,
        double filter,
        double expectedOpacity,
        double expectedFilter
    )
    {
        var channel = NewChannel();
        var logo = Guid.NewGuid();

        channel.UpdateViewerSettings(logo, LogoCorner.BottomRight, opacity, true, filter);

        Assert.Equal(logo, channel.LogoImageId);
        Assert.Equal(LogoCorner.BottomRight, channel.LogoCorner);
        Assert.Equal(expectedOpacity, channel.LogoOpacity);
        Assert.True(channel.ShowClock);
        Assert.Equal(expectedFilter, channel.AnalogFilterStrength);
    }

    [Fact]
    public void NewChannel_HasViewerOverlaysOff()
    {
        // Канал без логотипа, часов и шума — законная конфигурация, а не недонастроенная.
        var channel = NewChannel();

        Assert.Null(channel.LogoImageId);
        Assert.False(channel.ShowClock);
        Assert.Equal(0.0, channel.AnalogFilterStrength);
    }

    [Fact]
    public void AddBumperTemplate_AppendsWithNextPosition()
    {
        var channel = NewChannel();

        var t1 = channel.AddBumperTemplate("Block 2");
        var t2 = channel.AddBumperTemplate("Block 3");

        Assert.Equal(1, t1.Position);
        Assert.Equal(2, t2.Position);
        Assert.False(t1.IsDefault);
        Assert.Equal(3, channel.BumperTemplates.Count);
        Assert.Equal(t1, channel.FindBumperTemplate(t1.Id));
        Assert.Null(channel.FindBumperTemplate(Guid.NewGuid()));
    }

    [Fact]
    public void RemoveBumperTemplate_CannotRemoveDefault_CanRemoveOthers()
    {
        var channel = NewChannel();
        var def = channel.BumperTemplates[0];
        var extra = channel.AddBumperTemplate("Block 2");

        Assert.False(channel.RemoveBumperTemplate(def.Id));
        Assert.True(channel.RemoveBumperTemplate(extra.Id));
        Assert.False(channel.RemoveBumperTemplate(Guid.NewGuid()));
        Assert.Single(channel.BumperTemplates);
    }

    [Fact]
    public void UpdateTimeSettings_ClampsOffsetAndDropsNonPositiveNumber()
    {
        var channel = NewChannel();

        channel.UpdateTimeSettings(0, 99 * 60, new TimeOnly(5, 0));

        // Номер 0 — не номер; смещение за пределами суток оторвало бы сетку от календаря.
        Assert.Null(channel.Number);
        Assert.Equal(14 * 60, channel.UtcOffsetMinutes);
        Assert.Equal(new TimeOnly(5, 0), channel.DayStartTime);
    }

    [Fact]
    public void SetTemplate_LinksAndUnlinks()
    {
        var channel = NewChannel();
        var templateId = Guid.NewGuid();

        channel.SetTemplate(templateId);
        Assert.Equal(templateId, channel.TemplateId);

        channel.SetTemplate(null);
        Assert.Null(channel.TemplateId);
    }
}
