using System;
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using StellaOps.DependencyInjection;
using StellaOps.Feedser.Core.Jobs;
using StellaOps.Feedser.Exporter.Json;
using StellaOps.Feedser.Storage.Mongo.Exporting;

namespace StellaOps.Feedser.Exporter.TrivyDb;

public sealed class TrivyDbExporterDependencyInjectionRoutine : IDependencyInjectionRoutine
{
    private const string ConfigurationSection = "feedser:exporters:trivyDb";

    public IServiceCollection Register(IServiceCollection services, IConfiguration configuration)
    {
        ArgumentNullException.ThrowIfNull(services);
        ArgumentNullException.ThrowIfNull(configuration);

        services.TryAddSingleton<IJsonExportPathResolver, VulnListJsonExportPathResolver>();
        services.TryAddSingleton<ExportStateManager>();

        services.AddOptions<TrivyDbExportOptions>()
            .Bind(configuration.GetSection(ConfigurationSection))
            .PostConfigure(static options =>
            {
                options.OutputRoot = Normalize(options.OutputRoot, Path.Combine("exports", "trivy"));
                options.Json.OutputRoot = Normalize(options.Json.OutputRoot, Path.Combine("exports", "trivy", "tree"));
                options.TagFormat = string.IsNullOrWhiteSpace(options.TagFormat) ? "yyyyMMdd'T'HHmmss'Z'" : options.TagFormat;
                options.DatabaseVersionFormat = string.IsNullOrWhiteSpace(options.DatabaseVersionFormat) ? "yyyyMMdd'T'HHmmss'Z'" : options.DatabaseVersionFormat;
                options.ReferencePrefix = string.IsNullOrWhiteSpace(options.ReferencePrefix) ? "feedser/trivy" : options.ReferencePrefix;
            });

        services.AddSingleton<TrivyDbPackageBuilder>();
        services.AddSingleton<TrivyDbOciWriter>();
        services.AddSingleton<TrivyDbExportPlanner>();
        services.AddSingleton<ITrivyDbBuilder, TrivyDbBoltBuilder>();
        services.AddSingleton<ITrivyDbOrasPusher, TrivyDbOrasPusher>();
        services.AddSingleton<TrivyDbFeedExporter>();
        services.AddTransient<TrivyDbExportJob>();

        services.PostConfigure<JobSchedulerOptions>(options =>
        {
            if (!options.Definitions.ContainsKey(TrivyDbExportJob.JobKind))
            {
                options.Definitions[TrivyDbExportJob.JobKind] = new JobDefinition(
                    TrivyDbExportJob.JobKind,
                    typeof(TrivyDbExportJob),
                    TrivyDbExportJob.DefaultTimeout,
                    TrivyDbExportJob.DefaultLeaseDuration,
                    null,
                    true);
            }
        });

        return services;
    }

    private static string Normalize(string? value, string fallback)
        => string.IsNullOrWhiteSpace(value) ? fallback : value;
}
