using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using StellaOps.Feedser.Core;
using StellaOps.Feedser.Merge.Jobs;
using StellaOps.Feedser.Merge.Options;
using StellaOps.Feedser.Merge.Services;

namespace StellaOps.Feedser.Merge;

public static class MergeServiceCollectionExtensions
{
    public static IServiceCollection AddMergeModule(this IServiceCollection services, IConfiguration configuration)
    {
        ArgumentNullException.ThrowIfNull(services);
        ArgumentNullException.ThrowIfNull(configuration);

        services.TryAddSingleton<CanonicalHashCalculator>();
        services.TryAddSingleton<CanonicalMerger>();
        services.TryAddSingleton<AliasGraphResolver>();
        services.TryAddSingleton<AffectedPackagePrecedenceResolver>(sp =>
        {
            var options = configuration.GetSection("feedser:merge:precedence").Get<AdvisoryPrecedenceOptions>();
            return options is null ? new AffectedPackagePrecedenceResolver() : new AffectedPackagePrecedenceResolver(options);
        });

        services.TryAddSingleton<AdvisoryPrecedenceMerger>(sp =>
        {
            var resolver = sp.GetRequiredService<AffectedPackagePrecedenceResolver>();
            var options = configuration.GetSection("feedser:merge:precedence").Get<AdvisoryPrecedenceOptions>();
            var timeProvider = sp.GetRequiredService<TimeProvider>();
            var logger = sp.GetRequiredService<ILogger<AdvisoryPrecedenceMerger>>();
            return new AdvisoryPrecedenceMerger(resolver, options, timeProvider, logger);
        });

        services.TryAddSingleton<MergeEventWriter>();
        services.TryAddSingleton<AdvisoryMergeService>();
        services.AddTransient<MergeReconcileJob>();

        return services;
    }
}
