using System;
using System.Threading;
using System.Threading.Tasks;
using GmRelay.Bot.Features.Sessions.CreateSession.Wizard;
using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using SharedDraft = GmRelay.Shared.Features.Sessions.CreateSession.Wizard;

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

/// <summary>
/// Verifies the cleanup background service: each tick should call the draft
/// repository to delete expired drafts and must not propagate repository
/// failures (a transient DB blip should not bring the worker down).
/// </summary>
public sealed class WizardDraftCleanupServiceTests
{
    [Fact]
    public async Task RunOnceAsync_DeletesExpiredDrafts()
    {
        var drafts = Substitute.For<SharedDraft.IWizardDraftRepository>();
        drafts.DeleteExpiredAsync(Arg.Any<CancellationToken>()).Returns(7);

        var sut = new WizardDraftCleanupService(drafts, NullLogger<WizardDraftCleanupService>.Instance);

        await sut.RunOnceAsync(CancellationToken.None);

        await drafts.Received(1).DeleteExpiredAsync(Arg.Any<CancellationToken>());
    }

    [Fact]
    public async Task RunOnceAsync_OnRepositoryError_DoesNotThrow()
    {
        var drafts = Substitute.For<SharedDraft.IWizardDraftRepository>();
        drafts.DeleteExpiredAsync(Arg.Any<CancellationToken>())
            .ThrowsAsync(new InvalidOperationException("boom"));

        var sut = new WizardDraftCleanupService(drafts, NullLogger<WizardDraftCleanupService>.Instance);

        // Should swallow the exception — cleanup is best-effort.
        await sut.RunOnceAsync(CancellationToken.None);

        await drafts.Received(1).DeleteExpiredAsync(Arg.Any<CancellationToken>());
    }
}
