using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Tiku.Infrastructure.Security;

namespace Tiku.UnitTests.Security;

public sealed class DataProtectionKeyRingOptionsTests
{
    [Fact]
    public void Development_allows_an_unencrypted_key_ring()
    {
        var options = new DataProtectionKeyRingOptions();

        Assert.True(DataProtectionKeyRingOptions.BeValid(options, requireCertificate: false));
        Assert.Null(options.LoadCertificate(requireCertificate: false));
    }

    [Fact]
    public void Production_requires_a_certificate_path()
    {
        var options = new DataProtectionKeyRingOptions();

        Assert.False(DataProtectionKeyRingOptions.BeValid(options, requireCertificate: true));
        var exception = Assert.Throws<InvalidOperationException>(() =>
            options.LoadCertificate(requireCertificate: true));
        Assert.Contains("required outside Development", exception.Message, StringComparison.Ordinal);
    }

    [Fact]
    public void Application_name_is_always_required()
    {
        var options = new DataProtectionKeyRingOptions
        {
            ApplicationName = " ",
            CertificatePath = "/configured/key-ring.pfx"
        };

        Assert.False(DataProtectionKeyRingOptions.BeValid(options, requireCertificate: false));
        Assert.False(DataProtectionKeyRingOptions.BeValid(options, requireCertificate: true));
    }

    [Fact]
    public void Configured_certificate_file_must_be_loadable()
    {
        var options = new DataProtectionKeyRingOptions
        {
            CertificatePath = Path.Combine(
                Path.GetTempPath(),
                $"missing-data-protection-{Guid.NewGuid():N}.pfx")
        };

        Assert.True(DataProtectionKeyRingOptions.BeValid(options, requireCertificate: true));
        var exception = Assert.Throws<InvalidOperationException>(() =>
            options.LoadCertificate(requireCertificate: true));
        Assert.Contains("could not be loaded", exception.Message, StringComparison.Ordinal);
    }

    [Fact]
    public void Password_protected_pkcs12_certificate_with_private_key_is_loaded()
    {
        const string password = "unit-test-certificate-password";
        var certificatePath = Path.Combine(
            Path.GetTempPath(),
            $"data-protection-{Guid.NewGuid():N}.pfx");

        try
        {
            using var rsa = RSA.Create(2048);
            var request = new CertificateRequest(
                "CN=Tiku Data Protection Unit Test",
                rsa,
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pkcs1);
            using var certificate = request.CreateSelfSigned(
                DateTimeOffset.UtcNow.AddMinutes(-1),
                DateTimeOffset.UtcNow.AddDays(1));
            File.WriteAllBytes(certificatePath, certificate.Export(X509ContentType.Pfx, password));

            var options = new DataProtectionKeyRingOptions
            {
                CertificatePath = certificatePath,
                CertificatePassword = password
            };

            using var loaded = options.LoadCertificate(requireCertificate: true);
            Assert.NotNull(loaded);
            Assert.True(loaded.HasPrivateKey);
        }
        finally
        {
            File.Delete(certificatePath);
        }
    }
}
