using System;
using GmRelay.Bot.Features.Sessions.CreateSession.Wizard;
using GmRelay.Shared.Features.Sessions.CreateSession.Wizard;
using static GmRelay.Bot.Tests.Features.Sessions.CreateSession.Wizard.WizardTestFakes;

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

/// <summary>
/// Verifies the wizard's Cancel and Back transitions:
/// - Cancel deletes the draft and posts a "cancelled" message.
/// - Back rewinds the draft to the previous step in the flow.
/// </summary>
public sealed class GameCreationWizardCancelBackTests
{
    [Fact]
    public async Task Cancel_DeletesDraftAndPostsCancelledMessage()
    {
        var wizard = BuildWizard(out var drafts, out var messenger);
        var draft = NewDraft(WizardStepNames.Title);
        drafts.Seed(draft);

        var data = WizardCallbackData.Cancel();
        await wizard.HandleUpdateAsync(CallbackUpdate(data), draft, CancellationToken.None);

        Assert.Contains(draft.Id, drafts.DeletedIds);
        Assert.Single(messenger.Edits);
        Assert.Contains("отменён", messenger.Edits[0].Text, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("cb-1", messenger.AnsweredCallbacks);
    }

    [Fact]
    public async Task Back_FromTitle_StaysOnTitle_AsItIsFirstStep()
    {
        var wizard = BuildWizard(out var drafts, out _);
        var draft = NewDraft(WizardStepNames.Title);
        drafts.Seed(draft);

        var data = WizardCallbackData.Back();
        await wizard.HandleUpdateAsync(CallbackUpdate(data), draft, CancellationToken.None);

        // Title is the first step, so Back is a no-op.
        Assert.Equal(WizardStepNames.Title, draft.Step);
    }

    [Fact]
    public async Task Back_FromDescription_GoesToTitle()
    {
        var wizard = BuildWizard(out var drafts, out _);
        var draft = NewDraft(WizardStepNames.Description,
            new WizardPayload { Type = WizardCreationType.Single, Title = "T" });
        drafts.Seed(draft);

        var data = WizardCallbackData.Back();
        await wizard.HandleUpdateAsync(CallbackUpdate(data), draft, CancellationToken.None);

        Assert.Equal(WizardStepNames.Title, draft.Step);
    }

    [Fact]
    public async Task Back_FromCover_GoesToDescription()
    {
        var wizard = BuildWizard(out var drafts, out _);
        var draft = NewDraft(WizardStepNames.Cover,
            new WizardPayload { Type = WizardCreationType.Single, Title = "T", Description = "D" });
        drafts.Seed(draft);

        var data = WizardCallbackData.Back();
        await wizard.HandleUpdateAsync(CallbackUpdate(data), draft, CancellationToken.None);

        Assert.Equal(WizardStepNames.Description, draft.Step);
    }

    [Fact]
    public async Task Back_FromSystem_GoesToCover()
    {
        var wizard = BuildWizard(out var drafts, out _);
        var draft = NewDraft(WizardStepNames.System,
            new WizardPayload { Type = WizardCreationType.Single, Title = "T", Description = "D" });
        drafts.Seed(draft);

        var data = WizardCallbackData.Back();
        await wizard.HandleUpdateAsync(CallbackUpdate(data), draft, CancellationToken.None);

        Assert.Equal(WizardStepNames.Cover, draft.Step);
    }

    [Fact]
    public async Task Back_FromPoolAddSlots_GoesToPoolSystemDuration()
    {
        var wizard = BuildWizard(out var drafts, out _);
        var draft = NewDraft(WizardStepNames.PoolAddSlots,
            new WizardPayload { Type = WizardCreationType.Pool, Title = "Pool" });
        drafts.Seed(draft);

        var data = WizardCallbackData.Back();
        await wizard.HandleUpdateAsync(CallbackUpdate(data), draft, CancellationToken.None);

        Assert.Equal(WizardStepNames.PoolSystemDuration, draft.Step);
    }

    [Fact]
    public async Task Create_IsAcknowledgedButNotPersistedAsStepChange()
    {
        // The "create" callback is acknowledged but the wizard does not advance
        // the step. Submission happens in CreateSessionHandler, not the wizard.
        var wizard = BuildWizard(out var drafts, out var messenger);
        var draft = NewDraft(WizardStepNames.Confirm);
        drafts.Seed(draft);

        var data = WizardCallbackData.Create();
        await wizard.HandleUpdateAsync(CallbackUpdate(data), draft, CancellationToken.None);

        Assert.Equal(WizardStepNames.Confirm, draft.Step);
        Assert.Contains("cb-1", messenger.AnsweredCallbacks);
    }
}
