using Jiaowu.Api.Domain.System;

namespace Jiaowu.Api.Infrastructure.BackgroundJobs;

public sealed class InMemoryBackgroundJobWorker(
    InMemoryBackgroundJobTransport transport,
    BackgroundJobRunner runner,
    BackgroundJobOptions options,
    ILogger<InMemoryBackgroundJobWorker> logger) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var workers = Enum.GetValues<BackgroundJobKind>()
            .SelectMany(kind => Enumerable.Range(
                    0,
                    options.ConsumerConcurrency(kind))
                .Select(_ => ConsumeAsync(kind, stoppingToken)))
            .ToArray();

        try
        {
            await Task.WhenAll(workers);
        }
        catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
        {
            logger.LogInformation("In-memory background job worker is stopping.");
        }
    }

    private async Task ConsumeAsync(
        BackgroundJobKind kind,
        CancellationToken cancellationToken)
    {
        await foreach (var message in transport.ReadAllAsync(
                           kind,
                           cancellationToken))
        {
            var result = await runner.RunAsync(message, cancellationToken);
            if (result.Outcome != BackgroundJobRunOutcome.Retry)
                continue;

            await Task.Delay(result.RetryAfter, cancellationToken);
            await transport.PublishAsync(message, cancellationToken);
        }
    }
}
