using Microsoft.AspNetCore.DataProtection;
using Tiku.Infrastructure.Persistence;
using Tiku.Infrastructure.Security;

namespace Tiku.Api.Configuration;

internal static class DataProtectionExtensions
{
    internal static IServiceCollection AddApiDataProtection(
        this IServiceCollection services,
        IConfiguration configuration,
        IHostEnvironment environment)
    {
        var requireProtectedKeys = !environment.IsDevelopment();
        services.AddOptions<DataProtectionKeyRingOptions>()
            .Bind(configuration.GetSection(DataProtectionKeyRingOptions.SectionName))
            .PostConfigure(options => ApplyEnvironmentOverrides(options, configuration))
            .Validate(
                options => DataProtectionKeyRingOptions.BeValid(options, requireProtectedKeys),
                "Data Protection requires an application name and, outside Development, an X509 certificate path.")
            .ValidateOnStart();

        var keyRingOptions = configuration
            .GetSection(DataProtectionKeyRingOptions.SectionName)
            .Get<DataProtectionKeyRingOptions>() ?? new DataProtectionKeyRingOptions();
        ApplyEnvironmentOverrides(keyRingOptions, configuration);
        if (!DataProtectionKeyRingOptions.BeValid(keyRingOptions, requireProtectedKeys))
            throw new InvalidOperationException(
                "Data Protection requires an application name and, outside Development, an X509 certificate path.");

        var dataProtection = services
            .AddDataProtection()
            .SetApplicationName(keyRingOptions.ApplicationName.Trim())
            .PersistKeysToDbContext<TikuDbContext>();
        var certificate = keyRingOptions.LoadCertificate(requireProtectedKeys);
        if (certificate is not null) dataProtection.ProtectKeysWithCertificate(certificate);

        return services;
    }

    private static void ApplyEnvironmentOverrides(
        DataProtectionKeyRingOptions options,
        IConfiguration configuration)
    {
        options.ApplicationName =
            configuration["TIKU_DATA_PROTECTION_APPLICATION_NAME"] ?? options.ApplicationName;
        options.CertificatePath =
            configuration["TIKU_DATA_PROTECTION_CERTIFICATE_PATH"] ?? options.CertificatePath;
        options.CertificatePassword =
            configuration["TIKU_DATA_PROTECTION_CERTIFICATE_PASSWORD"] ?? options.CertificatePassword;
    }
}