using GmRelay.Bot.Features.Sessions.CreateSession;
using Telegram.Bot.Types;

namespace GmRelay.Bot.Tests.Features.Sessions.CreateSession;

public sealed class NewSessionCommandParserTests
{
    [Fact]
    public void Parse_ShouldExtractTitleLinkAndUpcomingTimes()
    {
        var nowUtc = new DateTimeOffset(2026, 4, 23, 12, 0, 0, TimeSpan.Zero);
        var text = """
            /newsession
            Название: Curse of Strahd
            Время: 24.04.2026 19:30
            Время: 01.05.2026 20:00
            Мест: 4
            Ссылка: https://example.test/room
            """;

        var result = NewSessionCommandParser.Parse(text, nowUtc);

        Assert.True(result.IsValid);
        Assert.Equal("Curse of Strahd", result.Title);
        Assert.Equal("https://example.test/room", result.Link);
        Assert.Equal(4, result.MaxPlayers);
        Assert.Equal(
            [
                new DateTimeOffset(2026, 4, 24, 16, 30, 0, TimeSpan.Zero),
                new DateTimeOffset(2026, 5, 1, 17, 0, 0, TimeSpan.Zero)
            ],
            result.ScheduledTimes);
        Assert.Empty(result.PastTimeInputs);
        Assert.Empty(result.InvalidTimeInputs);
    }

    [Fact]
    public void Parse_ShouldExtractOptionalImageUrl()
    {
        var nowUtc = new DateTimeOffset(2026, 4, 23, 12, 0, 0, TimeSpan.Zero);
        var text = """
            /newsession
            Название: Curse of Strahd
            Время: 24.04.2026 19:30
            Ссылка: https://example.test/room
            Картинка: https://example.test/strahd.jpg
            """;

        var result = NewSessionCommandParser.Parse(text, nowUtc);

        Assert.True(result.IsValid);
        Assert.Equal("https://example.test/strahd.jpg", result.ImageUrl);
    }

    [Fact]
    public void GetBatchImageReference_ShouldPreferAttachedPhotoOverParsedUrl()
    {
        var message = new Message
        {
            Photo =
            [
                new PhotoSize { FileId = "small-photo", Width = 320, Height = 180, FileSize = 10 },
                new PhotoSize { FileId = "large-photo", Width = 1280, Height = 720, FileSize = 20 }
            ]
        };

        var imageReference = CreateSessionHandler.GetBatchImageReference(
            message,
            "https://example.test/cover.jpg");

        Assert.Equal("large-photo", imageReference);
    }

    [Fact]
    public void Parse_ShouldExpandRecurringSchedule_WhenRepeatCountAndIntervalProvided()
    {
        var nowUtc = new DateTimeOffset(2026, 4, 23, 12, 0, 0, TimeSpan.Zero);
        var text = """
            /newsession
            Название: Kingmaker
            Время: 30.04.2026 19:30
            Игр: 4
            Интервал: 14
            Ссылка: https://example.test/kingmaker
            """;

        var result = NewSessionCommandParser.Parse(text, nowUtc);

        Assert.True(result.IsValid);
        Assert.Equal(
            [
                new DateTimeOffset(2026, 4, 30, 16, 30, 0, TimeSpan.Zero),
                new DateTimeOffset(2026, 5, 14, 16, 30, 0, TimeSpan.Zero),
                new DateTimeOffset(2026, 5, 28, 16, 30, 0, TimeSpan.Zero),
                new DateTimeOffset(2026, 6, 11, 16, 30, 0, TimeSpan.Zero)
            ],
            result.ScheduledTimes);
    }

    [Fact]
    public void Parse_ShouldCollectPastAndInvalidTimes()
    {
        var nowUtc = new DateTimeOffset(2026, 4, 23, 12, 0, 0, TimeSpan.Zero);
        var text = """
            Название: Delta Green
            Время: 20.04.2026 19:30
            Время: 31.04.2026 19:30
            Время: 25.04.2026 18:00
            Ссылка: https://example.test/dg
            """;

        var result = NewSessionCommandParser.Parse(text, nowUtc);

        Assert.True(result.IsValid);
        Assert.Single(result.ScheduledTimes);
        Assert.Equal(["20.04.2026 19:30"], result.PastTimeInputs);
        Assert.Equal(["31.04.2026 19:30"], result.InvalidTimeInputs);
    }

    [Fact]
    public void Parse_ShouldBeInvalid_WhenRequiredFieldsMissing()
    {
        var text = """
            /newsession
            Название: Blades in the Dark
            Время: 25.04.2026 19:30
            """;

        var result = NewSessionCommandParser.Parse(text, DateTimeOffset.UtcNow);

        Assert.False(result.IsValid);
        Assert.Null(result.Link);
    }

    [Fact]
    public void Parse_ShouldCollectInvalidSeatLimit()
    {
        var text = """
            /newsession
            Название: Blades in the Dark
            Время: 25.04.2026 19:30
            Мест: 0
            Ссылка: https://example.test/blades
            """;

        var result = NewSessionCommandParser.Parse(text, DateTimeOffset.UtcNow);

        Assert.False(result.IsValid);
        Assert.Null(result.MaxPlayers);
        Assert.Equal(["0"], result.InvalidSeatLimitInputs);
    }
}
