using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using StellaOps.Scanner.Queue.Nats;
using StellaOps.Scanner.Queue.Redis;

namespace StellaOps.Scanner.Queue;

public static class ScannerQueueServiceCollectionExtensions
{
    public static IServiceCollection AddScannerQueue(
        this IServiceCollection services,
        IConfiguration configuration,
        string sectionName = "scanner:queue")
    {
        ArgumentNullException.ThrowIfNull(services);
        ArgumentNullException.ThrowIfNull(configuration);

        var options = new ScannerQueueOptions();
        configuration.GetSection(sectionName).Bind(options);

        services.TryAddSingleton(TimeProvider.System);
        services.AddSingleton(options);

        services.AddSingleton<IScanQueue>(sp =>
        {
            var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
            var timeProvider = sp.GetService<TimeProvider>() ?? TimeProvider.System;

            return options.Kind switch
            {
                QueueTransportKind.Redis => new RedisScanQueue(
                    options,
                    options.Redis,
                    loggerFactory.CreateLogger<RedisScanQueue>(),
                    timeProvider),
                QueueTransportKind.Nats => new NatsScanQueue(
                    options,
                    options.Nats,
                    loggerFactory.CreateLogger<NatsScanQueue>(),
                    timeProvider),
                _ => throw new InvalidOperationException($"Unsupported queue transport kind '{options.Kind}'.")
            };
        });

        services.AddSingleton<ScannerQueueHealthCheck>();

        return services;
    }

    public static IHealthChecksBuilder AddScannerQueueHealthCheck(
        this IHealthChecksBuilder builder)
    {
        ArgumentNullException.ThrowIfNull(builder);

        builder.Services.TryAddSingleton<ScannerQueueHealthCheck>();
        builder.AddCheck<ScannerQueueHealthCheck>(
            name: "scanner-queue",
            failureStatus: HealthStatus.Unhealthy,
            tags: new[] { "scanner", "queue" });

        return builder;
    }
}
