using System;
using System.Threading;
using System.Threading.Tasks;
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", DateTime.UtcNow.AddHours(1));
        await sut.UpsertAsync(draft, CancellationToken.None);

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

        var loaded = await sut.GetActiveAsync(draft.Platform, draft.OwnerId, 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", DateTime.UtcNow.AddMinutes(-1));
        await sut.UpsertAsync(draft, CancellationToken.None);

        var loaded = await sut.GetActiveAsync(draft.Platform, draft.OwnerId, 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", DateTime.UtcNow.AddHours(1));
        await sut.UpsertAsync(draft, CancellationToken.None);

        var otherOwner = (long.Parse(draft.OwnerId, System.Globalization.CultureInfo.InvariantCulture) + 1)
            .ToString(System.Globalization.CultureInfo.InvariantCulture);
        var loaded = await sut.GetActiveAsync(draft.Platform, otherOwner, 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", DateTime.UtcNow.AddHours(1));
        var stale = NewDraft("Type", DateTime.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.Platform, fresh.OwnerId, CancellationToken.None);
        Assert.NotNull(loadedFresh);
    }

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