using FluentAssertions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using SIGCM2.Application.Audit;
using SIGCM2.Infrastructure;
using Xunit;

namespace SIGCM2.Application.Tests.Infrastructure.Audit;

/// UDT-010 Batch 3 — AuditOptions binding smoke tests.
/// Validates that AddInfrastructure binds AuditOptions from the "Audit" config section
/// and falls back to the POCO defaults when the section is absent.
public sealed class AuditOptionsBindingTests
{
    private static IServiceProvider BuildProvider(IEnumerable<KeyValuePair<string, string?>>? overrides = null)
    {
        // Minimum required config for AddInfrastructure to succeed.
        var inMemory = new Dictionary<string, string?>
        {
            ["ConnectionStrings:SqlServer"] = "Server=nowhere;Database=x;Integrated Security=true;",
            ["Jwt:Issuer"] = "test",
            ["Jwt:Audience"] = "test",
            ["Jwt:AccessTokenMinutes"] = "60",
            ["Jwt:RefreshTokenDays"] = "7",
            ["Jwt:PrivateKeyPath"] = "unused-in-this-test.pem",
            ["Jwt:PublicKeyPath"] = "unused-in-this-test.pem",
        };

        if (overrides is not null)
            foreach (var kv in overrides)
                inMemory[kv.Key] = kv.Value;

        var config = new ConfigurationBuilder().AddInMemoryCollection(inMemory).Build();
        var services = new ServiceCollection();
        services.AddInfrastructure(config);
        return services.BuildServiceProvider();
    }

    [Fact]
    public void AuditOptions_WithoutConfigSection_UsesPocoDefaults()
    {
        using var sp = (ServiceProvider)BuildProvider();

        var opts = sp.GetRequiredService<IOptions<AuditOptions>>().Value;

        opts.SanitizedKeys.Should().Contain("password");
        opts.SanitizedKeys.Should().Contain("refreshToken");
        opts.SanitizedKeys.Should().Contain("apiKey");
    }

    [Fact]
    public void AuditOptions_WithConfigSection_AddsToDefaults_PerIConfigurationArrayBinding()
    {
        // IConfiguration array binding is ADDITIVE, not REPLACE: config values at indices 0..N
        // overwrite those indices but defaults beyond N are preserved. This is intended for
        // AuditOptions — extensibility is additive (append, not replace).
        using var sp = (ServiceProvider)BuildProvider(new[]
        {
            new KeyValuePair<string, string?>("Audit:SanitizedKeys:11", "customSecret"),
            new KeyValuePair<string, string?>("Audit:SanitizedKeys:12", "internalToken"),
        });

        var opts = sp.GetRequiredService<IOptions<AuditOptions>>().Value;

        // The 11 defaults remain + the 2 extras appear at the configured indices.
        opts.SanitizedKeys.Should().Contain("password");      // default survived
        opts.SanitizedKeys.Should().Contain("customSecret");  // appended via config
        opts.SanitizedKeys.Should().Contain("internalToken"); // appended via config
    }
}
