// Copyright 2012-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Shouldly;
using ZB.MOM.NatsNet.Server.Internal;

namespace ZB.MOM.NatsNet.Server.Tests.Internal;

/// <summary>
/// Tests for server logging trace sanitization (RemovePassFromTrace, RemoveAuthTokenFromTrace).
/// Mirrors server/log_test.go — TestNoPasswordsFromConnectTrace, TestRemovePassFromTrace,
/// TestRemoveAuthTokenFromTrace.
/// </summary>
public class ServerLoggerTests
{
    // ---------------------------------------------------------------------------
    // T:2020 — TestNoPasswordsFromConnectTrace
    // ---------------------------------------------------------------------------

    /// <summary>
    /// Mirrors TestNoPasswordsFromConnectTrace.
    /// Verifies that a CONNECT trace with a password or auth_token does not
    /// expose the secret value after sanitization.
    /// </summary>
    [Fact] // T:2020
    public void NoPasswordsFromConnectTrace_ShouldSucceed()
    {
        const string connectWithPass =
            """CONNECT {"verbose":false,"pedantic":false,"user":"derek","pass":"s3cr3t","tls_required":false}""";
        const string connectWithToken =
            """CONNECT {"verbose":false,"auth_token":"secret-token","tls_required":false}""";

        ServerLogging.RemovePassFromTrace(connectWithPass).ShouldNotContain("s3cr3t");
        ServerLogging.RemoveAuthTokenFromTrace(connectWithToken).ShouldNotContain("secret-token");
    }

    // ---------------------------------------------------------------------------
    // T:2021 — TestRemovePassFromTrace
    // ---------------------------------------------------------------------------

    /// <summary>
    /// Mirrors TestRemovePassFromTrace — covers all test vectors from log_test.go.
    /// Each case verifies that RemovePassFromTrace redacts the first pass/password value
    /// with [REDACTED] while leaving other fields intact.
    /// </summary>
    [Theory] // T:2021
    [InlineData(
        "user and pass",
        "CONNECT {\"user\":\"derek\",\"pass\":\"s3cr3t\"}\r\n",
        "CONNECT {\"user\":\"derek\",\"pass\":\"[REDACTED]\"}\r\n")]
    [InlineData(
        "user and pass extra space",
        "CONNECT {\"user\":\"derek\",\"pass\":  \"s3cr3t\"}\r\n",
        "CONNECT {\"user\":\"derek\",\"pass\":  \"[REDACTED]\"}\r\n")]
    [InlineData(
        "user and pass is empty",
        "CONNECT {\"user\":\"derek\",\"pass\":\"\"}\r\n",
        "CONNECT {\"user\":\"derek\",\"pass\":\"[REDACTED]\"}\r\n")]
    [InlineData(
        "user and pass is empty whitespace",
        "CONNECT {\"user\":\"derek\",\"pass\":\"               \"}\r\n",
        "CONNECT {\"user\":\"derek\",\"pass\":\"[REDACTED]\"}\r\n")]
    [InlineData(
        "only pass",
        "CONNECT {\"pass\":\"s3cr3t\",}\r\n",
        "CONNECT {\"pass\":\"[REDACTED]\",}\r\n")]
    [InlineData(
        "complete connect",
        "CONNECT {\"echo\":true,\"verbose\":false,\"pedantic\":false,\"user\":\"foo\",\"pass\":\"s3cr3t\",\"tls_required\":false,\"name\":\"APM7JU94z77YzP6WTBEiuw\"}\r\n",
        "CONNECT {\"echo\":true,\"verbose\":false,\"pedantic\":false,\"user\":\"foo\",\"pass\":\"[REDACTED]\",\"tls_required\":false,\"name\":\"APM7JU94z77YzP6WTBEiuw\"}\r\n")]
    [InlineData(
        "user and pass are filtered",
        "CONNECT {\"user\":\"s3cr3t\",\"pass\":\"s3cr3t\"}\r\n",
        "CONNECT {\"user\":\"s3cr3t\",\"pass\":\"[REDACTED]\"}\r\n")]
    [InlineData(
        "single long password",
        "CONNECT {\"pass\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"}\r\n",
        "CONNECT {\"pass\":\"[REDACTED]\"}\r\n")]
    public void RemovePassFromTrace_ShouldSucceed(string name, string input, string expected)
    {
        _ = name; // used for test display only
        ServerLogging.RemovePassFromTrace(input).ShouldBe(expected);
    }

    // ---------------------------------------------------------------------------
    // T:2022 — TestRemoveAuthTokenFromTrace
    // ---------------------------------------------------------------------------

    /// <summary>
    /// Mirrors TestRemoveAuthTokenFromTrace — covers representative test vectors
    /// from log_test.go.  Each case verifies that RemoveAuthTokenFromTrace redacts
    /// the first auth_token value with [REDACTED].
    /// </summary>
    [Theory] // T:2022
    [InlineData(
        "user and auth_token",
        "CONNECT {\"user\":\"derek\",\"auth_token\":\"s3cr3t\"}\r\n",
        "CONNECT {\"user\":\"derek\",\"auth_token\":\"[REDACTED]\"}\r\n")]
    [InlineData(
        "user and auth_token extra space",
        "CONNECT {\"user\":\"derek\",\"auth_token\":  \"s3cr3t\"}\r\n",
        "CONNECT {\"user\":\"derek\",\"auth_token\":  \"[REDACTED]\"}\r\n")]
    [InlineData(
        "user and auth_token is empty",
        "CONNECT {\"user\":\"derek\",\"auth_token\":\"\"}\r\n",
        "CONNECT {\"user\":\"derek\",\"auth_token\":\"[REDACTED]\"}\r\n")]
    [InlineData(
        "only auth_token",
        "CONNECT {\"auth_token\":\"s3cr3t\",}\r\n",
        "CONNECT {\"auth_token\":\"[REDACTED]\",}\r\n")]
    [InlineData(
        "complete connect",
        "CONNECT {\"echo\":true,\"verbose\":false,\"pedantic\":false,\"auth_token\":\"s3cr3t\",\"tls_required\":false,\"name\":\"APM7JU94z77YzP6WTBEiuw\"}\r\n",
        "CONNECT {\"echo\":true,\"verbose\":false,\"pedantic\":false,\"auth_token\":\"[REDACTED]\",\"tls_required\":false,\"name\":\"APM7JU94z77YzP6WTBEiuw\"}\r\n")]
    [InlineData(
        "user and token are filtered",
        "CONNECT {\"user\":\"s3cr3t\",\"auth_token\":\"s3cr3t\"}\r\n",
        "CONNECT {\"user\":\"s3cr3t\",\"auth_token\":\"[REDACTED]\"}\r\n")]
    [InlineData(
        "single long token",
        "CONNECT {\"auth_token\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"}\r\n",
        "CONNECT {\"auth_token\":\"[REDACTED]\"}\r\n")]
    public void RemoveAuthTokenFromTrace_ShouldSucceed(string name, string input, string expected)
    {
        _ = name; // used for test display only
        ServerLogging.RemoveAuthTokenFromTrace(input).ShouldBe(expected);
    }
}
