<?php
/**
 * Shared Secret Redactor
 *
 * Roadmap item #33: guarantee that captcha secrets never land in `error_log`
 * or any module-originated log line. Every captcha module that decrypts a
 * secret runs its API responses through {@see self::redact()} before logging
 * or surfacing the payload.
 *
 * Also exposes a minimal "safe log" helper that only writes when WP_DEBUG and
 * WP_DEBUG_LOG are on, so production installs stay silent by default.
 *
 * @package WP_PowerSuite\Captcha\Shared
 * @since 1.1.0
 */

namespace WP_PowerSuite\Captcha\Shared;

/**
 * Secret redactor utility.
 */
final class SecretRedactor {

	/**
	 * Return a copy of `$message` with any value listed in `$secrets` replaced
	 * with `[REDACTED]`. Short secrets (< 8 chars) are skipped to avoid
	 * catastrophic false positives on common tokens.
	 *
	 * @param string        $message Arbitrary log/text message.
	 * @param array<string> $secrets Known secret strings to scrub.
	 */
	public static function redact( string $message, array $secrets ): string {
		foreach ( $secrets as $secret ) {
			$secret = (string) $secret;
			if ( strlen( $secret ) < 8 ) {
				continue;
			}
			$message = str_replace( $secret, '[REDACTED]', $message );
		}
		return $message;
	}

	/**
	 * Log a message only when WP_DEBUG + WP_DEBUG_LOG are on, after scrubbing
	 * the given secrets. Non-string input is json-encoded.
	 *
	 * @param mixed         $message  Any value (array/object/string).
	 * @param array<string> $secrets  Secrets to scrub from the final line.
	 */
	public static function safeLog( $message, array $secrets = [] ): void {
		if ( ! ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || ! ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) ) {
			return;
		}
		if ( ! is_string( $message ) ) {
			$encoded = wp_json_encode( $message );
			$message = is_string( $encoded ) ? $encoded : '';
		}
		$clean = self::redact( $message, $secrets );
		error_log( '[WP PowerSuite Captcha] ' . $clean ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
	}
}
