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

/// <summary>
/// Redacts sensitive information from log entries.
/// </summary>
public static class GatewayLogRedactor
{
    /// <summary>Placeholder for redacted values.</summary>
    public const string RedactedValue = "[redacted]";

    private static readonly HashSet<string> SensitiveCommandMethods = new(StringComparer.OrdinalIgnoreCase)
    {
        "AuthenticateUser",
        "WriteSecured",
        "WriteSecured2"
    };

    /// <summary>
    /// Determines whether a command method bears credentials.
    /// </summary>
    /// <param name="commandMethod">The command method name to check.</param>
    public static bool IsCredentialBearingCommand(string? commandMethod)
    {
        return commandMethod is not null
            && SensitiveCommandMethods.Contains(commandMethod);
    }

    /// <summary>
    /// Redacts the API key secret portion of a Bearer authorization header.
    /// </summary>
    /// <param name="authorizationHeader">The authorization header value to redact.</param>
    public static string? RedactApiKey(string? authorizationHeader)
    {
        if (string.IsNullOrWhiteSpace(authorizationHeader))
        {
            return authorizationHeader;
        }

        const string bearerPrefix = "Bearer ";
        if (!authorizationHeader.StartsWith(bearerPrefix, StringComparison.OrdinalIgnoreCase))
        {
            return RedactedValue;
        }

        string token = authorizationHeader[bearerPrefix.Length..].Trim();

        if (!token.StartsWith("mxgw_", StringComparison.OrdinalIgnoreCase))
        {
            return $"{bearerPrefix}{RedactedValue}";
        }

        string[] tokenParts = token.Split('_', 3, StringSplitOptions.RemoveEmptyEntries);
        if (tokenParts.Length < 2)
        {
            return $"{bearerPrefix}mxgw_{RedactedValue}";
        }

        return $"{bearerPrefix}mxgw_{tokenParts[1]}_{RedactedValue}";
    }

    /// <summary>
    /// Redacts the client identity if it contains an API key.
    /// </summary>
    /// <param name="clientIdentity">The client identity string to redact.</param>
    public static string? RedactClientIdentity(string? clientIdentity)
    {
        if (string.IsNullOrWhiteSpace(clientIdentity))
        {
            return clientIdentity;
        }

        return clientIdentity.Contains("mxgw_", StringComparison.OrdinalIgnoreCase)
            ? RedactApiKey(clientIdentity)
            : clientIdentity;
    }

    /// <summary>
    /// Redacts a command value if it contains credentials or value logging is disabled.
    /// </summary>
    /// <param name="commandMethod">The command method name to check for credentials.</param>
    /// <param name="value">The command value to redact.</param>
    /// <param name="valueLoggingEnabled">Whether value logging is enabled.</param>
    public static object? RedactCommandValue(
        string? commandMethod,
        object? value,
        bool valueLoggingEnabled = false)
    {
        if (value is null)
        {
            return null;
        }

        if (!valueLoggingEnabled || IsCredentialBearingCommand(commandMethod))
        {
            return RedactedValue;
        }

        return value;
    }
}
