using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using NATS.Server.Auth;

namespace NATS.Server.Auth.Tests.Auth;

public class TlsMapAuthParityBatch1Tests
{
    [Fact]
    public void GetTlsAuthDcs_extracts_domain_components_from_subject()
    {
        using var cert = CreateSelfSignedCert("CN=alice,DC=example,DC=com");

        TlsMapAuthenticator.GetTlsAuthDcs(cert.SubjectName).ShouldBe("DC=example,DC=com");
    }

    [Fact]
    public void DnsAltNameLabels_and_matches_follow_rfc6125_shape()
    {
        var labels = TlsMapAuthenticator.DnsAltNameLabels("*.Example.COM");
        labels.ShouldBe(["*", "example", "com"]);

        TlsMapAuthenticator.DnsAltNameMatches(labels, [new Uri("nats://node.example.com:6222")]).ShouldBeTrue();
        TlsMapAuthenticator.DnsAltNameMatches(labels, [new Uri("nats://a.b.example.com:6222")]).ShouldBeFalse();
    }

    [Fact]
    public void Authenticate_can_match_user_from_email_or_dns_san()
    {
        using var cert = CreateSelfSignedCertWithSan("CN=ignored", "ops@example.com", "router.example.com");
        var auth = new TlsMapAuthenticator([
            new User { Username = "ops@example.com", Password = "" },
            new User { Username = "router.example.com", Password = "" },
        ]);

        var ctx = new ClientAuthContext
        {
            Opts = new Protocol.ClientOptions(),
            Nonce = [],
            ClientCertificate = cert,
        };

        var result = auth.Authenticate(ctx);
        result.ShouldNotBeNull();
        (result.Identity == "ops@example.com" || result.Identity == "router.example.com").ShouldBeTrue();
    }

    private static X509Certificate2 CreateSelfSignedCert(string subjectName)
    {
        using var rsa = RSA.Create(2048);
        var req = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        return req.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(1));
    }

    private static X509Certificate2 CreateSelfSignedCertWithSan(string subjectName, string email, string dns)
    {
        using var rsa = RSA.Create(2048);
        var req = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        var sans = new SubjectAlternativeNameBuilder();
        sans.AddEmailAddress(email);
        sans.AddDnsName(dns);
        req.CertificateExtensions.Add(sans.Build());
        return req.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(1));
    }
}
