<?php
/**
 * Core functionality for BotFend Anti-Bot Firewall
 *
 * @package BotFend\Core
 * @since   4.6.0
 * @version 4.8.3 - Rebranded from SafeBot, external services opt-in, firewall integration
 */

namespace BotFend\Core;

use BotFend\Utilities\Utilities;
use BotFend\Database\Database;
use BotFend\Detection\Detection;
use BotFend\ThirdParty\IPHub;
use BotFend\ThirdParty\AbuseIPDB;
use BotFend\Challenges\Challenges;
use BotFend\Adaptive\Adaptive;
use BotFend\Detection\ThreatIntel;
use BotFend\Detection\Signatures;
use BotFend\Security\TorSystem;
use BotFend\Security\Advanced404;
use BotFend\Security\ConnectionFingerprint;
use BotFend\Security\IntelligentSession;
use BotFend\Security\BehavioralAnalyzer;
use BotFend\Security\WAF;
use BotFend\Security\WordPressProtection;
use BotFend\Logging\Logger;

defined( 'ABSPATH' ) || exit;

/**
 * Main Core class for BotFend Anti-Bot Firewall
 *
 * Handles all security checks, scoring, and request processing.
 * Uses accumulated scoring system with immediate block for critical threats.
 */
class Core {

	/**
	 * Plugin text domain.
	 *
	 * @var string
	 */
	const TEXT_DOMAIN = 'botfend-anti-bot-firewall';

	/**
	 * Admin nonce key.
	 *
	 * @var string
	 */
	const ADMIN_NONCE_KEY = 'botfend_admin_action';

	/**
	 * Security violations limit.
	 *
	 * @var int
	 */
	const SECURITY_VIOLATIONS_LIMIT = 100;

	/**
	 * Transient prefix.
	 *
	 * @var string
	 */
	const TRANSIENT_PREFIX = 'botfend_';

	/**
	 * Default transient expiry (seconds).
	 *
	 * @var int
	 */
	const TRANSIENT_EXPIRY = 300;

	/**
	 * Cache group for admin data.
	 *
	 * @var string
	 */
	const CACHE_GROUP = 'botfend_admin';

	/**
	 * Config instance.
	 *
	 * @var Config
	 */
	private $config;

	/**
	 * Utilities instance.
	 *
	 * @var Utilities
	 */
	private $utilities;

	/**
	 * Database instance.
	 *
	 * @var Database
	 */
	private $database;

	/**
	 * Detection instance.
	 *
	 * @var Detection
	 */
	private $detection;

	/**
	 * IPHub instance.
	 *
	 * @var IPHub
	 */
	private $iphub;

	/**
	 * AbuseIPDB instance.
	 *
	 * @var AbuseIPDB
	 */
	private $abuseipdb;

	/**
	 * Challenges instance.
	 *
	 * @var Challenges|null
	 */
	private $challenges;

	/**
	 * Adaptive instance.
	 *
	 * @var Adaptive|null
	 */
	private $adaptive;

	/**
	 * ThreatIntel instance.
	 *
	 * @var ThreatIntel|null
	 */
	private $threat_intel;

	/**
	 * Signatures instance.
	 *
	 * @var Signatures|null
	 */
	private $signatures;

	/**
	 * TorSystem instance.
	 *
	 * @var TorSystem|null
	 */
	private $tor_system;

	/**
	 * Advanced404 instance.
	 *
	 * @var Advanced404|null
	 */
	private $advanced_404;

	/**
	 * ConnectionFingerprint instance.
	 *
	 * @var ConnectionFingerprint|null
	 */
	private $connection_fp;

	/**
	 * IntelligentSession instance.
	 *
	 * @var IntelligentSession|null
	 */
	private $intelligent_session;

	/**
	 * BehavioralAnalyzer instance.
	 *
	 * @var BehavioralAnalyzer|null
	 */
	private $behavioral_analyzer;

	/**
	 * WAF instance.
	 *
	 * @var WAF|null
	 */
	private $waf;

	/**
	 * WordPressProtection instance.
	 *
	 * @var WordPressProtection|null
	 */
	private $wordpress_protection;

	/**
	 * Logger instance.
	 *
	 * @var Logger|null
	 */
	private $logger;

	/**
	 * Request processed flag.
	 *
	 * @var bool
	 */
	private $request_processed = false;

	/**
	 * Current request data.
	 *
	 * @var array
	 */
	private $current_request_data = array();

	/**
	 * Steps executed for debugging.
	 *
	 * @var array
	 */
	private $steps_executed = array();

	/**
	 * Skip heavy detection flag.
	 *
	 * @var bool
	 */
	private $skip_heavy_detection = false;

	/**
	 * WAF only mode flag.
	 *
	 * @var bool
	 */
	private $waf_only_mode = false;

	/**
	 * Unique request ID.
	 *
	 * @var string
	 */
	private $request_id;

	/**
	 * Constructor.
	 *
	 * @param Utilities|null  $utilities  Utilities instance.
	 * @param Database|null   $database   Database instance.
	 * @param Detection|null  $detection  Detection instance.
	 * @param IPHub|null      $iphub      IPHub instance.
	 * @param AbuseIPDB|null  $abuseipdb  AbuseIPDB instance.
	 */
	 public function __construct(
		?Utilities $utilities = null,
		?Database $database = null,
		?Detection $detection = null,
		?IPHub $iphub = null,
		?AbuseIPDB $abuseipdb = null
	) {
		$this->config     = Config::get_instance();
		$this->request_id = wp_generate_uuid4();

		// Initialize core components.
		$this->utilities  = $utilities ?: new Utilities();
		$this->database   = $database ?: new Database();
		$this->detection  = $detection ?: new Detection( $this->utilities, $this->database );
		$this->iphub      = $iphub ?: new IPHub( $this->utilities );
		$this->abuseipdb  = $abuseipdb ?: new AbuseIPDB( $this->database );

		$this->setup_transient_cleanup();

		// Run check immediately for blocking.
		if ( $this->config->get_bool( 'botfend_enabled', true ) ) {
			$this->check_visitor();
		}

		// Hook for 404 logging.
		add_action( 'template_redirect', array( $this, 'log_404_abuse' ) );

		// AJAX handlers.
		add_action( 'wp_ajax_botfend_unblock_request', array( $this, 'handle_unblock_request' ) );
		add_action( 'wp_ajax_nopriv_botfend_unblock_request', array( $this, 'handle_unblock_request' ) );
		add_action( 'wp_ajax_botfend_resolve_conflict', array( $this, 'resolve_security_conflict' ) );

		// ========== FIREWALL INTEGRATION HOOKS ==========
		// Sync firewall cache when blocklist changes (via admin UI)
		add_action( 'botfend_ip_blocked', array( $this, 'sync_firewall_blocklist_cache' ), 10, 1 );
		add_action( 'botfend_ip_unblocked', array( $this, 'sync_firewall_blocklist_cache' ), 10, 1 );

		// CRITICAL FIX: Sync whitelist cache when config changes (catch both Add and Update events)
		add_action( 'add_option_botfend_whitelist_ips', array( $this, 'sync_firewall_whitelist_cache' ), 10, 2 );
		add_action( 'update_option_botfend_whitelist_ips', array( $this, 'sync_firewall_whitelist_cache' ), 10, 2 );
        
		// CRITICAL FIX: Sync permanent blocks when config changes
		add_action( 'add_option_botfend_permanent_blocklist', array( $this, 'sync_firewall_blocklist_cache' ), 10, 2 );
		add_action( 'update_option_botfend_permanent_blocklist', array( $this, 'sync_firewall_blocklist_cache' ), 10, 2 );

		// Catch custom config saves
		add_action( 'botfend_config_updated', array( $this, 'sync_firewall_whitelist_on_config_update' ), 10, 2 );
		// =======================================================
	}

	/**
	 * Set additional components after construction.
	 *
	 */
	public function set_components(
		$challenges = null,
		$adaptive = null,
		$threat_intel = null,
		$signatures = null,
		$tor_system = null,
		$advanced_404 = null,
		$connection_fp = null,
		$intelligent_session = null,
		$behavioral_analyzer = null,
		$waf = null,
		$wordpress_protection = null,
		$logger = null
	) {
		$this->challenges            = $challenges;
		$this->adaptive              = $adaptive;
		$this->threat_intel          = $threat_intel;
		$this->signatures            = $signatures;
		$this->tor_system            = $tor_system;
		$this->advanced_404          = $advanced_404;
		$this->connection_fp         = $connection_fp;
		$this->intelligent_session   = $intelligent_session;
		$this->behavioral_analyzer   = $behavioral_analyzer;
		$this->waf                   = $waf;
		$this->wordpress_protection  = $wordpress_protection;
		$this->logger                = $logger;
	}

	/**
	 * Set logger instance.
	 *
	 * @param Logger $logger Logger instance.
	 * @return void
	 */
	public function set_logger( Logger $logger ) {
		$this->logger = $logger;
	}

	/**
	 * Get logger instance.
	 *
	 * @return Logger|null
	 */
	public function get_logger() {
		return $this->logger;
	}

/**
	 * Get config instance.
	 *
	 * @return Config
	 */
	public function get_config() {
		return $this->config;
	}

	/**
	 * Get utilities instance.
	 *
	 * @return Utilities
	 */
	public function get_utilities() {
		return $this->utilities;
	}
	
	/**
	 * Get database instance.
	 *
	 * @return Database
	 */
	public function get_database() {
		return $this->database;
	}

	/**
	 * Setup transient cleanup schedule.
	 *
	 * @return void
	 */
	private function setup_transient_cleanup() {
		if ( ! wp_next_scheduled( 'botfend_cleanup_transients' ) ) {
			wp_schedule_event( time(), 'hourly', 'botfend_cleanup_transients' );
		}
		add_action( 'botfend_cleanup_transients', array( $this, 'cleanup_old_transients' ) );
	}
	
/**
 * Cleanup old transients with strict SQL escaping.
 *
 *
 * @return void
 */
public function cleanup_old_transients() {
    global $wpdb;

    $two_hours_ago = time() - 7200;

    $like_prefix  = $wpdb->esc_like( '_transient_' . self::TRANSIENT_PREFIX ) . '%';
    $like_timeout = $wpdb->esc_like( '_transient_timeout_' . self::TRANSIENT_PREFIX ) . '%';

    // Delete all BotFend transients (expired or not)
    $wpdb->query(
        $wpdb->prepare(
            "DELETE FROM {$wpdb->options} 
            WHERE option_name LIKE %s 
            OR option_name LIKE %s",
            $like_prefix,
            $like_timeout
        )
    );

    // Clean up by timeout separately - only delete expired transients
    $wpdb->query(
        $wpdb->prepare(
            "DELETE FROM {$wpdb->options} 
            WHERE option_name LIKE %s 
            AND option_value < %d",
            $like_timeout,
            $two_hours_ago
        )
    );
}

	/**
	 * Get block screen CSS from external file.
	 *
	 * @return string
	 */
	private function get_block_screen_css(): string {
		$css_url = BOTFEND_URL . 'assets/css/botfend-block-screen.css';
		return '<link rel="stylesheet" href="' . esc_url( $css_url ) . '" media="all">';
	}

	/**
	 * Get unblock form CSS (reuses same file).
	 *
	 * @return string
	 */
	private function get_unblock_form_css(): string {
		return $this->get_block_screen_css();
	}

	/**
	 * Check if request path should skip
	 * @return bool
	 */
	private function should_skip_bot_detection( $request_path ) {
		$whitelisted_paths_raw = $this->config->get_string( 'whitelisted_paths', '' );
		$allowed_paths         = explode( "\n", $whitelisted_paths_raw );
		$allowed_paths         = array_filter( array_map( 'trim', $allowed_paths ) );

		$standard_paths = array(
			'/.well-known/traffic-advice',
			'/.well-known/security.txt',
			'/.well-known/assetlinks.json',
			'/.well-known/apple-app-site-association',
			'/.well-known/dnt-policy.txt',
			'/.well-known/brave-rewards-verification.txt',
			'/robots.txt',
			'/favicon.ico',
			'/sitemap.xml',
			'/sitemap_index.xml',
			'/humans.txt',
			'/ads.txt',
		);

		$allowed_paths = array_merge( $allowed_paths, $standard_paths );

		if ( in_array( $request_path, $allowed_paths, true ) ) {
			return true;
		}

		if ( 0 === strpos( $request_path, '/.well-known/' ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Validate CIDR notation.
	 */
	private function is_valid_cidr( $cidr, $check_guardrails = false ) {
		if ( false === strpos( $cidr, '/' ) ) {
			return false;
		}

		$parts = explode( '/', $cidr, 2 );
		if ( 2 !== count( $parts ) ) {
			return false;
		}

		$ip   = $parts[0];
		$mask = intval( $parts[1] );

		if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
			return false;
		}

		if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
			return $mask >= 0 && $mask <= 32;
		}

		if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
			return $mask >= 0 && $mask <= 128;
		}

		return false;
	}

	/**
	 * Get request headers safely.
	 *
	 * @return array
	 */
	private function get_request_headers() {
		if ( function_exists( 'getallheaders' ) ) {
			$headers = getallheaders();
			if ( is_array( $headers ) ) {
				return array_map( 'sanitize_text_field', $headers );
			}
		}

		$headers = array();
		foreach ( $_SERVER as $key => $value ) {
			if ( 0 === strpos( $key, 'HTTP_' ) ) {
				$header = str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', substr( $key, 5 ) ) ) ) );
				$headers[ $header ] = sanitize_text_field( $value );
			}
		}

		return $headers;
	}

	/**
	 * Get current URL.
	 *
	 * @return string
	 */
	private function get_current_url() {
		static $url = null;

		if ( null !== $url ) {
			return $url;
		}

		$protocol = is_ssl() ? 'https://' : 'http://';
		$host     = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
		$uri      = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
		$url      = esc_url_raw( $protocol . $host . $uri );

		return $url;
	}

	/**
	 * Log execution step for debugging
	 * @return void
	 */
	private function log_step( $step_name, $context = array() ) {
		$this->steps_executed[] = $step_name;

		if ( defined( 'WP_DEBUG' ) && WP_DEBUG && $this->config->get_bool( 'debug_mode', false ) ) {
			// Never log raw IPs in production - hash them if needed
			$safe_context = $context;
			if ( isset( $safe_context['ip'] ) ) {
				$safe_context['ip_hash'] = md5( $safe_context['ip'] );
				unset( $safe_context['ip'] );
			}
			
			error_log(
				sprintf(
					'[%s] BotFend Step: %s - Score: %d %s',
					$this->request_id,
					$step_name,
					$this->current_request_data['score'] ?? 0,
					! empty( $safe_context ) ? wp_json_encode( $safe_context ) : ''
				)
			);
		}
	}
	
	
	/**
 * Check rate limit for authenticated users with atomic operations.
 *
 * @param string $ip   IP address.
 * @param string $role User role.
 * @return bool
 */
private function check_authenticated_rate_limit( $ip, $role ) {
    // Validate IP first
    if ( ! $this->validate_ip_for_checks( $ip ) ) {
        return false;
    }
    
    $admin_limit  = $this->config->get_int( 'admin_rate_limit', 60 );
    $editor_limit = $this->config->get_int( 'editor_rate_limit', 45 );
    $window       = $this->config->get_int( 'rate_limit_window', 60 );

    $limit = ( 'admin' === $role ) ? $admin_limit : $editor_limit;

    $key = self::TRANSIENT_PREFIX . 'auth_rate_' . md5( $ip . '_' . $role );
    
    // Attempt atomic increment first (Safe for Redis/Memcached)
    if ( wp_cache_add( $key, 1, '', $window ) ) {
        $count = 1;
    } else {
        $count = wp_cache_incr( $key, 1, '' );
        // Fallback if object cache is bypassed
        if ( false === $count ) {
            $count = absint( get_transient( $key ) ?: 0 );
            $count++;
            set_transient( $key, $count, $window );
        }
    }

    return $count <= $limit;
}


/**
 * Validate IP address for security checks.
 * 
 */
private function validate_ip_for_checks( $ip ) {
    if ( empty( $ip ) || ! is_string( $ip ) ) {
        return false;
    }
    
    // Trim and sanitize basic string
    $ip = trim( sanitize_text_field( $ip ) );
    
    return filter_var( $ip, FILTER_VALIDATE_IP ) !== false;
}
	


	/**
	 * Handle rate limit block.
	 *
	 * @param string $ip   IP address.
	 * @param string $role User role.
	 * @return void
	 */
	private function handle_rate_limit_block( $ip, $role ) {
		$block_seconds = $this->config->get_int( 'rate_limit_block_duration', 30 );
		$block_hours   = $block_seconds / 3600;

		$factors = array(
			sprintf(
				/* translators: 1: User role, 2: Block duration in seconds */
				__( 'Rate limit exceeded: %1$s - blocked for %2$d seconds', 'botfend-anti-bot-firewall' ),
				esc_html( $role ),
				absint( $block_seconds )
			),
		);

		$this->current_request_data['factors'] = array_merge(
			$this->current_request_data['factors'] ?? array(),
			$factors
		);

		$this->log_step( $role . '_rate_limited_blocked' );

		$this->database->block_ip(
			$ip,
			'rate_limited',
			implode( '; ', $factors ),
			5,
			$block_hours,
			$this->utilities->get_country( $ip )
		);

		// ========== FIREWALL INTEGRATION ==========
		do_action( 'botfend_ip_blocked', $ip, 'rate_limited', 5, implode( '; ', $factors ) );
		// ===================================================

		$this->handle_blocked_access( $ip, false );
		exit;
	}

	/**
	 * Handle authenticated user checks.
	 *
	 * @return bool
	 */
	private function handle_authenticated_user() {
		$current_user = wp_get_current_user();

		if ( ! $current_user->exists() ) {
			return false;
		}

		$ip           = $this->utilities->get_client_ip();
		$request_path = $this->current_request_data['request_path'] ?? '';

		// Skip rate limiting for logged-in users in admin/REST areas.
		if ( 0 === strpos( $request_path, '/wp-admin/' ) || 0 === strpos( $request_path, '/wp-json/' ) ) {
			$this->log_step( 'logged_in_admin_api_skip_rate_limit' );

			if ( $current_user->has_cap( 'manage_options' ) ) {
				$this->waf_only_mode        = true;
				$this->skip_heavy_detection = true;
				$this->log_step( 'logged_in_admin_api_waf_only' );
			} elseif ( $current_user->has_cap( 'edit_posts' ) || $current_user->has_cap( 'publish_posts' ) ) {
				$this->skip_heavy_detection = true;
				$this->log_step( 'logged_in_admin_api_light_check' );
			}

			return true;
		}

		// Check if admin checks are completely disabled.
		if ( $current_user->has_cap( 'manage_options' ) && $this->config->get_bool( 'disable_admin_checks', true ) ) {
			$this->log_step( 'admin_checks_disabled' );
			$this->waf_only_mode        = true;
			$this->skip_heavy_detection = true;
			return true;
		}

		// Check if editor checks are completely disabled.
		if ( ( $current_user->has_cap( 'edit_posts' ) || $current_user->has_cap( 'publish_posts' ) ) && $this->config->get_bool( 'disable_editor_checks', true ) ) {
			$this->log_step( 'editor_checks_disabled' );
			$this->skip_heavy_detection = true;
			return true;
		}

		// Apply rate limits for logged-in users on frontend.
		if ( $current_user->has_cap( 'manage_options' ) && $this->config->get_bool( 'bypass_admin_rate_limit', false ) ) {
			$this->log_step( 'admin_rate_limit_bypassed' );
			$this->waf_only_mode        = true;
			$this->skip_heavy_detection = true;
			return true;
		}

		if ( $current_user->has_cap( 'manage_options' ) ) {
			if ( ! $this->check_authenticated_rate_limit( $ip, 'admin' ) ) {
				$this->handle_rate_limit_block( $ip, 'admin' );
			}

			$this->waf_only_mode        = true;
			$this->skip_heavy_detection = true;
			$this->log_step( 'admin_waf_only' );
			return true;
		} elseif ( $current_user->has_cap( 'edit_posts' ) || $current_user->has_cap( 'publish_posts' ) ) {
			if ( ! $this->check_authenticated_rate_limit( $ip, 'editor' ) ) {
				$this->handle_rate_limit_block( $ip, 'editor' );
			}

			$this->skip_heavy_detection = true;
			$this->log_step( 'editor_light_check' );
			return true;
		}

		return false;
	}

	/**
	 * Get REST route for current request.
	 *
	 * @return string
	 */
	private function get_rest_route() {
		if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) {
			return '';
		}

		if ( function_exists( 'rest_get_route_for_request' ) ) {
			return rest_get_route_for_request();
		}

		if ( isset( $GLOBALS['wp'] ) && isset( $GLOBALS['wp']->query_vars['rest_route'] ) ) {
			return $GLOBALS['wp']->query_vars['rest_route'];
		}

		return '';
	}

	/**
	 * Main visitor check - entry point for all security processing.
	 *
	 * @return void
	 */
	public function check_visitor() {
		$this->log_step( 'check_visitor_start' );

		// Skip security for logged-in users with editing capabilities.
		if ( is_user_logged_in() ) {
			$current_user = wp_get_current_user();
			if ( $current_user->exists() &&
				( $current_user->has_cap( 'edit_posts' ) ||
					$current_user->has_cap( 'publish_posts' ) ||
					$current_user->has_cap( 'manage_options' ) ) ) {
				return;
			}
		}

		// Skip security for admin-ajax and REST API when user is logged in.
		if ( ( wp_doing_ajax() || defined( 'REST_REQUEST' ) ) && is_user_logged_in() ) {
			return;
		}

		// Skip for block editor endpoints.
		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
			$route = $this->get_rest_route();
			if ( 0 === strpos( $route, '/wp/v2/posts' ) ||
				0 === strpos( $route, '/wp/v2/pages' ) ||
				0 === strpos( $route, '/wp/v2/media' ) ||
				false !== strpos( $route, '/block-editor' ) ) {
				return;
			}
		}

		// Don't run in admin area.
		if ( is_admin() ) {
			return;
		}

		// Prevent duplicate processing.
		if ( $this->request_processed ) {
			return;
		}

		// Gather request data with validation.
		$ip           = $this->utilities->get_client_ip();
		
		// Validate IP before proceeding
		if ( ! $this->validate_ip_for_checks( $ip ) ) {
			$this->log_step( 'invalid_ip_detected' );
			return;
		}
		
		$user_agent   = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
		$country      = $this->utilities->get_country( $ip );
		$request_path = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';

		$this->current_request_data = array(
			'ip'                 => $ip,
			'user_agent'         => $user_agent,
			'country'            => $country,
			'request_path'       => $request_path,
			'score'              => 0,
			'factors'            => array(),
			'action'             => 'allowed',
			'is_google_crawler'  => false,
			'blocked'            => false,
			'challenged'         => false,
			'request_id'         => $this->request_id,
		);

		$this->request_processed = true;

		// STEP 1: WHITELIST CHECK (Highest Priority).
		if ( $this->utilities->is_ip_whitelisted( $ip ) ) {
			$this->log_step( 'step1_whitelist' );
			$this->current_request_data['action']  = 'whitelist_allowed';
			$this->current_request_data['score']   = 0;
			$this->current_request_data['factors'][] = __( 'IP whitelisted - bypassing all protection', 'botfend-anti-bot-firewall' );
			$this->log_request_centralized();
			return;
		}

		// STEP 2: AUTHENTICATED USER HANDLING.
		if ( is_user_logged_in() ) {
			$this->handle_authenticated_user();
		}

		// STEP 3: PERMANENT BLOCKS.
		if ( $this->utilities->is_permanently_blocked( $ip ) ) {
			$this->log_step( 'step3_permanent_block' );
			$this->current_request_data['action']  = 'permanent_block';
			$this->current_request_data['score']   = 10;
			$this->current_request_data['blocked'] = true;
			$this->current_request_data['factors'][] = __( 'IP in permanent blocklist', 'botfend-anti-bot-firewall' );
			$this->log_request_centralized();
			$this->handle_blocked_access( $ip, true );
			exit;
		}

		// STEP 4: ACTIVE BLOCKS.
		if ( $this->database->is_ip_blocked( $ip ) ) {
			$this->log_step( 'step4_active_block' );
			$this->current_request_data['action']  = 'already_blocked';
			$this->current_request_data['score']   = 10;
			$this->current_request_data['blocked'] = true;
			$this->current_request_data['factors'][] = __( 'IP is currently blocked', 'botfend-anti-bot-firewall' );
			$this->log_request_centralized();
			$this->handle_blocked_access( $ip, false );
			exit;
		}

		// STEP 5: PATH WHITELIST.
		if ( $this->should_skip_bot_detection( $request_path ) ) {
			$this->log_step( 'step5_path_whitelist' );
			$this->current_request_data['action']  = 'path_whitelisted';
			$this->current_request_data['score']   = 0;
			$this->current_request_data['factors'][] = sprintf(
				/* translators: %s: Request path */
				__( 'Path whitelisted: %s', 'botfend-anti-bot-firewall' ),
				esc_html( $request_path )
			);
			$this->log_request_centralized();
			return;
		}

		// STEP 6: FACEBOOK IP CHECK.
		if ( $this->utilities->is_facebook_ip( $ip ) ) {
			$this->log_step( 'step6_facebook_ip' );
			$this->current_request_data['factors'][] = __( 'Facebook infrastructure IP', 'botfend-anti-bot-firewall' );
		}

		// STEP 7: CRAWLER VERIFICATION - Early exit for verified crawlers.
		$is_verified_crawler = false;
		if ( $this->config->get_bool( 'enable_crawler_verification', true ) ) {
			if ( $this->utilities->verify_legitimate_crawler( $ip, $user_agent ) ) {
				$this->log_step( 'step7_verified_crawler' );
				$is_verified_crawler = true;
				$crawler_name = $this->utilities->extract_crawler_from_ua( $user_agent );
				$this->current_request_data['factors'][] = sprintf(
					/* translators: %s: Crawler name */
					__( 'Verified %s crawler', 'botfend-anti-bot-firewall' ),
					esc_html( $crawler_name ?: 'legitimate' )
				);
				// Verified crawlers are always allowed
				$this->current_request_data['action'] = 'verified_crawler';
				$this->log_request_centralized();
				return;
			}
		}

		// STEP 8: INSTAGRAM CHECK.
		if ( $this->utilities->is_instagram_request( $ip, $user_agent ) ) {
			$this->log_step( 'step8_instagram' );
			$this->current_request_data['factors'][] = __( 'Instagram/Meta crawler detected', 'botfend-anti-bot-firewall' );
		}

		// STEP 9: LEGACY CRAWLER CHECK.
		if ( $this->config->get_bool( 'allow_legacy_crawlers', false ) && $this->utilities->is_known_crawler( $user_agent ) ) {
			$this->log_step( 'step9_legacy_crawler' );
			$this->current_request_data['factors'][] = __( 'Legacy crawler detected', 'botfend-anti-bot-firewall' );
		}

		// STEP 10: COUNTRY BLOCKING.
		if ( $country && ! $this->waf_only_mode ) {
			$country_block_action = $this->utilities->get_country_block_action( $country );
			$country_score        = $this->config->get_int( 'score_high_risk_country', 4 );

			switch ( $country_block_action ) {
				case 'block':
					$this->log_step( 'step10_country_block' );
					$this->current_request_data['action']  = 'country_block';
					$this->current_request_data['score']   = 10;
					$this->current_request_data['blocked'] = true;
					$this->current_request_data['factors'][] = sprintf(
						/* translators: %s: Country code */
						__( 'Country blocked: %s', 'botfend-anti-bot-firewall' ),
						esc_html( $country )
					);
					break;

				case 'challenge':
					$this->log_step( 'step10_country_challenge' );
					$this->current_request_data['score'] += $country_score;
					$this->current_request_data['challenged'] = true;
					$this->current_request_data['factors'][] = sprintf(
						/* translators: 1: Score added, 2: Country code */
						__( 'High-risk country (+%1$d score, challenge): %2$s', 'botfend-anti-bot-firewall' ),
						absint( $country_score ),
						esc_html( $country )
					);
					break;

				case 'score':
					$this->log_step( 'step10_country_score' );
					$this->current_request_data['score'] += $country_score;
					$this->current_request_data['factors'][] = sprintf(
						/* translators: 1: Score added, 2: Country code */
						__( 'High-risk country (+%1$d score): %2$s', 'botfend-anti-bot-firewall' ),
						absint( $country_score ),
						esc_html( $country )
					);
					break;
			}
		}

		// STEP 11: JS CHALLENGE CHECK.
		if ( isset( $this->challenges ) && $this->config->get_bool( 'enable_js_challenge', true ) && ! $this->waf_only_mode ) {
			$challenge_key     = self::TRANSIENT_PREFIX . 'challenge_passed_' . md5( $ip );
			$challenge_passed = get_transient( $challenge_key );

			if ( $challenge_passed ) {
				$this->log_step( 'step11_challenge_passed' );
				$this->current_request_data['action']  = 'challenge_passed';
				$this->current_request_data['factors'][] = __( 'JS challenge previously passed', 'botfend-anti-bot-firewall' );
				$this->log_request_centralized();
				return;
			}
		}

		// STEP 12: ADAPTIVE SAMPLING.
		if ( isset( $this->adaptive ) && $this->config->get_bool( 'enable_adaptive', true ) && ! $this->waf_only_mode && ! $this->skip_heavy_detection ) {
			if ( ! $this->adaptive->should_check_request( $ip ) ) {
				$this->log_step( 'step12_adaptive_sampled' );
				$this->current_request_data['action']  = 'sampled';
				$this->current_request_data['factors'][] = __( 'Request sampled (adaptive mode)', 'botfend-anti-bot-firewall' );
				$this->log_request_centralized();
				return;
			}
		}

		// STEP 13: CENTRALIZED DETECTION.
		if ( ! $this->skip_heavy_detection && method_exists( $this->detection, 'process_request_centralized' ) ) {
			$this->log_step( 'step13_detection' );
			$detection_result = $this->detection->process_request_centralized( $ip );

			$this->current_request_data['score']   += $detection_result['score'];
			if ( 'allowed' !== $detection_result['action'] ) {
				$this->current_request_data['action'] = $detection_result['action'];
			}
			$this->current_request_data['factors'] = array_merge( $this->current_request_data['factors'], $detection_result['factors'] );
			if ( $detection_result['blocked'] ) {
				$this->current_request_data['blocked'] = true;
			}
			if ( $detection_result['challenged'] ) {
				$this->current_request_data['challenged'] = true;
			}
		}

		// STEP 14: THREAT INTELLIGENCE - DISABLED BY DEFAULT (opt-in required)
		if ( $this->threat_intel && $this->config->get_bool( 'enable_threat_intel', false ) && ! $this->skip_heavy_detection ) {
			if ( method_exists( $this->threat_intel, 'check_ip' ) ) {
				$threat_result = $this->threat_intel->check_ip( $ip );
				$threat_score  = $this->config->get_int( 'score_known_attacker', 8 );

				if ( $threat_result && isset( $threat_result['score'] ) && $threat_result['score'] > 0 ) {
					$this->current_request_data['score'] += $threat_score;
					$this->current_request_data['factors'][] = sprintf(
						/* translators: 1: Score added, 2: Threat sources */
						__( 'Threat intelligence (+%1$d score): %2$s', 'botfend-anti-bot-firewall' ),
						absint( $threat_score ),
						esc_html( implode( ', ', $threat_result['sources'] ?? array() ) )
					);
				}
			}
		}

		// STEP 15: SIGNATURES.
		if ( $this->signatures && $this->config->get_bool( 'enable_signatures', true ) && ! $this->skip_heavy_detection ) {
			if ( method_exists( $this->signatures, 'analyze_request' ) ) {
				$signature_result = $this->signatures->analyze_request(
					$ip,
					$user_agent,
					$this->get_request_headers(),
					$request_path
				);

				if ( $signature_result && isset( $signature_result['score'] ) && $signature_result['score'] > 0 ) {
					$this->current_request_data['score'] += $signature_result['score'];
					$this->current_request_data['factors'][] = sprintf(
						/* translators: 1: Score added, 2: Signature count */
						__( 'Bot signatures (+%1$d score): %2$d detected', 'botfend-anti-bot-firewall' ),
						absint( $signature_result['score'] ),
						absint( $signature_result['signature_count'] ?? 0 )
					);
				}
			}
		}

		// STEP 16: WAF DETECTION.
		if ( $this->waf && $this->config->get_bool( 'enable_waf', true ) ) {
			$this->log_step( 'step16_waf' );
			$waf_score = apply_filters( 'botfend_waf_score', 0, $ip, $this->request_id );

			if ( $waf_score > 0 ) {
				$this->log_step( 'waf_detected' );
				$this->current_request_data['score'] += $waf_score;
				$this->current_request_data['factors'][] = sprintf(
					/* translators: %d: WAF score */
					__( 'WAF detection (+%d score)', 'botfend-anti-bot-firewall' ),
					absint( $waf_score )
				);
			}
		}

		// STEP 17: WORDPRESS PROTECTION.
		if ( $this->wordpress_protection && $this->config->get_bool( 'enable_wp_protection', true ) && ! $this->waf_only_mode ) {
			if ( method_exists( $this->wordpress_protection, 'check_request' ) ) {
				$wp_result = $this->wordpress_protection->check_request();
				if ( $wp_result && isset( $wp_result['detected'] ) && $wp_result['detected'] ) {
					$wp_score = $wp_result['score'] ?? 0;
					$this->current_request_data['score'] += $wp_score;
					$this->current_request_data['factors'][] = sprintf(
						/* translators: 1: Score added, 2: Rule name */
						__( 'WP Protection (+%1$d score): %2$s', 'botfend-anti-bot-firewall' ),
						absint( $wp_score ),
						esc_html( $wp_result['rule'] ?? 'detected' )
					);
				}
			}
		}

		// STEP 18: ADVANCED 404 DETECTION.
		if ( $this->advanced_404 && $this->config->get_bool( 'enable_advanced_404', true ) && is_404() && ! $this->skip_heavy_detection ) {
			if ( method_exists( $this->advanced_404, 'check_standard_404_abuse' ) &&
				method_exists( $this->advanced_404, 'analyze_path' ) &&
				method_exists( $this->advanced_404, 'update_404_count' ) ) {

				$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';

				// Standard 404 abuse (rate-based) - ADD SCORE.
				$standard_abuse_score = $this->advanced_404->check_standard_404_abuse( $ip );
				if ( $standard_abuse_score > 0 ) {
					$this->current_request_data['score'] += $standard_abuse_score;
					$this->current_request_data['factors'][] = sprintf(
						/* translators: %d: Score added */
						__( 'Standard 404 abuse (+%d score)', 'botfend-anti-bot-firewall' ),
						absint( $standard_abuse_score )
					);
				}

				// Advanced pattern detection.
				$advanced_result   = $this->advanced_404->analyze_path( $request_uri, $ip );
				$advanced_score    = $advanced_result['score'] ?? 0;
				$block_threshold   = $this->config->get_int( 'advanced_404_block_threshold', 5 );

				if ( $advanced_score >= $block_threshold ) {
					// IMMEDIATE BLOCK - do not accumulate.
					$this->current_request_data['action']   = 'advanced_404_block';
					$this->current_request_data['blocked']  = true;
					$this->current_request_data['score']    = 10;
					$this->current_request_data['factors'][] = sprintf(
						/* translators: 1: Score, 2: Pattern categories */
						__( 'Advanced 404 attack - Immediate block (Score: %1$d, Patterns: %2$s)', 'botfend-anti-bot-firewall' ),
						absint( $advanced_score ),
						esc_html( implode( ', ', $advanced_result['detected_categories'] ?? array() ) )
					);
				} elseif ( $advanced_score > 0 ) {
					// ADD TO SCORE.
					$this->current_request_data['score'] += $advanced_score;
					$this->current_request_data['factors'][] = sprintf(
						/* translators: 1: Score added, 2: Pattern categories */
						__( 'Suspicious 404 patterns (+%1$d score): %2$s', 'botfend-anti-bot-firewall' ),
						absint( $advanced_score ),
						esc_html( implode( ', ', $advanced_result['detected_categories'] ?? array() ) )
					);
				}

				// Update count for rate tracking.
				$this->advanced_404->update_404_count( $ip );
			}
		}

		// STEP 19: TOR DETECTION.
		if ( $this->tor_system && $this->config->get_bool( 'enable_tor_detection', false ) && ! $this->skip_heavy_detection ) {
			if ( method_exists( $this->database, 'is_tor_exit_node' ) && $this->database->is_tor_exit_node( $ip ) ) {
				$tor_action = $this->config->get_string( 'tor_action', 'challenge' );
				$tor_score  = $this->config->get_int( 'score_tor', 4 );

				switch ( $tor_action ) {
					case 'block':
						$this->current_request_data['action']   = 'tor_blocked';
						$this->current_request_data['score']    = 9;
						$this->current_request_data['blocked']  = true;
						$this->current_request_data['factors'][] = __( 'Tor exit node - Immediate block', 'botfend-anti-bot-firewall' );
						break;

					case 'challenge':
						$this->current_request_data['score']    += $tor_score;
						$this->current_request_data['action']    = 'tor_challenge';
						$this->current_request_data['challenged'] = true;
						$this->current_request_data['factors'][] = sprintf(
							/* translators: %d: Score added */
							__( 'Tor exit node (+%d score, challenge)', 'botfend-anti-bot-firewall' ),
							absint( $tor_score )
						);
						break;

					case 'add_score':
						$this->current_request_data['score']    += $tor_score;
						$this->current_request_data['factors'][] = sprintf(
							/* translators: %d: Score added */
							__( 'Tor exit node (+%d score)', 'botfend-anti-bot-firewall' ),
							absint( $tor_score )
						);
						break;

					case 'log_only':
						$this->current_request_data['score']    += $tor_score;
						$this->current_request_data['factors'][] = sprintf(
							/* translators: %d: Score added */
							__( 'Tor exit node (+%d score, logged only)', 'botfend-anti-bot-firewall' ),
							absint( $tor_score )
						);
						break;
				}
			}
		}

		// STEP 20: IPHUB CHECK - DISABLED BY DEFAULT (opt-in required)
		if ( $this->config->get_bool( 'enable_iphub', false ) && ! $this->skip_heavy_detection ) {
			if ( method_exists( $this->iphub, 'check_ip' ) ) {
				$iphub_result = $this->iphub->check_ip( $ip );

				if ( $iphub_result && isset( $iphub_result['action'] ) && 'block' === $iphub_result['action'] ) {
					$this->current_request_data['action']   = 'iphub_block';
					$this->current_request_data['score']    = 10;
					$this->current_request_data['blocked']  = true;
					$this->current_request_data['factors'][] = sprintf(
						/* translators: %s: IPHub reason */
						__( 'IPHub: %s', 'botfend-anti-bot-firewall' ),
						esc_html( $iphub_result['reason'] ?? '' )
					);
				}
			}
		}

		// STEP 21: ABUSEIPDB CHECK - DISABLED BY DEFAULT (opt-in required)
		if ( $this->config->get_bool( 'enable_abuseipdb', false ) && ! $this->skip_heavy_detection ) {
			if ( method_exists( $this->abuseipdb, 'check_ip' ) ) {
				$abuseipdb_result = $this->abuseipdb->check_ip( $ip );

				if ( $abuseipdb_result && isset( $abuseipdb_result['action'] ) ) {
					$action_type = $this->config->get_string( 'abuseipdb_action', 'block' );

					if ( 'block' === $abuseipdb_result['action'] && 'block' === $action_type ) {
						$this->current_request_data['action']   = 'abuseipdb_block';
						$this->current_request_data['score']    = 10;
						$this->current_request_data['blocked']  = true;
						$this->current_request_data['factors'][] = sprintf(
							/* translators: %s: AbuseIPDB reason */
							__( 'AbuseIPDB: %s', 'botfend-anti-bot-firewall' ),
							esc_html( $abuseipdb_result['reason'] ?? '' )
						);
					} elseif ( 'add_score' === $action_type && 'block' === $abuseipdb_result['action'] ) {
						$abuse_score = $this->config->get_int( 'score_known_attacker', 8 );
						$this->current_request_data['score'] += $abuse_score;
						$this->current_request_data['factors'][] = sprintf(
							/* translators: 1: Score added, 2: AbuseIPDB reason */
							__( 'AbuseIPDB flagged (+%1$d score): %2$s', 'botfend-anti-bot-firewall' ),
							absint( $abuse_score ),
							esc_html( $abuseipdb_result['reason'] ?? '' )
						);
					}
				}
			}
		}

		// STEP 22: FINAL ACTION PROCESSING.
		$this->log_step( 'step22_final_action' );

		// Cap score at 10.
		$this->current_request_data['score'] = min( 10, $this->current_request_data['score'] );

		$this->process_final_action();
	}

	/**
	 * Centralized logging for all requests.
	 *
	 * @return void
	 */
	private function log_request_centralized() {
		if ( empty( $this->current_request_data['ip'] ) ) {
			return;
		}

		$ip          = $this->current_request_data['ip'];
		$score       = $this->current_request_data['score'];
		$action      = $this->current_request_data['action'];
		$factors     = $this->current_request_data['factors'];
		$user_agent  = $this->current_request_data['user_agent'];
		$country     = $this->current_request_data['country'];
		$request_id  = $this->current_request_data['request_id'];

		$is_google_crawler = $this->utilities->is_google_crawler( $ip, $user_agent );
		$this->current_request_data['is_google_crawler'] = $is_google_crawler;

		if ( $this->logger && method_exists( $this->logger, 'queue_log' ) ) {
			$this->logger->queue_log(
				$ip,
				$score,
				$action,
				$factors,
				$user_agent,
				$is_google_crawler,
				$country,
				$request_id
			);
		} elseif ( method_exists( $this->database, 'log_request' ) ) {
			$this->database->log_request(
				$ip,
				$score,
				$action,
				$factors,
				$user_agent,
				$is_google_crawler,
				$country
			);
		}
	}

	/**
	 * Process final action based on accumulated score.
	 *
	 * @return void
	 */
	private function process_final_action() {
		$ip         = $this->current_request_data['ip'];
		$score      = $this->current_request_data['score'];
		$action     = $this->current_request_data['action'];
		$factors    = $this->current_request_data['factors'];
		$country    = $this->current_request_data['country'];
		$blocked    = $this->current_request_data['blocked'];
		$challenged = $this->current_request_data['challenged'];

		if ( ! $blocked && ! $challenged ) {
			
			// 1. Define standard thresholds for each mode
			$mode_presets = array(
				'learning'   => array( 'block' => 9, 'challenge' => 7 ),
				'balanced'   => array( 'block' => 8, 'challenge' => 6 ),
				'aggressive' => array( 'block' => 6, 'challenge' => 4 ),
				'emergency'  => array( 'block' => 4, 'challenge' => 2 ),
			);

			// 2. Determine which mode is actively driving the system
			$is_adaptive = $this->config->get_bool( 'enable_adaptive', true );
			$active_mode = 'balanced';

			if ( $is_adaptive && $this->adaptive && method_exists( $this->adaptive, 'get_protection_mode' ) ) {
				// Autopilot is ON: Get the dynamically shifting mode from the AI engine
				$active_mode = $this->adaptive->get_protection_mode();
			} else {
				// Autopilot is OFF: Get the hardcoded mode the user selected in the dropdown
				$active_mode = $this->config->get_string( 'adaptive_mode', 'balanced' );
			}

			// Ensure safe fallback if mode string is somehow invalid
			if ( ! isset( $mode_presets[ $active_mode ] ) ) {
				$active_mode = 'balanced';
			}

			// 3. Apply the thresholds strictly based on the active mode
			$auto_block_score = $mode_presets[ $active_mode ]['block'];
			$challenge_score  = $mode_presets[ $active_mode ]['challenge'];

			if ( $score >= $auto_block_score ) {
				$action  = 'blocked';
				$blocked = true;
			} elseif ( $score >= $challenge_score && $this->config->get_bool( 'enable_js_challenge', true ) && ! $this->waf_only_mode ) {
				$action     = 'challenged';
				$challenged = true;
			} else {
				$action = 'allowed';
			}

			$this->current_request_data['action']     = $action;
			$this->current_request_data['blocked']    = $blocked;
			$this->current_request_data['challenged'] = $challenged;
		}

		$this->log_request_centralized();

		if ( $blocked ) {
    // 1. Physically write the block to the Database FIRST
    $this->take_immediate_action();

    // 2. NOW sync the DB to the File System Cache
    // ========== FIREWALL INTEGRATION ==========
    $this->trigger_firewall_sync_on_block( $ip, $action, $score, $factors );
    // ===================================================
    
    $this->handle_blocked_access( $ip, false );
    exit;
} elseif ( $challenged && isset( $this->challenges ) && method_exists( $this->challenges, 'issue_js_challenge' ) ) {
			$this->challenges->issue_js_challenge( $ip );
			exit;
		}

		// Optional admin notification.
		if ( $score >= 8 && $this->config->get_bool( 'notify_admin', false ) ) {
			$this->notify_admin( $ip, $score );
		}
	}

	/**
	 * Take immediate action for critical threats.
	 *
	 * @return void
	 */
	private function take_immediate_action() {
		$ip       = $this->current_request_data['ip'];
		$score    = $this->current_request_data['score'];
		$action   = $this->current_request_data['action'];
		$factors  = $this->current_request_data['factors'];
		$country  = $this->current_request_data['country'];
		$log_only = $this->config->get_bool( 'log_only', false );

		if ( $log_only ) {
			return;
		}

		$duration = $this->config->get_int( 'block_duration', 24 );

		if ( ! method_exists( $this->database, 'block_ip' ) ) {
			return;
		}

		$blocked = false;
		$reason  = '';

		switch ( $action ) {
			case 'blocked':
			case 'iphub_block':
			case 'abuseipdb_block':
			case 'tor_blocked':
			case 'advanced_404_block':
				$reason = implode( ', ', $factors );
				$this->database->block_ip( $ip, 'auto_block', $reason, $score, $duration, $country );
				$blocked = true;
				break;

			case 'country_block':
				$reason = sprintf(
					/* translators: %s: Country code */
					__( 'Country blocked: %s', 'botfend-anti-bot-firewall' ),
					esc_html( $country )
				);
				$this->database->block_ip( $ip, 'country_block', $reason, $score, $duration, $country );
				$blocked = true;
				break;
		}
		
		// ========== FIREWALL INTEGRATION ==========
		if ( $blocked ) {
			do_action( 'botfend_ip_blocked', $ip, $action, $score, $reason );
		}
		// ===================================================
	}

	/**
	 * Handle blocked access.
	 *
	 * @param string $ip           IP address.
	 * @param bool   $is_permanent Whether block is permanent.
	 * @return void
	 */
	public function handle_blocked_access( $ip, $is_permanent = false ) {
		status_header( 403 );
		nocache_headers();

		$current_url = $this->get_current_url();

		if ( ! $is_permanent && isset( $_GET['request_unblock'] ) && $this->config->get_bool( 'allow_unblock', true ) ) {
			if ( ! isset( $_GET['botfend_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['botfend_nonce'] ) ), 'botfend_unblock_form' ) ) {
				$this->render_blocked_page( $ip, $is_permanent );
				exit;
			}
			$this->show_unblock_form( $ip );
			exit;
		}

		$this->render_blocked_page( $ip, $is_permanent );
	}

	/**
	 * Render blocked page HTML with external CSS and proper escaping.
	 *
	 * @param string $ip           IP address.
	 * @param bool   $is_permanent Whether block is permanent.
	 * @return void
	 */
	private function render_blocked_page( $ip, $is_permanent = false ) {
		$current_url = $this->get_current_url();
		$unblock_url = '';

		if ( ! $is_permanent && $this->config->get_bool( 'allow_unblock', true ) ) {
			$unblock_url = add_query_arg(
				array(
					'request_unblock' => 1,
					'botfend_nonce'   => wp_create_nonce( 'botfend_unblock_form' ),
				),
				$current_url
			);
		}
		?>
		<!DOCTYPE html>
		<html <?php language_attributes(); ?>>
		<head>
			<meta charset="<?php bloginfo( 'charset' ); ?>">
			<meta name="viewport" content="width=device-width, initial-scale=1.0">
			<meta name="robots" content="noindex, nofollow">
			<title><?php echo $is_permanent ? esc_html__( 'Access Permanently Restricted', 'botfend-anti-bot-firewall' ) : esc_html__( 'Access Restricted', 'botfend-anti-bot-firewall' ); ?></title>
			<?php echo $this->get_block_screen_css(); ?>
		</head>
		<body>
			<div class="container">
				<h1><?php echo $is_permanent ? esc_html__( 'Access Permanently Restricted', 'botfend-anti-bot-firewall' ) : esc_html__( 'Access Temporarily Restricted', 'botfend-anti-bot-firewall' ); ?></h1>

				<?php if ( $is_permanent ) : ?>
					<p><?php printf( esc_html__( 'Your IP address %s has been permanently blocked.', 'botfend-anti-bot-firewall' ), '<strong>' . esc_html( $ip ) . '</strong>' ); ?></p>
					<div class="notice permanent-notice">
						<strong><?php esc_html_e( 'Permanent Block', 'botfend-anti-bot-firewall' ); ?></strong>
						<p><?php esc_html_e( 'Contact the site administrator if you believe this is an error.', 'botfend-anti-bot-firewall' ); ?></p>
					</div>
				<?php else : ?>
					<p><?php printf( esc_html__( 'Our security system has detected unusual activity from your IP address %s.', 'botfend-anti-bot-firewall' ), '<strong>' . esc_html( $ip ) . '</strong>' ); ?></p>
					<div class="notice">
						<strong><?php esc_html_e( 'Possible reasons:', 'botfend-anti-bot-firewall' ); ?></strong>
						<ul>
							<li><?php esc_html_e( 'Unusually high number of requests', 'botfend-anti-bot-firewall' ); ?></li>
							<li><?php esc_html_e( 'Suspicious browsing patterns', 'botfend-anti-bot-firewall' ); ?></li>
							<li><?php esc_html_e( 'Using VPN/Proxy services that are abused by bots', 'botfend-anti-bot-firewall' ); ?></li>
							<li><?php esc_html_e( 'IP flagged in global threat databases', 'botfend-anti-bot-firewall' ); ?></li>
							<li><?php esc_html_e( 'Web Application Firewall detected attack patterns', 'botfend-anti-bot-firewall' ); ?></li>
							<li><?php esc_html_e( 'WordPress protection rules triggered', 'botfend-anti-bot-firewall' ); ?></li>
						</ul>
					</div>

					<div class="whitelist-info">
						<strong><?php esc_html_e( 'Whitelist Information:', 'botfend-anti-bot-firewall' ); ?></strong>
						<p><?php esc_html_e( 'If you are a legitimate user who needs regular access, you can request to be added to the whitelist. Whitelisted IPs bypass all security checks.', 'botfend-anti-bot-firewall' ); ?></p>
											</div>

					<p><?php esc_html_e( 'If you believe this is an error, you can:', 'botfend-anti-bot-firewall' ); ?></p>
					<ol>
						<li><?php esc_html_e( 'Try again in a few hours', 'botfend-anti-bot-firewall' ); ?></li>
						<li><?php esc_html_e( 'Disable any VPN or proxy services', 'botfend-anti-bot-firewall' ); ?></li>
						<li><?php esc_html_e( 'Request an unblock review by the administrator', 'botfend-anti-bot-firewall' ); ?></li>
						<li><?php esc_html_e( 'Request to be added to the whitelist for permanent access', 'botfend-anti-bot-firewall' ); ?></li>
					</ol>

					<?php if ( $this->config->get_bool( 'allow_unblock', true ) ) : ?>
						<p><a href="<?php echo esc_url( $unblock_url ); ?>" class="btn"><?php esc_html_e( 'Request Unblock Review', 'botfend-anti-bot-firewall' ); ?></a></p>
					<?php endif; ?>
				<?php endif; ?>

				<p><small><?php esc_html_e( 'This restriction helps protect our website from malicious bots and ensures a better experience for legitimate visitors.', 'botfend-anti-bot-firewall' ); ?></small></p>
			</div>
		</body>
		</html>
		<?php
		exit;
	}

	/**
	 * Show unblock request form with proper escaping.
	 *
	 * @param string $ip IP address.
	 * @return void
	 */
	private function show_unblock_form( $ip ) {
		$current_url = $this->get_current_url();
		?>
		<!DOCTYPE html>
		<html <?php language_attributes(); ?>>
		<head>
			<meta charset="<?php bloginfo( 'charset' ); ?>">
			<meta name="viewport" content="width=device-width, initial-scale=1.0">
			<meta name="robots" content="noindex, nofollow">
			<title><?php esc_html_e( 'Request Unblock Review', 'botfend-anti-bot-firewall' ); ?></title>
			<?php echo $this->get_unblock_form_css(); ?>
		</head>
		<body>
			<div class="container">
				<h1><?php esc_html_e( 'Request Access Review', 'botfend-anti-bot-firewall' ); ?></h1>

				<?php if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] ) : ?>
					<?php
					if ( ! isset( $_POST['botfend_unblock_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['botfend_unblock_nonce'] ) ), 'botfend_unblock_request' ) ) {
						echo '<div class="error">' . esc_html__( 'Security check failed. Please try again.', 'botfend-anti-bot-firewall' ) . '</div>';
					} else {
						$email              = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
						$reason             = isset( $_POST['reason'] ) ? sanitize_textarea_field( wp_unslash( $_POST['reason'] ) ) : '';
						$request_whitelist  = isset( $_POST['request_whitelist'] ) && '1' === $_POST['request_whitelist'];

						if ( $this->submit_unblock_request( $ip, $email, $reason, $request_whitelist ) ) {
							echo '<div class="success">' . esc_html__( 'Your request has been submitted. The site administrator will review it shortly.', 'botfend-anti-bot-firewall' ) . '</div>';
						} else {
							echo '<div class="error">' . esc_html__( 'There was an error submitting your request. You may already have a pending request for this IP.', 'botfend-anti-bot-firewall' ) . '</div>';
						}
					}
					?>
				<?php else : ?>
					<p><?php esc_html_e( 'Please provide your email address and reason for requesting access:', 'botfend-anti-bot-firewall' ); ?></p>

					<div class="whitelist-info">
						<strong><?php esc_html_e( 'Whitelist Option:', 'botfend-anti-bot-firewall' ); ?></strong>
						<p><?php esc_html_e( 'If you need permanent, unrestricted access, you can request to be added to the whitelist. Whitelisted IPs bypass ALL security checks.', 'botfend-anti-bot-firewall' ); ?></p>
					</div>

					<form method="POST" action="<?php echo esc_url( $current_url ); ?>">
						<?php wp_nonce_field( 'botfend_unblock_request', 'botfend_unblock_nonce' ); ?>
						<input type="email" name="email" placeholder="<?php esc_attr_e( 'Your email address', 'botfend-anti-bot-firewall' ); ?>" required>
						<textarea name="reason" rows="4" placeholder="<?php esc_attr_e( 'Why do you need access? Please explain your use case.', 'botfend-anti-bot-firewall' ); ?>" required></textarea>
						<label style="display: block; margin: 10px 0;">
							<input type="checkbox" name="request_whitelist" value="1">
							<?php esc_html_e( 'Request to be added to whitelist for permanent access', 'botfend-anti-bot-firewall' ); ?>
						</label>
						<button type="submit"><?php esc_html_e( 'Submit Request', 'botfend-anti-bot-firewall' ); ?></button>
					</form>

					<p><small><?php printf( esc_html__( 'Your IP address: %s', 'botfend-anti-bot-firewall' ), '<strong>' . esc_html( $ip ) . '</strong>' ); ?></small></p>
					<p><small><?php esc_html_e( 'Note: This is a manual review process. Please allow 24-48 hours for a response.', 'botfend-anti-bot-firewall' ); ?></small></p>
				<?php endif; ?>
			</div>
		</body>
		</html>
		<?php
		exit;
	}

	/**
	 * Handle AJAX unblock request with proper nonce verification.
	 *
	 * @return void
	 */
	public function handle_unblock_request() {
		// Verify nonce first
		if ( ! check_ajax_referer( 'botfend_unblock', 'nonce', false ) ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'botfend-anti-bot-firewall' ) ) );
		}
		
		if ( ! $this->config->get_bool( 'disable_sessions', false ) ) {
			wp_send_json_error( array( 'message' => __( 'Unblock requests are disabled.', 'botfend-anti-bot-firewall' ) ) );
		}

		$ip = $this->utilities->get_client_ip();

		if ( $this->utilities->is_rate_limited_api( 'unblock_request', $ip, 3, 300 ) ) {
			wp_send_json_error( array( 'message' => __( 'Too many requests. Please try again later.', 'botfend-anti-bot-firewall' ) ) );
		}

		$ip                = isset( $_POST['ip'] ) ? sanitize_text_field( wp_unslash( $_POST['ip'] ) ) : '';
		$email             = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
		$reason            = isset( $_POST['reason'] ) ? sanitize_textarea_field( wp_unslash( $_POST['reason'] ) ) : '';
		$request_whitelist = isset( $_POST['request_whitelist'] ) && '1' === $_POST['request_whitelist'];

		if ( $this->submit_unblock_request( $ip, $email, $reason, $request_whitelist ) ) {
			wp_send_json_success( array( 'message' => __( 'Request submitted successfully', 'botfend-anti-bot-firewall' ) ) );
		} else {
			wp_send_json_error( array( 'message' => __( 'Failed to submit request', 'botfend-anti-bot-firewall' ) ) );
		}
	}

	/**
	 * Resolve security conflict (admin AJAX).
	 *
	 * @return void
	 */
	public function resolve_security_conflict() {
		// Verify nonce first
		if ( ! check_ajax_referer( self::ADMIN_NONCE_KEY, 'nonce', false ) ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'botfend-anti-bot-firewall' ) ) );
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Permission denied.', 'botfend-anti-bot-firewall' ) );
		}

		$ip     = isset( $_POST['ip'] ) ? sanitize_text_field( wp_unslash( $_POST['ip'] ) ) : '';
		$action = isset( $_POST['action_type'] ) ? sanitize_text_field( wp_unslash( $_POST['action_type'] ) ) : '';

		if ( empty( $ip ) || empty( $action ) ) {
			wp_send_json_error( array( 'message' => __( 'Invalid parameters.', 'botfend-anti-bot-firewall' ) ) );
		}

		switch ( $action ) {
			case 'add_to_whitelist':
				$result  = $this->add_to_whitelist( $ip );
				$message = __( 'Added to whitelist. This IP will now bypass all blocks.', 'botfend-anti-bot-firewall' );
				break;
			case 'remove_from_whitelist':
				$result  = $this->remove_from_whitelist( $ip );
				$message = __( 'Removed from whitelist.', 'botfend-anti-bot-firewall' );
				break;
			case 'remove_block':
				$result  = $this->remove_from_blocklist( $ip );
				$message = __( 'Removed from blocklist.', 'botfend-anti-bot-firewall' );
				break;
			case 'keep_block':
				$result  = $this->log_resolution( $ip, 'block_maintained' );
				$message = __( 'Block maintained (whitelist was removed).', 'botfend-anti-bot-firewall' );
				break;
			default:
				wp_send_json_error( array( 'message' => __( 'Invalid action.', 'botfend-anti-bot-firewall' ) ) );
		}

		if ( $result ) {
			$this->clear_violation_for_ip( $ip );
			wp_send_json_success( array( 'message' => $message ) );
		} else {
			wp_send_json_error( array( 'message' => __( 'Failed to resolve conflict.', 'botfend-anti-bot-firewall' ) ) );
		}
	}

	/**
	 * Add IP to whitelist with validation.
	 *
	 * @param string $ip IP address.
	 * @return bool
	 */
	private function add_to_whitelist( $ip ) {
		// Validate IP or CIDR
		if ( ! $this->validate_ip_for_checks( $ip ) && ! $this->is_valid_cidr( $ip, true ) ) {
			return false;
		}

		$whitelist = $this->config->get_string( 'botfend_whitelist_ips', '' );
		$lines     = explode( "\n", $whitelist );

		foreach ( $lines as $line ) {
			$line = trim( $line );
			if ( $line === $ip ) {
				return true;
			}
		}

		$lines[] = $ip;
		$result  = $this->config->set( 'botfend_whitelist_ips', implode( "\n", array_filter( $lines ) ) );

		if ( $result ) {
			$this->utilities->debug_log( 'Added IP to whitelist', array( 'ip' => $ip ) );
			if ( method_exists( $this->database, 'remove_block' ) ) {
				$this->database->remove_block( $ip );
			}
			$this->remove_from_blocklist( $ip );
			
			// ========== FIREWALL INTEGRATION ==========
			do_action( 'botfend_ip_unblocked', $ip );
			// ===================================================
		}

		return $result;
	}

	/**
	 * Remove IP from whitelist.
	 *
	 * @param string $ip IP address.
	 * @return bool
	 */
	private function remove_from_whitelist( $ip ) {
		$whitelist = $this->config->get_string( 'botfend_whitelist_ips', '' );
		$lines     = explode( "\n", $whitelist );

		$new_lines = array_filter(
			$lines,
			function ( $line ) use ( $ip ) {
				$line = trim( $line );
				return ! empty( $line ) && $line !== $ip && 0 !== strpos( $line, '#' );
			}
		);

		$result = $this->config->set( 'botfend_whitelist_ips', implode( "\n", $new_lines ) );

		if ( $result ) {
			$this->utilities->debug_log( 'Removed IP from whitelist', array( 'ip' => $ip ) );
		}

		return $result;
	}

	/**
	 * Remove IP from permanent blocklist.
	 *
	 * @param string $ip IP address.
	 * @return bool
	 */
	private function remove_from_blocklist( $ip ) {
		$blocklist = $this->config->get_string( 'botfend_permanent_blocklist', '' );
		$lines     = explode( "\n", $blocklist );

		$new_lines = array_filter(
			$lines,
			function ( $line ) use ( $ip ) {
				$line = trim( $line );
				return ! empty( $line ) && $line !== $ip && 0 !== strpos( $line, '#' );
			}
		);

		$result = $this->config->set( 'botfend_permanent_blocklist', implode( "\n", $new_lines ) );

		if ( $result ) {
			$this->utilities->debug_log( 'Removed IP from permanent blocklist', array( 'ip' => $ip ) );
			
			// ========== FIREWALL INTEGRATION ==========
			do_action( 'botfend_ip_unblocked', $ip );
			// ===================================================
		}

		return $result;
	}

	/**
	 * Log resolution of security conflict.
	 *
	 * @param string $ip         IP address.
	 * @param string $resolution Resolution type.
	 * @return bool
	 */
	private function log_resolution( $ip, $resolution ) {
		$violations = get_option( 'botfend_security_violations', array() );

		foreach ( $violations as &$violation ) {
			if ( $violation['ip'] === $ip && ! $violation['resolved'] ) {
				$violation['resolved']     = true;
				$violation['resolution']   = sanitize_text_field( $resolution );
				$violation['resolved_at']  = current_time( 'mysql' );
				break;
			}
		}

		return update_option( 'botfend_security_violations', $violations, false );
	}

	/**
	 * Clear security violation for IP.
	 *
	 * @param string $ip IP address.
	 * @return void
	 */
	private function clear_violation_for_ip( $ip ) {
		$violations = get_option( 'botfend_security_violations', array() );

		$new_violations = array_filter(
			$violations,
			function ( $violation ) use ( $ip ) {
				return $violation['ip'] !== $ip || false !== $violation['resolved'];
			}
		);

		update_option( 'botfend_security_violations', array_values( $new_violations ), false );
	}

	/**
	 * Submit unblock request to database.
	 *
	 * @param string $ip                IP address.
	 * @param string $email             User email.
	 * @param string $reason            Request reason.
	 * @param bool   $request_whitelist Whether to request whitelist.
	 * @return bool
	 */
	private function submit_unblock_request( $ip, $email, $reason, $request_whitelist = false ) {
		if ( ! method_exists( $this->database, 'submit_unblock_request' ) ) {
			return false;
		}
		return $this->database->submit_unblock_request( $ip, $email, $reason, $request_whitelist );
	}

	/**
	 * Log 404 abuse (placeholder for hook).
	 *
	 * @return void
	 */
	public function log_404_abuse() {
		// This method exists for the hook - actual logging is in Advanced404 class.
	}

	/**
	 * Notify admin about high-risk request.
	 *
	 * @param string $ip    IP address.
	 * @param int    $score Threat score.
	 * @return void
	 */
	private function notify_admin( $ip, $score ) {
		if ( ! $this->config->get_bool( 'notify_admin', false ) ) {
			return;
		}

		$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
		$country    = $this->utilities->get_country( $ip );
		$subject    = sprintf(
			/* translators: %s: IP address */
			__( '[BotFend Anti-Bot Firewall] High-risk request from %s', 'botfend-anti-bot-firewall' ),
			$ip
		);
		$message    = sprintf(
			/* translators: 1: IP address, 2: Score, 3: Country, 4: User Agent */
			__( "BotFend Anti-Bot Firewall detected a high-risk request:\n\nIP: %1\$s\nScore: %2\$d\nCountry: %3\$s\nUser Agent: %4\$s\nTime: %5\$s",
				'botfend-anti-bot-firewall'
			),
			$ip,
			$score,
			$country,
			$user_agent,
			current_time( 'mysql' )
		);

		wp_mail( get_option( 'admin_email' ), $subject, $message );
	}

	/**
	 * Get security violations for admin.
	 *
	 * @return array
	 */
	public function get_security_violations() {
		return get_option( 'botfend_security_violations', array() );
	}

	/**
	 * Clear all security violations.
	 *
	 * @return bool
	 */
	public function clear_all_security_violations() {
		return update_option( 'botfend_security_violations', array(), false );
	}

	/**
	 * Get all components.
	 *
	 * @return array
	 */
	public function get_components() {
		return array(
			'utilities'             => $this->utilities,
			'database'              => $this->database,
			'detection'             => $this->detection,
			'iphub'                 => $this->iphub,
			'abuseipdb'             => $this->abuseipdb,
			'challenges'            => $this->challenges,
			'adaptive'              => $this->adaptive,
			'threat_intel'          => $this->threat_intel,
			'signatures'            => $this->signatures,
			'tor_system'            => $this->tor_system,
			'advanced_404'          => $this->advanced_404,
			'connection_fp'         => $this->connection_fp,
			'intelligent_session'   => $this->intelligent_session,
			'behavioral_analyzer'   => $this->behavioral_analyzer,
			'waf'                   => $this->waf,
			'wordpress_protection'  => $this->wordpress_protection,
			'logger'                => $this->logger,
			'config'                => $this->config,
		);
	}

	/**
	 * Get WordPress protection component.
	 *
	 * @return WordPressProtection|null
	 */
	public function get_wordpress_protection() {
		return $this->wordpress_protection;
	}

	/**
	 * Get protection status.
	 *
	 * @return array
	 */
	public function get_protection_status() {
		$violations            = $this->get_security_violations();
		$unresolved_violations = array_filter(
			$violations,
			function ( $v ) {
				return ! $v['resolved'];
			}
		);

		$transient_health = $this->check_transient_system_health();

		return array(
			'enabled'                      => $this->config->get_bool( 'botfend_enabled', true ),
			'adaptive_enabled'             => $this->config->get_bool( 'enable_adaptive', true ),
			'threat_intel_enabled'         => $this->config->get_bool( 'enable_threat_intel', false ),
			'signatures_enabled'           => $this->config->get_bool( 'enable_signatures', true ),
			'waf_enabled'                  => $this->config->get_bool( 'enable_waf', true ),
			'wordpress_protection_enabled' => $this->config->get_bool( 'enable_wp_protection', true ),
			'crawler_verification_enabled' => $this->config->get_bool( 'enable_crawler_verification', true ),
			'centralized_logging_enabled'  => $this->config->get_bool( 'enable_centralized_logging', true ),
			'current_mode'                 => isset( $this->adaptive ) ? $this->adaptive->get_protection_mode() : 'balanced',
			'attack_level'                 => isset( $this->adaptive ) ? $this->adaptive->get_attack_level() : 0,
			'security_hierarchy'           => 'whitelist_superior',
			'whitelist_priority'           => 'highest',
			'unresolved_conflicts'         => count( $unresolved_violations ),
			'total_conflicts'              => count( $violations ),
			'transient_system'             => $transient_health['status'],
			'transient_count'              => $transient_health['count'],
			'using_php_sessions'           => false,
			'storage_method'               => 'wordpress_transients',
		);
	}

	/**
	 * Get request metrics.
	 *
	 * @return array
	 */
	public function get_request_metrics() {
		return array(
			'steps_executed'    => $this->steps_executed,
			'steps_count'       => count( $this->steps_executed ),
			'final_score'       => $this->current_request_data['score'] ?? 0,
			'final_action'      => $this->current_request_data['action'] ?? 'unknown',
			'request_processed' => $this->request_processed,
			'request_id'        => $this->request_id,
			'skip_heavy'        => $this->skip_heavy_detection,
			'waf_only'          => $this->waf_only_mode,
		);
	}

	/**
	 * Check transient system health.
	 *
	 * @return array
	 */
	private function check_transient_system_health() {
		global $wpdb;

		$count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE %s",
				'_transient_botfend_%'
			)
		);

		$status = 'healthy';
		if ( $count > 1000 ) {
			$status = 'warning';
		}
		if ( $count > 5000 ) {
			$status = 'critical';
		}

		return array(
			'status' => $status,
			'count'  => absint( $count ),
		);
	}

	/**
	 * Display security hierarchy info in admin.
	 *
	 * @return void
	 */
	public function display_security_hierarchy_info() {
		?>
		<div class="notice notice-success">
			<h3><?php esc_html_e( 'Security Hierarchy: Whitelist Superior', 'botfend-anti-bot-firewall' ); ?></h3>
			<p><?php esc_html_e( 'BotFend Anti-Bot Firewall uses the following security hierarchy:', 'botfend-anti-bot-firewall' ); ?></p>
			<ol>
				<li><strong><?php esc_html_e( 'Whitelist', 'botfend-anti-bot-firewall' ); ?></strong> - <?php esc_html_e( 'Highest priority. Whitelisted IPs bypass ALL blocks and protection.', 'botfend-anti-bot-firewall' ); ?></li>
				<li><strong><?php esc_html_e( 'Permanent Blocks', 'botfend-anti-bot-firewall' ); ?></strong> - <?php esc_html_e( 'Second priority. Cannot be overridden except by whitelist.', 'botfend-anti-bot-firewall' ); ?></li>
				<li><strong><?php esc_html_e( 'Active Blocks', 'botfend-anti-bot-firewall' ); ?></strong> - <?php esc_html_e( 'Third priority. Auto-generated blocks.', 'botfend-anti-bot-firewall' ); ?></li>
				<li><strong><?php esc_html_e( 'Centralized Detection', 'botfend-anti-bot-firewall' ); ?></strong> - <?php esc_html_e( 'Single entry point for all security checks and logging.', 'botfend-anti-bot-firewall' ); ?></li>
			</ol>
			<p><strong><?php esc_html_e( 'Important:', 'botfend-anti-bot-firewall' ); ?></strong> <?php esc_html_e( 'All security components accumulate scores. Critical threats trigger immediate blocks.', 'botfend-anti-bot-firewall' ); ?></p>
		</div>
		<?php
	}

	/**
	 * Clear admin cache by type.
	 *
	 * @param string $cache_type Cache type to clear.
	 * @return void
	 */
	public function clear_admin_cache( $cache_type = 'all' ) {
		switch ( $cache_type ) {
			case 'stats':
				$this->invalidate_pattern_cache( 'botfend_stats_' );
				break;
			case 'logs':
				$this->invalidate_pattern_cache( 'botfend_logs_' );
				break;
			case 'waf':
				$this->invalidate_pattern_cache( 'botfend_waf_' );
				break;
			case 'all':
				$this->invalidate_pattern_cache( 'botfend_' );
				break;
			default:
				$this->invalidate_pattern_cache( 'botfend_' . $cache_type . '_' );
				break;
		}
	}

	/**
 * Invalidate pattern cache with external object cache compatibility.
 *
 * @param string $pattern Cache key pattern (ignored - full group flush required for Redis).
 * @return void
 */
private function invalidate_pattern_cache( $pattern ) {
    // Enterprise environments use Redis/Memcached. We cannot iterate keys.
    // Flushing the entire group is the only safe way to invalidate external object caches.
    if ( function_exists( 'wp_cache_flush_group' ) ) {
        wp_cache_flush_group( self::CACHE_GROUP );
        return;
    }
    
    // Fallback for environments without group flush support
    global $wp_object_cache;
    if ( isset( $wp_object_cache->cache[ self::CACHE_GROUP ] ) ) {
        foreach ( array_keys( $wp_object_cache->cache[ self::CACHE_GROUP ] ) as $key ) {
            if ( 0 === strpos( $key, $pattern ) ) {
                wp_cache_delete( $key, self::CACHE_GROUP );
            }
        }
    }
}

	/**
	 * Check if a feature is available.
	 *
	 * @param string $feature Feature name.
	 * @return bool
	 */
	public function is_feature_available( $feature ) {
		$features = array(
			'adaptive_sampling'    => $this->config->get_bool( 'enable_adaptive_sampling', true ),
			'centralized_logging'  => $this->config->get_bool( 'enable_centralized_logging', true ),
		);

		return $features[ $feature ] ?? false;
	}

/*
|==========================================================================
| FIREWALL INTEGRATION METHODS
*/

/**
 * Sync firewall blocklist cache file.
 */
public function sync_firewall_blocklist_cache( $ip = null ): bool {
    // Only run if firewall setup class exists
    if ( ! class_exists( 'BotFend\Core\FirewallSetup' ) ) {
        $firewall_file = BOTFEND_PATH . 'includes/core/FirewallSetup.php';
        if ( file_exists( $firewall_file ) ) {
            require_once $firewall_file;
        } else {
            // Silent failure - firewall not installed
            return false;
        }
    }
    
    if ( ! class_exists( 'BotFend\Core\FirewallSetup' ) ) {
        return false;
    }
    
    $config = Config::get_instance();
    $firewall_setup = new \BotFend\Core\FirewallSetup( $config, $this->utilities );
    
    $firewall_setup->set_database( $this->database );
    
    return $firewall_setup->sync_blocklist_from_database();
}

	/**
	 * Sync firewall whitelist cache file.
	 *
	 *
	 * @since 4.8.1
	 * @return bool True on success, false on failure
	 */
	public function sync_firewall_whitelist_cache( $old_value = null, $new_value = null ): bool {
		if ( ! class_exists( 'BotFend\Core\FirewallSetup' ) ) {
			$firewall_file = BOTFEND_PATH . 'includes/core/FirewallSetup.php';
			if ( file_exists( $firewall_file ) ) {
				require_once $firewall_file;
			} else {
				return false;
			}
		}
		
		if ( ! class_exists( 'BotFend\Core\FirewallSetup' ) ) {
			return false;
		}
		
		$config = Config::get_instance();
		$firewall_setup = new \BotFend\Core\FirewallSetup( $config, $this->utilities );
		return $firewall_setup->update_whitelist_cache();
	}

	/**
	 * Hook callback for whitelist config updates.
	 *
	 * @since 4.8.1
	 * @param string $option_name Option name
	 * @param mixed  $value       Option value
	 * @return void
	 */
	public function sync_firewall_whitelist_on_config_update( $option_name, $value ): void {
		if ( $option_name === 'botfend_whitelist_ips' ) {
			$this->sync_firewall_whitelist_cache( null, $value );
		}
	}

	/**
	 * Trigger firewall cache sync after block.
	 *
	 * Called from process_final_action() when a block occurs.
	 * Lightweight async-friendly - fires after response sent if possible.
	 *
	 * @since 4.8.1
	 * @param string $ip      Blocked IP address
	 * @param string $action  Block action type
	 * @param int    $score   Threat score
	 * @param array  $factors Detection factors
	 * @return void
	 */
	private function trigger_firewall_sync_on_block( $ip, $action = '', $score = 0, $factors = array() ): void {
		// Fast path - check if firewall is enabled
		if ( ! $this->config->get_bool( 'firewall_enabled', true ) ) {
			return;
		}
		
		// Trigger the action for immediate sync (other hooks may listen)
		do_action( 'botfend_ip_blocked', $ip, $action, $score, $factors );
		
		// Use shutdown hook for non-blocking sync (WordPress best practice)
		// This ensures the cache is updated even if the request ends early
		add_action( 'shutdown', function() {
			$this->sync_firewall_blocklist_cache();
		}, 20 );
	}
}
					