// Copyright 2012-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0
namespace ZB.MOM.NatsNet.Server.Tests.Auth;

using ZB.MOM.NatsNet.Server;
using ZB.MOM.NatsNet.Server.Auth;
using Shouldly;
using Xunit;

public class AuthHandlerExtendedTests
{
    [Fact]
    public void ValidateProxies_ProxyRequiredWithoutProtocol_ReturnsError()
    {
        var opts = new ServerOptions { ProxyRequired = true, ProxyProtocol = false };
        var err = AuthHandler.ValidateProxies(opts);
        err.ShouldNotBeNull();
        err!.Message.ShouldContain("proxy_required");
    }

    [Fact]
    public void ValidateProxies_ProxyRequiredWithProtocol_ReturnsNull()
    {
        var opts = new ServerOptions { ProxyRequired = true, ProxyProtocol = true };
        var err = AuthHandler.ValidateProxies(opts);
        err.ShouldBeNull();
    }

    [Fact]
    public void GetAuthErrClosedState_ProxyNotTrusted_ReturnsProxyNotTrusted()
    {
        var err = new AuthProxyNotTrustedException();
        AuthHandler.GetAuthErrClosedState(err).ShouldBe(ClosedState.ProxyNotTrusted);
    }

    [Fact]
    public void GetAuthErrClosedState_ProxyRequired_ReturnsProxyRequired()
    {
        var err = new AuthProxyRequiredException();
        AuthHandler.GetAuthErrClosedState(err).ShouldBe(ClosedState.ProxyRequired);
    }

    [Fact]
    public void GetAuthErrClosedState_OtherError_ReturnsAuthenticationViolation()
    {
        var err = new InvalidOperationException("bad credentials");
        AuthHandler.GetAuthErrClosedState(err).ShouldBe(ClosedState.AuthenticationViolation);
    }

    [Fact]
    public void GetAuthErrClosedState_NullError_ReturnsAuthenticationViolation()
    {
        AuthHandler.GetAuthErrClosedState(null).ShouldBe(ClosedState.AuthenticationViolation);
    }

    [Fact]
    public void CheckClientTlsCertSubject_NullCert_ReturnsFalse()
    {
        AuthHandler.CheckClientTlsCertSubject(null, _ => true).ShouldBeFalse();
    }

    [Fact]
    public void ProcessUserPermissionsTemplate_ExpandsAccountVariable()
    {
        var lim = new Permissions
        {
            Publish = new SubjectPermission { Allow = new List<string> { "{{account}}.events" } },
        };
        var (result, err) = AuthHandler.ProcessUserPermissionsTemplate(lim, "myaccount", null);
        err.ShouldBeNull();
        result.Publish!.Allow![0].ShouldBe("myaccount.events");
    }

    [Fact]
    public void ProcessUserPermissionsTemplate_ExpandsTagVariable()
    {
        var lim = new Permissions
        {
            Subscribe = new SubjectPermission { Allow = new List<string> { "{{tag.region}}.alerts" } },
        };
        var tags = new Dictionary<string, string> { ["region"] = "us-east" };
        var (result, err) = AuthHandler.ProcessUserPermissionsTemplate(lim, "acc", tags);
        err.ShouldBeNull();
        result.Subscribe!.Allow![0].ShouldBe("us-east.alerts");
    }
}

public class JwtProcessorOperatorTests
{
    [Fact]
    public void ReadOperatorJwtInternal_EmptyString_ReturnsError()
    {
        var (claims, err) = JwtProcessor.ReadOperatorJwtInternal(string.Empty);
        claims.ShouldBeNull();
        err.ShouldNotBeNull();
    }

    [Fact]
    public void ReadOperatorJwtInternal_InvalidPrefix_ReturnsFormatError()
    {
        var (claims, err) = JwtProcessor.ReadOperatorJwtInternal("NOTAJWT.payload.sig");
        claims.ShouldBeNull();
        err.ShouldBeOfType<FormatException>();
    }

    [Fact]
    public void ReadOperatorJwt_FileNotFound_ReturnsError()
    {
        var (claims, err) = JwtProcessor.ReadOperatorJwt("/nonexistent/operator.jwt");
        claims.ShouldBeNull();
        err.ShouldBeOfType<IOException>();
    }

    [Fact]
    public void ValidateTrustedOperators_EmptyList_ReturnsNull()
    {
        var opts = new ServerOptions();
        JwtProcessor.ValidateTrustedOperators(opts).ShouldBeNull();
    }
}
