using ZB.MOM.WW.MxGateway.Server.Diagnostics;

namespace ZB.MOM.WW.MxGateway.Tests.Diagnostics;

public sealed class GatewayLogRedactorTests
{
    /// <summary>Verifies that RedactApiKey preserves the key ID and removes the secret.</summary>
    [Fact]
    public void RedactApiKey_PreservesKeyIdAndRemovesSecret()
    {
        string? redacted = GatewayLogRedactor.RedactApiKey("Bearer mxgw_operator01_super-secret");

        Assert.Equal("Bearer mxgw_operator01_[redacted]", redacted);
        Assert.DoesNotContain("super-secret", redacted);
    }

    /// <summary>Verifies that RedactApiKey removes secrets containing underscores.</summary>
    [Fact]
    public void RedactApiKey_RemovesSecretContainingUnderscores()
    {
        string? redacted = GatewayLogRedactor.RedactApiKey("Bearer mxgw_operator01_super_secret_value");

        Assert.Equal("Bearer mxgw_operator01_[redacted]", redacted);
        Assert.DoesNotContain("super_secret_value", redacted);
    }

    /// <summary>Verifies that IsCredentialBearingCommand identifies credential-bearing MXAccess commands.</summary>
    /// <param name="commandMethod">Name of the MXAccess command method.</param>
    [Theory]
    [InlineData("AuthenticateUser")]
    [InlineData("WriteSecured")]
    [InlineData("WriteSecured2")]
    public void IsCredentialBearingCommand_IdentifiesSensitiveMxAccessCommands(string commandMethod)
    {
        Assert.True(GatewayLogRedactor.IsCredentialBearingCommand(commandMethod));
    }

    /// <summary>Verifies that RedactCommandValue does not log raw values by default.</summary>
    [Fact]
    public void RedactCommandValue_DoesNotLogRawValuesByDefault()
    {
        object? redacted = GatewayLogRedactor.RedactCommandValue("Write", "plaintext-tag-value");

        Assert.Equal("[redacted]", redacted);
    }

    /// <summary>Verifies that RedactCommandValue redacts secured writes even when value logging is enabled.</summary>
    [Fact]
    public void RedactCommandValue_RedactsSecuredWriteEvenWhenValueLoggingIsEnabled()
    {
        object? redacted = GatewayLogRedactor.RedactCommandValue(
            "WriteSecured",
            "credential-bearing-value",
            valueLoggingEnabled: true);

        Assert.Equal("[redacted]", redacted);
    }

    /// <summary>Verifies that RedactCommandValue allows non-sensitive values only when value logging is enabled.</summary>
    [Fact]
    public void RedactCommandValue_AllowsNonSensitiveValueOnlyWhenValueLoggingIsEnabled()
    {
        object? redacted = GatewayLogRedactor.RedactCommandValue(
            "Write",
            "diagnostic-value",
            valueLoggingEnabled: true);

        Assert.Equal("diagnostic-value", redacted);
    }

    /// <summary>Verifies that LogScope redacts client identity before scope state is created.</summary>
    [Fact]
    public void LogScope_RedactsClientIdentityBeforeScopeStateIsCreated()
    {
        GatewayLogScope scope = new(
            SessionId: "session-1",
            WorkerProcessId: 1234,
            CorrelationId: 99,
            CommandMethod: "AuthenticateUser",
            ClientIdentity: "Bearer mxgw_admin_secret");

        IReadOnlyDictionary<string, object?> values = scope.ToDictionary();

        Assert.Equal("session-1", values["SessionId"]);
        Assert.Equal(1234, values["WorkerProcessId"]);
        Assert.Equal((ulong)99, values["CorrelationId"]);
        Assert.Equal("AuthenticateUser", values["CommandMethod"]);
        Assert.Equal("Bearer mxgw_admin_[redacted]", values["ClientIdentity"]);
    }
}
