using System;
using System.Threading;
using System.Threading.Tasks;
using GmRelay.Bot.Features.Sessions.CreateSession;
using GmRelay.Bot.Features.Sessions.CreateSession.Wizard;
using GmRelay.Shared.Features.Sessions.CreateSession.Wizard;
using Microsoft.Extensions.Logging.Abstractions;
using static GmRelay.Bot.Tests.Features.Sessions.CreateSession.Wizard.WizardTestFakes;

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

/// <summary>
/// Verifies the validation gates inside
/// <see cref="CreateSessionHandler.SubmitDraftAsync"/>. We never reach the
/// shared handler in any of these tests, so the shared dependency is
/// passed as <c>null!</c> — a NRE on that branch would itself prove the
/// validation did not fire.
/// </summary>
public sealed class CreateSessionHandlerSubmitValidationTests
{
    [Fact]
    public async Task SubmitDraftAsync_MissingVisibility_EditsMessageNamingVisibility()
    {
        var drafts = new FakeWizardDraftRepository();
        var messenger = new FakeWizardMessenger();

        var sut = new CreateSessionHandler(
            drafts,
            shared: null!,
            messenger,
            NullLogger<CreateSessionHandler>.Instance);

        // All required fields set except Visibility.
        var payload = new WizardPayload
        {
            Type = WizardCreationType.Single,
            Title = "T",
            System = "Dnd5e",
            DurationMinutes = 240,
            Single = new WizardSingleInput
            {
                ScheduledAt = DateTimeOffset.UtcNow.AddDays(7),
                MaxPlayers = 4,
            },
        };
        var draft = NewDraft(WizardStepNames.Confirm, payload);
        drafts.Seed(draft);

        await sut.SubmitDraftAsync(draft, CancellationToken.None);

        Assert.Single(messenger.Edits);
        Assert.Contains("видимость", messenger.Edits[0].Text, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public async Task SubmitDraftAsync_MissingSystem_EditsMessageNamingSystem()
    {
        var drafts = new FakeWizardDraftRepository();
        var messenger = new FakeWizardMessenger();

        var sut = new CreateSessionHandler(
            drafts,
            shared: null!,
            messenger,
            NullLogger<CreateSessionHandler>.Instance);

        // All required fields set except System.
        var payload = new WizardPayload
        {
            Type = WizardCreationType.Single,
            Title = "T",
            DurationMinutes = 240,
            Visibility = WizardVisibility.Public,
            Single = new WizardSingleInput
            {
                ScheduledAt = DateTimeOffset.UtcNow.AddDays(7),
                MaxPlayers = 4,
            },
        };
        var draft = NewDraft(WizardStepNames.Confirm, payload);
        drafts.Seed(draft);

        await sut.SubmitDraftAsync(draft, CancellationToken.None);

        Assert.Single(messenger.Edits);
        Assert.Contains("система", messenger.Edits[0].Text, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public async Task SubmitDraftAsync_MissingDateTimeForSingleType_EditsMessageNamingDateTime()
    {
        var drafts = new FakeWizardDraftRepository();
        var messenger = new FakeWizardMessenger();

        var sut = new CreateSessionHandler(
            drafts,
            shared: null!,
            messenger,
            NullLogger<CreateSessionHandler>.Instance);

        // All required fields set except ScheduledAt for Single type.
        var payload = new WizardPayload
        {
            Type = WizardCreationType.Single,
            Title = "T",
            System = "Dnd5e",
            DurationMinutes = 240,
            Visibility = WizardVisibility.Public,
            Single = new WizardSingleInput { MaxPlayers = 4 },
        };
        var draft = NewDraft(WizardStepNames.Confirm, payload);
        drafts.Seed(draft);

        await sut.SubmitDraftAsync(draft, CancellationToken.None);

        Assert.Single(messenger.Edits);
        Assert.Contains("дата/время", messenger.Edits[0].Text, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public async Task SubmitDraftAsync_EmptyPool_EditsMessageNamingSlots()
    {
        var drafts = new FakeWizardDraftRepository();
        var messenger = new FakeWizardMessenger();

        var sut = new CreateSessionHandler(
            drafts,
            shared: null!,
            messenger,
            NullLogger<CreateSessionHandler>.Instance);

        // Pool type with no slots at all.
        var payload = new WizardPayload
        {
            Type = WizardCreationType.Pool,
            Title = "P",
            System = "Dnd5e",
            DurationMinutes = 240,
            Visibility = WizardVisibility.Public,
            Pool = new WizardPoolInput(),
        };
        var draft = NewDraft(WizardStepNames.Confirm, payload);
        drafts.Seed(draft);

        await sut.SubmitDraftAsync(draft, CancellationToken.None);

        Assert.Single(messenger.Edits);
        Assert.Contains("слоты", messenger.Edits[0].Text, StringComparison.OrdinalIgnoreCase);
    }
}
