<?php
if (!defined('ABSPATH')) exit;

class Calliope_SP_Logger {
    private const MAX_LOGS = 50;
    private const MAX_MESSAGE_LENGTH = 10000;

    public static function log($network, $status, $message) {
        if (!is_string($message)) {
            $message = wp_json_encode($message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        }

        $message = self::sanitize_message((string) $message);

        $logs = get_option('calliope_sp_debug_logs', []);
        if (!is_array($logs)) {
            $logs = [];
        }

        array_unshift($logs, [
            'date'    => current_time('mysql'),
            'network' => sanitize_key((string) $network),
            'status'  => sanitize_key((string) $status),
            'message' => $message,
        ]);

        $logs = array_slice($logs, 0, self::MAX_LOGS);
        update_option('calliope_sp_debug_logs', $logs);
    }

    /**
     * Reuse the log message sanitizer from settings callbacks and migrations.
     *
     * @param string $message Raw log message.
     * @return string
     */
    public static function sanitize_message_for_storage($message) {
        return self::sanitize_message($message);
    }

    private static function sanitize_message($message) {
        $message = wp_strip_all_tags((string) $message);
        $message = preg_replace('/[\x00-\x1F\x7F]/u', ' ', $message);
        $message = preg_replace('/\s+/u', ' ', $message);

        $patterns = [
            // JSON/body style secrets: access_token":"...", client_secret=..., oauth_token=...
            '/((?:access[_-]?token|refresh[_-]?token|client[_-]?secret|app[_-]?secret|consumer[_-]?secret|token[_-]?secret|oauth[_-]?token|oauth[_-]?token[_-]?secret|authorization[_-]?code|id[_-]?token|code[_-]?verifier|password)\s*["\']?\s*[:=]\s*["\']?)([^"\',\s&}\]]+)/iu',

            // Query-string style secrets inside logged URLs or raw request strings.
            '/((?:[?&]|\b)(?:access_token|refresh_token|client_secret|app_secret|consumer_secret|token_secret|oauth_token|oauth_token_secret|id_token|code|state)=)([^&\s"\']+)/iu',

            // Authorization headers or Bearer tokens embedded in messages.
            '/((?:authorization\s*["\']?\s*[:=]\s*["\']?bearer\s+)|(?:bearer\s+))([A-Za-z0-9\-._~+\/]+=*)/iu',
        ];

        foreach ($patterns as $pattern) {
            $message = preg_replace_callback($pattern, static function ($matches) {
                return $matches[1] . '[redacted]';
            }, $message);
        }

        if (function_exists('mb_substr')) {
            $message = mb_substr($message, 0, self::MAX_MESSAGE_LENGTH);
        } else {
            $message = substr($message, 0, self::MAX_MESSAGE_LENGTH);
        }

        return trim($message);
    }
}
