using GmRelay.Shared.Features.Sessions.CreateSession.Wizard;
using Npgsql;

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

[Collection(WizardDraftRepositoryCollection.Name)]
public sealed class WizardDraftRepositoryTests(WizardDraftRepositoryFixture fixture)
{
    [Fact]
    public async Task UpsertAsync_InsertThenUpdate_PreservesSingleRow()
    {
        var connectionString = await fixture.CreateSchemaDatabaseAsync();
        await using var dataSource = NpgsqlDataSource.Create(connectionString);
        var sut = new WizardDraftRepository(dataSource);

        var draft = NewDraft("Type", DateTimeOffset.UtcNow.AddHours(1));
        await sut.UpsertAsync(draft, CancellationToken.None);

        draft.Step = "Title";
        draft.UpdatedAt = DateTimeOffset.UtcNow.AddSeconds(1);
        await sut.UpsertAsync(draft, CancellationToken.None);

        var loaded = await sut.GetActiveAsync(draft.ChatId, draft.MessageThreadId, draft.OwnerTelegramId, CancellationToken.None);
        Assert.NotNull(loaded);
        Assert.Equal("Title", loaded!.Step);
    }

    [Fact]
    public async Task GetActiveAsync_ExpiredDraft_ReturnsNull()
    {
        var connectionString = await fixture.CreateSchemaDatabaseAsync();
        await using var dataSource = NpgsqlDataSource.Create(connectionString);
        var sut = new WizardDraftRepository(dataSource);

        var draft = NewDraft("Type", DateTimeOffset.UtcNow.AddMinutes(-1));
        await sut.UpsertAsync(draft, CancellationToken.None);

        var loaded = await sut.GetActiveAsync(draft.ChatId, draft.MessageThreadId, draft.OwnerTelegramId, CancellationToken.None);
        Assert.Null(loaded);
    }

    [Fact]
    public async Task GetActiveAsync_DifferentOwner_ReturnsNull()
    {
        var connectionString = await fixture.CreateSchemaDatabaseAsync();
        await using var dataSource = NpgsqlDataSource.Create(connectionString);
        var sut = new WizardDraftRepository(dataSource);

        var draft = NewDraft("Type", DateTimeOffset.UtcNow.AddHours(1));
        await sut.UpsertAsync(draft, CancellationToken.None);

        var loaded = await sut.GetActiveAsync(draft.ChatId, draft.MessageThreadId, ownerTelegramId: draft.OwnerTelegramId + 1, CancellationToken.None);
        Assert.Null(loaded);
    }

    [Fact]
    public async Task DeleteExpiredAsync_DeletesOnlyExpired()
    {
        var connectionString = await fixture.CreateSchemaDatabaseAsync();
        await using var dataSource = NpgsqlDataSource.Create(connectionString);
        var sut = new WizardDraftRepository(dataSource);

        var fresh = NewDraft("Type", DateTimeOffset.UtcNow.AddHours(1));
        var stale = NewDraft("Type", DateTimeOffset.UtcNow.AddMinutes(-1));
        stale.Id = Guid.NewGuid();
        await sut.UpsertAsync(fresh, CancellationToken.None);
        await sut.UpsertAsync(stale, CancellationToken.None);

        var deleted = await sut.DeleteExpiredAsync(CancellationToken.None);
        Assert.Equal(1, deleted);

        var loadedFresh = await sut.GetActiveAsync(fresh.ChatId, fresh.MessageThreadId, fresh.OwnerTelegramId, CancellationToken.None);
        Assert.NotNull(loadedFresh);
    }

    private static WizardDraft NewDraft(string step, DateTimeOffset expiresAt) => new()
    {
        Id = Guid.NewGuid(),
        ChatId = 42,
        MessageThreadId = null,
        OwnerTelegramId = 100,
        Step = step,
        PayloadJson = "{}",
        CreatedAt = DateTimeOffset.UtcNow,
        UpdatedAt = DateTimeOffset.UtcNow,
        ExpiresAt = expiresAt,
    };
}
