<?php
/**
 * TOR detection and management system for BotFend Anti-Bot Firewall
 *
 * @package BotFend\Security
 * @since 5.0.0
 * @version 4.8.3 - External services disabled by default, fixed escaping
 */

namespace BotFend\Security;

use BotFend\Core\Config;
use BotFend\Database\Database;
use BotFend\Utilities\Utilities;

defined('ABSPATH') || exit;

class TorSystem {
    
    private Config $config;
    private Database $database;
    private ?Utilities $utilities = null;
    
    private const TOR_EXIT_LIST_URL = 'https://check.torproject.org/torbulkexitlist';
private const TOR_EXIT_LIST_ALT_URL = 'https://www.dan.me.uk/torlist/';
    
    private const MAX_CACHE_SIZE = 500;
    private const CACHE_TRIM_AMOUNT = 100;
    private const CACHE_TOR_TTL = 6 * HOUR_IN_SECONDS;
    private const IMPORT_CHUNK_SIZE = 500;
    private const IMPORT_TIMEOUT = 45;
    private const LOCK_TIMEOUT = 300;
    private const RATE_LIMIT_WINDOW = 3600;
    private const MAX_IMPORTS_PER_HOUR = 4;
    
    private static array $tor_cache = [];
    private static int $cache_hits = 0;
    private static int $cache_misses = 0;
    
    public function __construct(Database $database) {
        $this->config = Config::get_instance();
        $this->database = $database;
        if (class_exists('BotFend\\Utilities\\Utilities')) {
            $this->utilities = new Utilities();
        }
        add_action('botfend_update_tor_nodes', [$this, 'cron_update_tor_nodes']);
        add_action('botfend_import_tor_nodes', [$this, 'cron_update_tor_nodes']);
        add_action('wp_ajax_botfend_update_tor_nodes', [$this, 'ajax_update_tor_nodes']);
        add_action('wp_ajax_botfend_verify_tor_challenge', [$this, 'verify_tor_challenge']);
        add_action('wp_ajax_nopriv_botfend_verify_tor_challenge', [$this, 'verify_tor_challenge']);
        add_action('init', [$this, 'maybe_schedule_cron']);
        add_action('shutdown', [__CLASS__, 'log_cache_stats']);
    }
    
    public function maybe_schedule_cron(): void {
        if (!wp_next_scheduled('botfend_update_tor_nodes')) {
            wp_schedule_event(time() + HOUR_IN_SECONDS, 'twicedaily', 'botfend_update_tor_nodes');
        }
    }
    
    public static function clear_schedule(): void {
        wp_clear_scheduled_hook('botfend_update_tor_nodes');
        wp_clear_scheduled_hook('botfend_import_tor_nodes');
    }
    
    public static function log_cache_stats(): void {
        if (defined('WP_DEBUG') && WP_DEBUG && defined('BOTFEND_DEBUG_TOR') && BOTFEND_DEBUG_TOR) {
            $total = self::$cache_hits + self::$cache_misses;
            $hit_rate = $total > 0 ? round((self::$cache_hits / $total) * 100, 2) : 0;
            error_log(sprintf('BotFend TOR Cache Stats: %d hits, %d misses, %.2f%% hit rate, %d cached entries', self::$cache_hits, self::$cache_misses, $hit_rate, count(self::$tor_cache)));
        }
    }
    
    public function cron_update_tor_nodes(): void {
        // Check if external TOR check is enabled (default: false)
        if (!$this->config->get_bool('enable_external_tor_check', false)) {
            return;
        }
        
        $locking_key = 'botfend_tor_updating';
        if (get_transient($locking_key)) {
            return;
        }
        set_transient($locking_key, time(), self::LOCK_TIMEOUT);
        try { 
            $this->import_tor_exit_nodes(); 
        } finally { 
            delete_transient($locking_key); 
        }
    }
    
    public function process_tor(string $ip, int $current_score): array {
        $default_result = [
            'score' => $current_score, 
            'action' => 'none', 
            'factors' => [], 
            'blocked' => false, 
            'challenged' => false, 
            'should_exit' => false
        ];
        
        // TOR detection is disabled by default (opt-in required)
        if (!$this->config->get_bool('enable_tor_detection', false)) {
            return $default_result;
        }
        
        $is_tor = $this->is_tor_exit_node($ip);
        if (!$is_tor) {
            return $default_result;
        }
        
        $tor_action = $this->config->get_string('tor_action', 'challenge');
        $tor_score = $this->config->get_int('score_tor', 4);
        $new_score = $current_score;
        $factors = [esc_html__('Tor exit node', 'botfend-anti-bot-firewall')];
        $blocked = false;
        $challenged = false;
        $action = 'none';
        $should_exit = false;
        
        switch ($tor_action) {
            case 'block': 
                $new_score = min(10, $new_score + $tor_score); 
                $action = 'tor_blocked'; 
                $blocked = true; 
                $should_exit = true; 
                $this->log_tor_detection($ip, 'blocked', $new_score); 
                $this->block_tor_traffic($ip, $new_score); 
                break;
            case 'challenge': 
                $new_score = min(10, $new_score + $tor_score); 
                $action = 'tor_challenge'; 
                $challenged = true; 
                $should_exit = true; 
                $this->log_tor_detection($ip, 'challenged', $new_score); 
                $this->challenge_tor_user($ip); 
                break;
            case 'add_score': 
                $new_score = min(10, $new_score + $tor_score); 
                $action = 'tor_scored'; 
                $should_exit = false; 
                $this->log_tor_detection($ip, 'scored', $new_score); 
                break;
            case 'log_only': 
                $action = 'tor_logged'; 
                $should_exit = false; 
                $this->log_tor_detection($ip, 'logged', $current_score); 
                break;
            default: 
                $new_score = min(10, $new_score + $tor_score); 
                $action = 'tor_scored'; 
                $should_exit = false; 
                $this->log_tor_detection($ip, 'scored', $new_score); 
                break;
        }
        
        return [
            'score' => $new_score, 
            'action' => $action, 
            'factors' => $factors, 
            'blocked' => $blocked, 
            'challenged' => $challenged, 
            'should_exit' => $should_exit
        ];
    }
    
    public function is_tor_exit_node(string $ip): bool {
        if (!$this->is_valid_ip($ip)) {
            return false;
        }
        
        // If external TOR check is disabled, return false
        if (!$this->config->get_bool('enable_external_tor_check', false)) {
            return false;
        }
        
        $cache_key = 'tor_' . md5($ip);
        
        if (isset(self::$tor_cache[$cache_key])) { 
            self::$cache_hits++; 
            return self::$tor_cache[$cache_key]; 
        }
        
        self::$cache_misses++;
        
        $cached = wp_cache_get($cache_key, 'botfend_tor');
        if ($cached !== false) { 
            self::$tor_cache[$cache_key] = (bool) $cached; 
            $this->maintain_cache_size(); 
            return (bool) $cached; 
        }
        
        $is_tor = false;
        if (method_exists($this->database, 'is_tor_exit_node')) { 
            $is_tor = $this->database->is_tor_exit_node($ip); 
        }
        
        self::$tor_cache[$cache_key] = $is_tor;
        wp_cache_set($cache_key, $is_tor, 'botfend_tor', self::CACHE_TOR_TTL);
        $this->maintain_cache_size();
        
        return $is_tor;
    }
    
    private function maintain_cache_size(): void {
        if (count(self::$tor_cache) > self::MAX_CACHE_SIZE) { 
            self::$tor_cache = array_slice(self::$tor_cache, self::CACHE_TRIM_AMOUNT, null, true); 
        }
    }
    
    private function is_valid_ip(string $ip): bool {
        if (empty($ip) || strlen($ip) > 45) {
            return false;
        }
        return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6) !== false;
    }
    
    public function import_tor_exit_nodes() {
        // CRITICAL: External TOR check is DISABLED BY DEFAULT
        if (!$this->config->get_bool('enable_external_tor_check', false)) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('BotFend TOR: External TOR check is disabled. Enable in settings to import TOR nodes.');
            }
            return false;
        }
        
        if (!$this->check_import_rate_limit()) { 
            error_log('BotFend TOR: Import rate limited - too many requests'); 
            return false; 
        }
        
        $start_time = microtime(true);
        $url = self::TOR_EXIT_LIST_URL;
        
        $response = wp_safe_remote_get($url, [
            'timeout' => self::IMPORT_TIMEOUT, 
            'user-agent' => 'BotFend Anti-Bot Firewall/' . BOTFEND_VERSION, 
            'sslverify' => true, 
            'headers' => ['Accept' => 'text/plain', 'Accept-Encoding' => 'gzip, deflate']
        ]);
        
        if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
            $response = wp_safe_remote_get(self::TOR_EXIT_LIST_ALT_URL, [
                'timeout' => self::IMPORT_TIMEOUT, 
                'user-agent' => 'BotFend Anti-Bot Firewall/' . BOTFEND_VERSION, 
                'sslverify' => true
            ]);
        }
        
        if (is_wp_error($response)) { 
            $this->log_error('Connection failed', $response->get_error_message()); 
            return false; 
        }
        
        $status_code = wp_remote_retrieve_response_code($response);
        if ($status_code !== 200) { 
            $this->log_error('HTTP error', "Status: {$status_code}"); 
            return false; 
        }
        
        $body = wp_remote_retrieve_body($response);
        if (empty($body)) { 
            $this->log_error('Empty response', 'No data received'); 
            return false; 
        }
        
        $ips = $this->parse_tor_list($body);
        if (empty($ips)) { 
            $this->log_error('Parse error', 'No valid IPs found'); 
            return false; 
        }
        
        $imported = $this->import_chunked($ips);
        $duration = round(microtime(true) - $start_time, 2);
        
        update_option('botfend_tor_last_update', time(), false);
        update_option('botfend_tor_last_count', $imported, false);
        update_option('botfend_tor_last_duration', $duration, false);
        
        $this->record_import();
        $this->clear_all_caches();
        
        if (defined('WP_DEBUG') && WP_DEBUG) { 
            error_log(sprintf('BotFend TOR: Imported %d nodes in %.2f seconds', $imported, $duration)); 
        }
        
        return $imported;
    }
    
    private function parse_tor_list(string $body): array {
        $ips = [];
        $lines = explode("\n", $body);
        foreach ($lines as $line) { 
            $line = trim($line); 
            if ($line === '' || $line[0] === '#') {
                continue; 
            }
            $parts = preg_split('/\s+/', $line, 2); 
            $ip = trim($parts[0]); 
            if (filter_var($ip, FILTER_VALIDATE_IP)) {
                $ips[] = $ip;
            }
        }
        return array_unique($ips);
    }
    
    private function import_chunked(array $ips): int {
        $chunks = array_chunk($ips, self::IMPORT_CHUNK_SIZE);
        $imported = 0;
        foreach ($chunks as $chunk) { 
            $result = $this->database->import_tor_exit_nodes_batch($chunk); 
            if ($result !== false) {
                $imported += $result;
            }
            if (count($chunks) > 1) {
                usleep(10000);
            }
        }
        return $imported;
    }
    
    private function check_import_rate_limit(): bool { 
        $imports = get_transient('botfend_tor_import_count'); 
        if ($imports === false) {
            return true;
        }
        return (int) $imports < self::MAX_IMPORTS_PER_HOUR; 
    }
    
    private function record_import(): void { 
        $imports = get_transient('botfend_tor_import_count'); 
        if ($imports === false) {
            set_transient('botfend_tor_import_count', 1, self::RATE_LIMIT_WINDOW);
        } else {
            set_transient('botfend_tor_import_count', (int) $imports + 1, self::RATE_LIMIT_WINDOW);
        }
    }
    
    public function get_tor_exit_nodes(?int $limit = null, int $offset = 0): array {
        if (!method_exists($this->database, 'get_tor_exit_nodes')) {
            return [];
        }
        
        $cache_key = 'botfend_tor_nodes_' . ($limit ?? 'all') . '_' . $offset;
        $cached = wp_cache_get($cache_key, 'botfend_tor');
        if ($cached !== false) {
            return $cached;
        }
        
        $nodes = $this->database->get_tor_exit_nodes($limit, $offset);
        wp_cache_set($cache_key, $nodes, 'botfend_tor', self::CACHE_TOR_TTL);
        
        return $nodes;
    }
    
    public function get_tor_exit_nodes_count(): int {
        if (!method_exists($this->database, 'get_tor_exit_nodes_count')) {
            return 0;
        }
        
        $cache_key = 'botfend_tor_nodes_count';
        $cached = wp_cache_get($cache_key, 'botfend_tor');
        if ($cached !== false) {
            return (int) $cached;
        }
        
        $count = $this->database->get_tor_exit_nodes_count();
        wp_cache_set($cache_key, $count, 'botfend_tor', self::CACHE_TOR_TTL);
        
        return $count;
    }
    
    public function get_status(): array {
        $node_count = $this->get_tor_exit_nodes_count();
        $last_update = absint(get_option('botfend_tor_last_update', 0));
        $last_count = absint(get_option('botfend_tor_last_count', 0));
        $last_duration = floatval(get_option('botfend_tor_last_duration', 0));
        
        if ($node_count > 0 && $last_update === 0) { 
            $last_update = time(); 
            update_option('botfend_tor_last_update', $last_update, false); 
        }
        
        return [
            'enabled' => $this->config->get_bool('enable_tor_detection', false),
            'external_enabled' => $this->config->get_bool('enable_external_tor_check', false),
            'action' => $this->config->get_string('tor_action', 'challenge'), 
            'score' => $this->config->get_int('score_tor', 4), 
            'last_update' => $last_update, 
            'node_count' => $node_count, 
            'last_import_count' => $last_count, 
            'last_import_duration' => $last_duration, 
            'cache_size' => count(self::$tor_cache), 
            'cache_hits' => self::$cache_hits, 
            'cache_misses' => self::$cache_misses
        ];
    }
    
    private function clear_all_caches(): void { 
        self::$tor_cache = []; 
        self::$cache_hits = 0; 
        self::$cache_misses = 0; 
        wp_cache_delete('botfend_tor_nodes_count', 'botfend_tor'); 
        wp_cache_delete('botfend_tor_nodes_all_0', 'botfend_tor'); 
        if (method_exists($this->database, 'invalidate_tor_cache')) {
            $this->database->invalidate_tor_cache();
        }
    }
    
    private function log_error(string $type, string $message): void { 
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log("BotFend TOR Error [{$type}]: {$message}");
        }
    }
    
    private function log_tor_detection(string $ip, string $action, int $score): void {
        if (!$this->database || !method_exists($this->database, 'log_request')) {
            return;
        }
        
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
        $country = '';
        if ($this->utilities && method_exists($this->utilities, 'get_country')) { 
            $country = sanitize_text_field($this->utilities->get_country($ip)); 
        }
        
        $this->database->log_request(
            sanitize_text_field($ip), 
            $score, 
            "tor_{$action}", 
            [sprintf(esc_html__('TOR exit node - action: %s', 'botfend-anti-bot-firewall'), esc_html($action))], 
            sanitize_text_field($user_agent), 
            false, 
            sanitize_text_field($country)
        );
    }
    
    private function block_tor_traffic(string $ip, int $score): void {
        if (!method_exists($this->database, 'block_ip')) {
            return;
        }
        
        $block_duration = $this->config->get_int('block_duration', 24);
        $country = '';
        if ($this->utilities && method_exists($this->utilities, 'get_country')) { 
            $country = sanitize_text_field($this->utilities->get_country($ip)); 
        }
        
        $this->database->block_ip(
            sanitize_text_field($ip), 
            'tor', 
            esc_html__('TOR exit node detected', 'botfend-anti-bot-firewall'), 
            $score, 
            $block_duration, 
            sanitize_text_field($country)
        );
        
        if (!headers_sent()) { 
            status_header(403); 
            wp_die(
                '<h1>' . esc_html__('Access Denied', 'botfend-anti-bot-firewall') . '</h1>' .
                '<p>' . esc_html__('Your connection appears to be using the TOR network. For security reasons, TOR connections are not allowed on this site.', 'botfend-anti-bot-firewall') . '</p>' .
                '<p>' . esc_html__('If you believe this is an error, please contact the site administrator.', 'botfend-anti-bot-firewall') . '</p>', 
                esc_html__('Access Denied', 'botfend-anti-bot-firewall'), 
                ['response' => 403]
            ); 
        }
    }
    
    private function challenge_tor_user(string $ip): void {
        if ($this->is_tor_verified($ip)) {
            return;
        }
        
        $challenge_id = wp_generate_password(32, false);
        $transient_key = 'botfend_tor_challenge_' . $this->get_safe_key($challenge_id);
        set_transient($transient_key, sanitize_text_field($ip), 300);
        
        add_action('wp_footer', function() use ($challenge_id) { 
            $this->render_challenge_script($challenge_id); 
        }, 999999);
    }

	/**
 * Render challenge script with proper enqueuing
 */
private function render_challenge_script(string $challenge_id): void {
    // Enqueue CSS properly
    wp_enqueue_style('botfend-block-css', BOTFEND_ASSETS_URL . 'css/botfend-block.css', [], BOTFEND_VERSION);
    
    // Create nonce with proper escaping
    $ajax_nonce = wp_create_nonce('botfend_tor_challenge');
    
    // Pass data to JavaScript
    wp_register_script('botfend-tor-challenge', '', [], BOTFEND_VERSION, true);
    wp_enqueue_script('botfend-tor-challenge');
    wp_add_inline_script('botfend-tor-challenge', '
(function($) {
    var challengeId = ' . wp_json_encode($challenge_id) . ';
    var ajaxUrl = ' . wp_json_encode(admin_url('admin-ajax.php')) . ';
    var nonce = ' . wp_json_encode($ajax_nonce) . ';
    
    $("#botfend-tor-challenge").fadeIn();
    
    $("#botfend-verify-tor").on("click", function() {
        $("#botfend-challenge-container").hide();
        $("#botfend-verifying").show();
        
        $.ajax({
            url: ajaxUrl, 
            type: "POST", 
            data: {
                action: "botfend_verify_tor_challenge", 
                challenge_id: challengeId, 
                nonce: nonce
            },
            success: function(response) {
                if (response.success) { 
                    $("#botfend-verifying").hide(); 
                    $("#botfend-verified").show(); 
                    localStorage.setItem("botfend_tor_verified", "true"); 
                    localStorage.setItem("botfend_tor_verified_time", Date.now()); 
                    setTimeout(function() { 
                        location.reload(); 
                    }, 1500); 
                } else { 
                    $("#botfend-verifying").hide(); 
                    $("#botfend-error").show(); 
                }
            },
            error: function() { 
                $("#botfend-verifying").hide(); 
                $("#botfend-error").show(); 
            }
        });
    });
    
    if (localStorage.getItem("botfend_tor_verified") === "true") { 
        var verifiedTime = parseInt(localStorage.getItem("botfend_tor_verified_time") || "0"); 
        var hoursPassed = (Date.now() - verifiedTime) / (1000 * 60 * 60); 
        if (hoursPassed < 24) {
            $("#botfend-tor-challenge").hide();
        }
    }
})(jQuery);
');
    ?>
    <div id="botfend-tor-challenge" class="botfend-challenge-overlay">
        <div class="botfend-challenge-modal">
            <h2 class="botfend-modal-title"><?php echo esc_html__('Security Verification Required', 'botfend-anti-bot-firewall'); ?></h2>
            <p class="botfend-modal-text"><?php echo esc_html__('Your connection appears to be using the TOR network. Please complete the verification to continue.', 'botfend-anti-bot-firewall'); ?></p>
            <div id="botfend-challenge-container" class="botfend-challenge-container">
                <p class="botfend-modal-text"><?php echo esc_html__('Click the button below to verify you are human:', 'botfend-anti-bot-firewall'); ?></p>
                <button id="botfend-verify-tor" class="botfend-btn-primary"><?php echo esc_html__("Verify I'm Human", 'botfend-anti-bot-firewall'); ?></button>
            </div>
            <div id="botfend-verifying" class="botfend-hidden"><p class="botfend-modal-text"><?php echo esc_html__('Verifying...', 'botfend-anti-bot-firewall'); ?></p><div class="botfend-spinner"></div></div>
            <div id="botfend-verified" class="botfend-hidden"><p class="botfend-success-text"><?php echo esc_html__('Verification successful! Redirecting...', 'botfend-anti-bot-firewall'); ?></p></div>
            <div id="botfend-error" class="botfend-hidden"><p class="botfend-error-text"><?php echo esc_html__('Verification failed. Please refresh the page and try again.', 'botfend-anti-bot-firewall'); ?></p></div>
        </div>
    </div>
    <?php
}
    
    public function verify_tor_challenge(): void {
        // Verify nonce
        if (!isset($_POST['nonce'])) { 
            wp_send_json_error(['message' => esc_html__('Missing nonce', 'botfend-anti-bot-firewall')]); 
        }
        
        $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
        if (!wp_verify_nonce($nonce, 'botfend_tor_challenge')) { 
            wp_send_json_error(['message' => esc_html__('Invalid nonce', 'botfend-anti-bot-firewall')]); 
        }
        
        // Verify challenge ID
        if (!isset($_POST['challenge_id'])) { 
            wp_send_json_error(['message' => esc_html__('Missing challenge ID', 'botfend-anti-bot-firewall')]); 
        }
        
        $challenge_id = sanitize_text_field(wp_unslash($_POST['challenge_id']));
        $transient_key = 'botfend_tor_challenge_' . $this->get_safe_key($challenge_id);
        $stored_ip = get_transient($transient_key);
        
        // Get current IP
        $current_ip = '';
        if ($this->utilities && method_exists($this->utilities, 'get_client_ip')) {
            $current_ip = $this->utilities->get_client_ip();
        }
        
        // Verify IP matches
        if ($stored_ip && hash_equals($stored_ip, $current_ip)) {
            delete_transient($transient_key);
            $hash = wp_hash($current_ip . 'botfend_tor');
            $secure = is_ssl();
            
            // Set cookie with proper parameters
            setcookie(
                'botfend_tor_verified', 
                $hash, 
                [
                    'expires' => time() + DAY_IN_SECONDS, 
                    'path' => COOKIEPATH, 
                    'domain' => COOKIE_DOMAIN, 
                    'secure' => $secure, 
                    'httponly' => true, 
                    'samesite' => 'Lax'
                ]
            );
            
            wp_send_json_success(['message' => esc_html__('Verification successful', 'botfend-anti-bot-firewall')]);
        }
        
        wp_send_json_error(['message' => esc_html__('Verification failed', 'botfend-anti-bot-firewall')]);
    }
    
    public function is_tor_verified(?string $ip = null): bool {
        if (!$ip && $this->utilities) {
            $ip = $this->utilities->get_client_ip();
        }
        if (empty($ip) || !$this->is_valid_ip($ip)) {
            return false;
        }
        
        if (isset($_COOKIE['botfend_tor_verified'])) { 
            $cookie_value = sanitize_text_field(wp_unslash($_COOKIE['botfend_tor_verified'])); 
            $expected = wp_hash($ip . 'botfend_tor'); 
            return hash_equals($expected, $cookie_value); 
        }
        
        return false;
    }
    
    private function get_safe_key(string $value): string { 
        return substr(md5(sanitize_text_field($value)), 0, 12); 
    }
    
    public function ajax_update_tor_nodes(): void {
        // Verify nonce
        if (!isset($_POST['nonce'])) { 
            wp_send_json_error(['message' => esc_html__('Missing nonce', 'botfend-anti-bot-firewall')]); 
        }
        
        $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
        if (!wp_verify_nonce($nonce, 'botfend_update_tor_nodes')) { 
            wp_send_json_error(['message' => esc_html__('Invalid nonce', 'botfend-anti-bot-firewall')]); 
        }
        
        if (!current_user_can('manage_options')) { 
            wp_send_json_error(['message' => esc_html__('Insufficient permissions', 'botfend-anti-bot-firewall')]); 
        }
        
        // Check if external TOR check is enabled
        if (!$this->config->get_bool('enable_external_tor_check', false)) {
            wp_send_json_error(['message' => esc_html__('External TOR check is disabled. Please enable it in settings first.', 'botfend-anti-bot-firewall')]);
        }
        
        $result = $this->import_tor_exit_nodes();
        
        if ($result !== false) {
            $count = number_format_i18n($result);
            $last_update = wp_date(get_option('date_format') . ' ' . get_option('time_format'), time());
            wp_send_json_success([
                'message' => sprintf(esc_html__('Successfully updated %s TOR exit nodes.', 'botfend-anti-bot-firewall'), $count), 
                'count' => $result, 
                'last_updated' => $last_update
            ]);
        } else {
            wp_send_json_error(['message' => esc_html__('Failed to update TOR exit nodes. Please try again later.', 'botfend-anti-bot-firewall')]);
        }
    }
    
    public static function clear_runtime_caches(): void { 
        self::$tor_cache = []; 
        self::$cache_hits = 0; 
        self::$cache_misses = 0; 
    }
    
    public static function get_cache_stats(): array {
        return [
            'size' => count(self::$tor_cache), 
            'hits' => self::$cache_hits, 
            'misses' => self::$cache_misses, 
            'hit_rate' => (self::$cache_hits + self::$cache_misses) > 0 ? round((self::$cache_hits / (self::$cache_hits + self::$cache_misses)) * 100, 2) : 0
        ];
    }
}