using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Shouldly;
using Xunit;

namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;

[Trait("Category", "Unit")]
public sealed class OpcUaClientCertAuthTests
{
    /// <summary>
    /// Verifies that BuildCertificateIdentity rejects missing certificate path.
    /// </summary>
    [Fact]
    public void BuildCertificateIdentity_rejects_missing_path()
    {
        var opts = new OpcUaClientDriverOptions { AuthType = OpcUaAuthType.Certificate };
        Should.Throw<InvalidOperationException>(() => OpcUaClientDriver.BuildCertificateIdentity(opts))
            .Message.ShouldContain("UserCertificatePath");
    }

    /// <summary>
    /// Verifies that BuildCertificateIdentity rejects nonexistent certificate file.
    /// </summary>
    [Fact]
    public void BuildCertificateIdentity_rejects_nonexistent_file()
    {
        var opts = new OpcUaClientDriverOptions
        {
            AuthType = OpcUaAuthType.Certificate,
            UserCertificatePath = Path.Combine(Path.GetTempPath(), $"does-not-exist-{Guid.NewGuid():N}.pfx"),
        };
        Should.Throw<FileNotFoundException>(() => OpcUaClientDriver.BuildCertificateIdentity(opts));
    }

    /// <summary>
    /// Verifies that BuildCertificateIdentity loads a valid PFX with private key.
    /// </summary>
    [Fact]
    public void BuildCertificateIdentity_loads_a_valid_PFX_with_private_key()
    {
        // Generate a self-signed cert on the fly so the test doesn't ship a static PFX.
        // The driver doesn't care about the issuer — just needs a cert with a private key.
        using var rsa = RSA.Create(2048);
        var req = new CertificateRequest("CN=OpcUaClientCertAuthTests", rsa,
            HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        var cert = req.CreateSelfSigned(DateTimeOffset.UtcNow.AddMinutes(-5), DateTimeOffset.UtcNow.AddHours(1));

        var tmpPath = Path.Combine(Path.GetTempPath(), $"opcua-cert-test-{Guid.NewGuid():N}.pfx");
        File.WriteAllBytes(tmpPath, cert.Export(X509ContentType.Pfx, "testpw"));
        try
        {
            var opts = new OpcUaClientDriverOptions
            {
                AuthType = OpcUaAuthType.Certificate,
                UserCertificatePath = tmpPath,
                UserCertificatePassword = "testpw",
            };
            var identity = OpcUaClientDriver.BuildCertificateIdentity(opts);
            identity.ShouldNotBeNull();
            identity.TokenType.ShouldBe(Opc.Ua.UserTokenType.Certificate);
        }
        finally
        {
            try { File.Delete(tmpPath); } catch { /* best-effort */ }
        }
    }
}
