<?php
/**
 * Real-time behavioral analysis for bot detection
 * Detects automated behavior patterns without JavaScript
 *
 * @package BotFend\Security
 * @since 4.3.0
 * @version 4.8.3 - Rebranded from SafeBot, fixed object cache sync
 */

namespace BotFend\Security;

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

defined('ABSPATH') || exit;

/**
 * Class BehavioralAnalyzer
 *
 * Detects automated bot behavior by analyzing request patterns,
 * timing, and navigation sequences. Fully configurable with weights
 * and exemptions for different user roles and paths.
 *
 * @since 4.3.0
 */
class BehavioralAnalyzer {
    
    private $config;
    private $utilities;
    private $database;
    private $behavior_cache = [];
    private $patterns = [];
    private $settings = [];
    private static $compiled_patterns = null;
    
    private const MAX_SCORE = 10;
    private const CACHE_TTL = 300;
    private const MAX_REQUESTS = 50;
    private const MAX_TRACKING_CACHE = 1000;
    
    public function __construct(Utilities $utilities, Database $database) {
        $this->config = Config::get_instance();
        $this->utilities = $utilities;
        $this->database = $database;
        
        $this->load_settings();
        $this->load_detection_patterns();
        
        add_action('init', [$this, 'analyze_behavior'], 5);
        add_action('shutdown', [$this, 'finalize_behavior_analysis']);
    }
    
    private function load_settings() {
        $this->settings = [
            'min_requests' => $this->config->get_int('behavior_min_requests', 5),
            'time_window' => $this->config->get_int('behavior_time_window', 300),
            'block_threshold' => $this->config->get_int('behavior_block_threshold', 10),
            
            'penalty_enabled' => $this->config->get_bool('behavior_penalty_enabled', true),
            'max_penalty' => $this->config->get_int('behavior_max_penalty', 5),
            'penalty_ttl' => $this->config->get_int('behavior_penalty_ttl', 3600),
            
            'weights' => [
                'sequential_access' => $this->config->get_int('weight_sequential', 3),
                'burst_pattern' => $this->config->get_int('weight_burst', 4),
                'random_paths' => $this->config->get_int('weight_random_paths', 2),
                'no_referrer' => $this->config->get_int('weight_no_referrer', 1),
                'fixed_timing' => $this->config->get_int('weight_fixed_timing', 3),
                'mixed_methods' => $this->config->get_int('weight_mixed_methods', 2),
                'parameter_scanning' => $this->config->get_int('weight_parameter_scan', 4),
                'suspicious_headers' => $this->config->get_int('weight_suspicious_headers', 2),
                'excessive_length' => $this->config->get_int('weight_excessive_length', 1),
            ],
            
            'exempt_admins' => $this->config->get_bool('behavior_exempt_admins', true),
            'exempt_editors' => $this->config->get_bool('behavior_exempt_editors', true),
            'exempt_logged_in' => $this->config->get_bool('behavior_exempt_logged_in', true),
            'exempt_ajax' => $this->config->get_bool('behavior_exempt_ajax', true),
            'exempt_api' => $this->config->get_bool('behavior_exempt_api', true),
            'exempt_paths' => $this->parse_exempt_paths(
                $this->config->get_string('behavior_exempt_paths', "/wp-admin/*\n/wp-login.php\n/wp-json/*\n/wp-cron.php")
            ),
            
            'sensitivity' => $this->config->get_string('behavior_sensitivity', 'medium'),
            'max_tracking' => $this->config->get_int('behavior_max_tracking', 100),
            'tracking_ttl' => $this->config->get_int('behavior_tracking_ttl', 3600),
        ];
        
        $this->apply_sensitivity_multiplier();
    }
    
    private function apply_sensitivity_multiplier() {
        $multiplier = 1.0;
        
        switch ($this->settings['sensitivity']) {
            case 'low':
                $multiplier = 0.7;
                break;
            case 'high':
                $multiplier = 1.5;
                break;
            case 'custom':
                return;
            default: // medium
                $multiplier = 1.0;
        }
        
        foreach ($this->settings['weights'] as $key => $value) {
            $this->settings['weights'][$key] = min(10, max(1, (int) round($value * $multiplier)));
        }
    }
    
    private function parse_exempt_paths($paths_string) {
        $paths = explode("\n", $paths_string);
        $clean_paths = [];
        
        foreach ($paths as $path) {
            $path = trim($path);
            if (!empty($path)) {
                $clean_paths[] = $path;
            }
        }
        
        return $clean_paths;
    }
    
    private function should_exempt_user(): bool {
        $ip = $this->utilities->get_client_ip();
        if ($this->utilities->is_ip_whitelisted($ip)) {
            return true;
        }
        
        if ($this->database->is_ip_blocked($ip)) {
            return true;
        }
        
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? 
            sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
        if ($this->utilities->verify_legitimate_crawler($ip, $user_agent)) {
            return true;
        }
        
        if (is_user_logged_in()) {
            $current_user = wp_get_current_user();
            
            if ($this->settings['exempt_admins'] && in_array('administrator', $current_user->roles, true)) {
                return true;
            }
            
            if ($this->settings['exempt_editors'] && in_array('editor', $current_user->roles, true)) {
                return true;
            }
            
            if ($this->settings['exempt_logged_in']) {
                return true;
            }
        }
        
        return false;
    }
    
    private function should_exempt_path(): bool {
        $request_uri = isset($_SERVER['REQUEST_URI']) ? 
            esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : '';
        
        if ($this->settings['exempt_ajax'] && wp_doing_ajax()) {
            return true;
        }
        
        if ($this->settings['exempt_api'] && (defined('REST_REQUEST') && REST_REQUEST)) {
            return true;
        }
        
        foreach ($this->settings['exempt_paths'] as $pattern) {
            if (strpos($pattern, '*') !== false) {
                $regex = str_replace(['*', '/'], ['.*', '\/'], $pattern);
                if (preg_match('/^' . $regex . '$/', $request_uri)) {
                    return true;
                }
            } elseif (strpos($request_uri, $pattern) !== false) {
                return true;
            }
        }
        
        $whitelisted_paths = $this->config->get_string('whitelisted_paths', '');
        $paths = explode("\n", $whitelisted_paths);
        foreach ($paths as $path) {
            $path = trim($path);
            if (!empty($path) && strpos($request_uri, $path) !== false) {
                return true;
            }
        }
        
        return false;
    }
    
    private function load_detection_patterns() {
        if (self::$compiled_patterns !== null) {
            $this->patterns = self::$compiled_patterns;
            return;
        }
        
        $this->patterns = [
            'sequential_access' => [
                'description' => esc_html__('Sequential page access', 'botfend-anti-bot-firewall'),
                'weight' => $this->settings['weights']['sequential_access'],
                'detection' => 'sequential'
            ],
            'burst_pattern' => [
                'description' => esc_html__('Burst requests in short time', 'botfend-anti-bot-firewall'),
                'weight' => $this->settings['weights']['burst_pattern'],
                'detection' => 'burst'
            ],
            'random_paths' => [
                'description' => esc_html__('Random navigation patterns', 'botfend-anti-bot-firewall'),
                'weight' => $this->settings['weights']['random_paths'],
                'detection' => 'random'
            ],
            'no_referrer' => [
                'description' => esc_html__('Missing referrers', 'botfend-anti-bot-firewall'),
                'weight' => $this->settings['weights']['no_referrer'],
                'detection' => 'referrer'
            ],
            'fixed_timing' => [
                'description' => esc_html__('Consistent request timing', 'botfend-anti-bot-firewall'),
                'weight' => $this->settings['weights']['fixed_timing'],
                'detection' => 'timing'
            ],
            'mixed_methods' => [
                'description' => esc_html__('Unusual HTTP methods', 'botfend-anti-bot-firewall'),
                'weight' => $this->settings['weights']['mixed_methods'],
                'detection' => 'methods'
            ],
            'parameter_scanning' => [
                'description' => esc_html__('Parameter fuzzing', 'botfend-anti-bot-firewall'),
                'weight' => $this->settings['weights']['parameter_scanning'],
                'detection' => 'parameters'
            ],
            'suspicious_headers' => [
                'description' => esc_html__('Suspicious headers', 'botfend-anti-bot-firewall'),
                'weight' => $this->settings['weights']['suspicious_headers'],
                'detection' => 'headers'
            ],
            'excessive_length' => [
                'description' => esc_html__('Excessive request length', 'botfend-anti-bot-firewall'),
                'weight' => $this->settings['weights']['excessive_length'],
                'detection' => 'length'
            ]
        ];
        
        self::$compiled_patterns = $this->patterns;
    }
    
    private function get_session_identifier($ip) {
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? 
                     sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
        
        $daily_salt = get_transient('botfend_behavior_salt');
        if (false === $daily_salt) {
            $daily_salt = wp_generate_password(32, false);
            set_transient('botfend_behavior_salt', $daily_salt, DAY_IN_SECONDS);
        }
        
        $data = sanitize_text_field($ip) . '|' . $user_agent . '|' . $daily_salt;
        return 'bb_' . wp_hash($data, 'nonce');
    }
    
    private function save_tracking_to_transient($identifier, $tracking) {
        static $tracking_count = null;
        
        // FIXED: Only count DB entries if we are not using an external object cache.
        // External object caches handle their own evictions, and running COUNT(*) on 
        // wp_options during every 'init' hook will severely bottleneck the site.
        if ($tracking_count === null) {
            if (wp_using_ext_object_cache()) {
                $tracking_count = 0; // Cache layer will handle limits naturally
            } else {
                global $wpdb;
                $like_str = $wpdb->esc_like('_transient_botfend_behavior_tracking_') . '%';
                $tracking_count = (int) $wpdb->get_var($wpdb->prepare(
                    "SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE %s",
                    $like_str
                ));
            }
        }
        
        if (!wp_using_ext_object_cache() && $tracking_count >= $this->settings['max_tracking']) {
            $this->cleanup_oldest_tracking();
        }
        
        set_transient(
            'botfend_behavior_tracking_' . $identifier,
            $tracking,
            $this->settings['tracking_ttl']
        );
    }
    
    private function cleanup_oldest_tracking() {
        // FIXED: Respect object cache and escape wildcard strings
        if (wp_using_ext_object_cache()) {
            return;
        }
        
        global $wpdb;
        
        $like_str = $wpdb->esc_like('_transient_botfend_behavior_tracking_') . '%';
        
        $wpdb->query($wpdb->prepare(
            "DELETE FROM {$wpdb->options} 
             WHERE option_name LIKE %s 
             ORDER BY option_id ASC 
             LIMIT %d",
            $like_str,
            max(1, intval($this->settings['max_tracking'] / 10))
        ));
    }
    
    private function is_valid_ip($ip) {
        if (empty($ip) || !is_string($ip)) {
            return false;
        }
        
        $dangerous_patterns = [
            '--', ';', '/*', '*/', 'UNION', 'SELECT', 'INSERT', 
            'DELETE', 'UPDATE', 'DROP', 'SCRIPT', 'JAVASCRIPT'
        ];
        
        $ip_upper = strtoupper(sanitize_text_field($ip));
        foreach ($dangerous_patterns as $pattern) {
            if (strpos($ip_upper, $pattern) !== false) {
                return false;
            }
        }
        
        return filter_var($ip, FILTER_VALIDATE_IP) !== false;
    }
    
    private function get_safe_request_defaults($ip, $identifier) {
        return [
            'timestamp' => microtime(true),
            'time' => time(),
            'ip' => sanitize_text_field($ip),
            'session_id' => sanitize_text_field($identifier),
            'uri' => '',
            'method' => 'GET',
            'referrer' => '',
            'user_agent' => '',
            'query_string' => '',
            'is_ajax' => false,
            'is_admin' => false,
            'is_404' => false
        ];
    }
    
    private function record_request($ip, $identifier) {
        try {
            $request_uri = isset($_SERVER['REQUEST_URI']) ? 
                esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : '';
            
            $request_method = isset($_SERVER['REQUEST_METHOD']) ? 
                sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])) : 'GET';
            
            $referrer = isset($_SERVER['HTTP_REFERER']) ? 
                esc_url_raw(wp_unslash($_SERVER['HTTP_REFERER'])) : '';
            
            $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? 
                sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
            
            $query_string = isset($_SERVER['QUERY_STRING']) ? 
                sanitize_text_field(wp_unslash($_SERVER['QUERY_STRING'])) : '';
            
            return [
                'timestamp' => microtime(true),
                'time' => time(),
                'ip' => sanitize_text_field($ip),
                'session_id' => sanitize_text_field($identifier),
                'uri' => $request_uri,
                'method' => $request_method,
                'referrer' => $referrer,
                'user_agent' => $user_agent,
                'query_string' => $query_string,
                'is_ajax' => wp_doing_ajax(),
                'is_admin' => is_admin(),
                'is_404' => is_404()
            ];
        } catch (\Exception $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log(sprintf(
                    'BotFend: Error recording request for IP %s. Message: %s',
                    $ip,
                    $e->getMessage()
                ));
            }
            
            return $this->get_safe_request_defaults($ip, $identifier);
        }
    }
    
    public function analyze_behavior() {
        if (!$this->config->get_bool('enable_behavioral_analysis', true)) {
            return;
        }
        
        if ($this->should_exempt_user()) {
            return;
        }
        
        if ($this->should_exempt_path()) {
            return;
        }
        
        $ip = $this->utilities->get_client_ip();
        
        if (!$this->is_valid_ip($ip)) {
            return;
        }
        
        $identifier = $this->get_session_identifier($ip);
        
        if (count($this->behavior_cache) >= self::MAX_TRACKING_CACHE) {
            $this->behavior_cache = array_slice($this->behavior_cache, -800, null, true);
        }
        
        if (!isset($this->behavior_cache[$identifier])) {
            $tracking = get_transient('botfend_behavior_tracking_' . $identifier);
            if ($tracking && is_array($tracking)) {
                $this->behavior_cache[$identifier] = $tracking;
            } else {
                $this->behavior_cache[$identifier] = [
                    'start_time' => time(),
                    'requests' => [],
                    'patterns_detected' => [],
                    'total_score' => 0,
                    'request_count' => 0
                ];
            }
        }
        
        $tracking = &$this->behavior_cache[$identifier];
        
        $max_age = $this->settings['time_window'];
        $tracking['requests'] = array_filter($tracking['requests'], function($req) use ($max_age) {
            return (time() - absint($req['time'])) <= $max_age;
        });
        
        $current_request = $this->record_request($ip, $identifier);
        $tracking['requests'][] = $current_request;
        $tracking['request_count'] = count($tracking['requests']);
        
        if (count($tracking['requests']) > self::MAX_REQUESTS) {
            $tracking['requests'] = array_slice($tracking['requests'], -self::MAX_REQUESTS);
        }
        
        $min_requests = $this->settings['min_requests'];
        if ($tracking['request_count'] >= $min_requests) {
            $analysis = $this->analyze_patterns($tracking['requests'], $ip);
            
            if ($analysis['score'] > 0) {
                $tracking['total_score'] += absint($analysis['score']);
                $tracking['patterns_detected'] = array_merge(
                    $tracking['patterns_detected'],
                    array_map('sanitize_text_field', $analysis['patterns'])
                );
                
                $tracking['patterns_detected'] = array_unique($tracking['patterns_detected']);
                
                $block_threshold = $this->settings['block_threshold'];
                if ($tracking['total_score'] >= $block_threshold) {
                    $this->handle_automated_behavior($ip, $tracking, $analysis, $identifier);
                }
            }
        }
        
        $this->save_tracking_to_transient($identifier, $tracking);
    }
    
    private function analyze_patterns($requests, $ip) {
        $score = 0;
        $patterns = [];
        
        if (count($requests) < $this->settings['min_requests']) {
            return ['score' => 0, 'patterns' => []];
        }
        
        if ($this->detect_sequential_access($requests)) {
            $score += absint($this->patterns['sequential_access']['weight']);
            $patterns[] = 'sequential_access';
        }
        
        if ($this->detect_burst_pattern($requests)) {
            $score += absint($this->patterns['burst_pattern']['weight']);
            $patterns[] = 'burst_pattern';
        }
        
        if ($this->detect_random_paths($requests)) {
            $score += absint($this->patterns['random_paths']['weight']);
            $patterns[] = 'random_paths';
        }
        
        if ($this->detect_no_referrer($requests)) {
            $score += absint($this->patterns['no_referrer']['weight']);
            $patterns[] = 'no_referrer';
        }
        
        if ($this->detect_fixed_timing($requests)) {
            $score += absint($this->patterns['fixed_timing']['weight']);
            $patterns[] = 'fixed_timing';
        }
        
        if ($this->detect_mixed_methods($requests)) {
            $score += absint($this->patterns['mixed_methods']['weight']);
            $patterns[] = 'mixed_methods';
        }
        
        if ($this->detect_parameter_scanning($requests)) {
            $score += absint($this->patterns['parameter_scanning']['weight']);
            $patterns[] = 'parameter_scanning';
        }
        
        if ($this->detect_suspicious_headers($requests)) {
            $score += absint($this->patterns['suspicious_headers']['weight']);
            $patterns[] = 'suspicious_headers';
        }
        
        if ($this->detect_excessive_length($requests)) {
            $score += absint($this->patterns['excessive_length']['weight']);
            $patterns[] = 'excessive_length';
        }
        
        return [
            'score' => min(self::MAX_SCORE, max(0, $score)),
            'patterns' => array_map('sanitize_text_field', $patterns)
        ];
    }
    
    private function detect_suspicious_headers($requests) {
        $suspicious_count = 0;
        
        foreach ($requests as $request) {
            $user_agent = $request['user_agent'] ?? '';
            
            if (empty($user_agent)) {
                $suspicious_count++;
            } elseif (strlen($user_agent) < 10) {
                $suspicious_count++;
            } elseif (preg_match('/^(curl|wget|python|java|go-http|libwww)/i', $user_agent)) {
                $suspicious_count++;
            }
        }
        
        return $suspicious_count > count($requests) * 0.5;
    }
    
    private function detect_excessive_length($requests) {
        foreach ($requests as $request) {
            $uri = $request['uri'] ?? '';
            $query_string = $request['query_string'] ?? '';
            
            if (strlen($uri) > 500) {
                return true;
            }
            
            if (strlen($query_string) > 2000) {
                return true;
            }
        }
        
        return false;
    }
    
    private function detect_sequential_access($requests) {
        $uris = array_column($requests, 'uri');
        $uris = array_map('esc_url_raw', $uris);
        
        $numeric_sequences = 0;
        foreach ($uris as $uri) {
            if (preg_match('/\/(\d+)(?:\/|$)/', $uri, $matches)) {
                $numeric_sequences++;
            }
        }
        
        if ($numeric_sequences >= 3) {
            $numbers = [];
            foreach ($uris as $uri) {
                if (preg_match('/\/(\d+)(?:\/|$)/', $uri, $matches)) {
                    $numbers[] = absint($matches[1]);
                }
            }
            
            sort($numbers);
            $sequential = true;
            for ($i = 1; $i < count($numbers); $i++) {
                if ($numbers[$i] != $numbers[$i-1] + 1) {
                    $sequential = false;
                    break;
                }
            }
            
            if ($sequential) {
                return true;
            }
        }
        
        return false;
    }
    
    private function detect_burst_pattern($requests) {
        if (count($requests) < 5) {
            return false;
        }
        
        $recent_requests = array_filter($requests, function($request) {
            return time() - absint($request['time']) <= 10;
        });
        
        if (count($recent_requests) > 20) {
            return true;
        }
        
        $timestamps = array_column($requests, 'timestamp');
        rsort($timestamps);
        
        $bursts = 0;
        for ($i = 1; $i < count($timestamps); $i++) {
            if ($timestamps[$i-1] - $timestamps[$i] < 0.1) {
                $bursts++;
            }
        }
        
        return $bursts >= 3;
    }
    
    private function detect_random_paths($requests) {
        if (count($requests) < 5) {
            return false;
        }
        
        $uris = array_column($requests, 'uri');
        $uris = array_map('esc_url_raw', $uris);
        
        $segments_by_request = [];
        foreach ($uris as $uri) {
            $path = wp_parse_url($uri, PHP_URL_PATH);
            $segments = $path ? array_filter(explode('/', sanitize_text_field($path))) : [];
            $segments_by_request[] = array_map('sanitize_text_field', $segments);
        }
        
        $similarities = [];
        for ($i = 1; $i < count($segments_by_request); $i++) {
            $prev = $segments_by_request[$i-1];
            $curr = $segments_by_request[$i];
            
            $common = count(array_intersect($prev, $curr));
            $total = count(array_unique(array_merge($prev, $curr)));
            
            $similarity = $total > 0 ? ($common / $total) : 0;
            $similarities[] = $similarity;
        }
        
        $avg_similarity = count($similarities) > 0 ? array_sum($similarities) / count($similarities) : 0;
        
        return $avg_similarity < 0.1;
    }
    
    private function detect_no_referrer($requests) {
        if (count($requests) < 3) {
            return false;
        }
        
        $no_referrer = 0;
        $fake_referrer = 0;
        $total = 0;
        
        foreach ($requests as $request) {
            $total++;
            $referrer = esc_url_raw($request['referrer']);
            
            if (empty($referrer)) {
                $no_referrer++;
            } elseif (strpos($referrer, 'http') !== 0) {
                $fake_referrer++;
            } elseif (filter_var($referrer, FILTER_VALIDATE_URL) === false) {
                $fake_referrer++;
            }
        }
        
        return ($no_referrer + $fake_referrer) / $total > 0.8;
    }
    
    private function detect_fixed_timing($requests) {
        if (count($requests) < 4) {
            return false;
        }
        
        $timestamps = array_column($requests, 'timestamp');
        sort($timestamps);
        
        $diffs = [];
        for ($i = 1; $i < count($timestamps); $i++) {
            $diffs[] = $timestamps[$i] - $timestamps[$i-1];
        }
        
        if (count($diffs) >= 3) {
            $mean = array_sum($diffs) / count($diffs);
            $variance = 0;
            
            foreach ($diffs as $diff) {
                $variance += pow($diff - $mean, 2);
            }
            $variance /= count($diffs);
            
            return $variance < 0.1;
        }
        
        return false;
    }
    
    private function detect_mixed_methods($requests) {
        if (count($requests) < 4) {
            return false;
        }
        
        $methods = array_count_values(array_column($requests, 'method'));
        
        $suspicious_methods = ['HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE', 'CONNECT'];
        $suspicious_count = 0;
        
        foreach ($suspicious_methods as $method) {
            if (isset($methods[$method])) {
                $suspicious_count += absint($methods[$method]);
            }
        }
        
        $total_requests = count($requests);
        
        return $suspicious_count / $total_requests > 0.3;
    }
    
    private function detect_parameter_scanning($requests) {
        $parameter_patterns = 0;
        
        foreach ($requests as $request) {
            $uri = esc_url_raw($request['uri']);
            
            if (strpos($uri, '?') !== false) {
                $parsed_url = wp_parse_url($uri);
                $query = isset($parsed_url['query']) ? sanitize_text_field($parsed_url['query']) : '';
                
                if (strlen($query) > 2048) {
                    $parameter_patterns += 3;
                    continue;
                }
                
                if (substr_count($query, '&') > 30) {
                    $parameter_patterns += 2;
                    continue;
                }
                
                if ($query) {
                    if (preg_match('/(\w+)=\w+&(\w+)=\w+&(\w+)=\w+/', $query)) {
                        $parameter_patterns++;
                    }
                    
                    parse_str($query, $params);
                    foreach ($params as $value) {
                        if (strlen(sanitize_text_field($value)) > 100) {
                            $parameter_patterns++;
                            break;
                        }
                    }
                    
                    $sql_patterns = [
                        '/union.+select/i',
                        '/select.+from/i',
                        '/insert.+into/i',
                        '/update.+set/i',
                        '/delete.+from/i',
                        '/drop.+table/i',
                        '/create.+table/i',
                        '/1=1/i',
                        '/or.+\d+=\d+/i'
                    ];
                    
                    foreach ($sql_patterns as $pattern) {
                        if (preg_match($pattern, sanitize_text_field($query))) {
                            $parameter_patterns += 2;
                            break;
                        }
                    }
                    
                    $xss_patterns = [
                        '/<script/i',
                        '/javascript:/i',
                        '/onload=/i',
                        '/onerror=/i',
                        '/onclick=/i',
                        '/alert\(/i',
                        '/document\./i',
                        '/window\./i'
                    ];
                    
                    foreach ($xss_patterns as $pattern) {
                        if (preg_match($pattern, sanitize_text_field($query))) {
                            $parameter_patterns += 2;
                            break;
                        }
                    }
                    
                    if (preg_match('/(\.\.\/|\.\.%2f|\.\.%5c)/i', sanitize_text_field($query))) {
                        $parameter_patterns += 3;
                    }
                }
            }
        }
        
        return $parameter_patterns >= 3;
    }
    
    private function handle_automated_behavior($ip, $tracking, $analysis, $identifier) {
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? 
            sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
        
        $country = $this->utilities->get_country($ip);
        
        $log_message = sprintf(
            esc_html__('Automated behavior detected. Score: %1$d, Patterns: %2$s, Requests: %3$d', 'botfend-anti-bot-firewall'),
            absint($tracking['total_score']),
            esc_html(implode(', ', $tracking['patterns_detected'])),
            absint($tracking['request_count'])
        );
        
        $this->database->log_request(
            sanitize_text_field($ip),
            absint($tracking['total_score']),
            'automated_behavior',
            [$log_message],
            sanitize_text_field($user_agent),
            false,
            sanitize_text_field($country)
        );
        
        if ($this->settings['penalty_enabled']) {
            $penalty_key = 'botfend_behavior_penalty_' . md5($ip);
            $current_penalty = absint(get_transient($penalty_key) ?: 0);
            $penalty = min($this->settings['max_penalty'], absint($tracking['total_score'] / 2));
            set_transient($penalty_key, $current_penalty + $penalty, $this->settings['penalty_ttl']);
        }
        
        if ($tracking['total_score'] >= $this->settings['block_threshold'] * 1.5) {
            $duration = $this->config->get_int('block_duration', 24);
            
            if ($this->settings['penalty_enabled']) {
                $penalty_key = 'botfend_behavior_penalty_' . md5($ip);
                $penalty = absint(get_transient($penalty_key) ?: 0);
                $duration = min(720, $duration * (1 + ($penalty / 10)));
            }
            
            $block_reason = sprintf(
                esc_html__('High-level automated behavior detected. Patterns: %s', 'botfend-anti-bot-firewall'),
                esc_html(implode(', ', array_slice($tracking['patterns_detected'], 0, 3)))
            );
            
            $block_score = min(10, max(1, absint($tracking['total_score'] / 2)));
            
            $this->database->block_ip(
                sanitize_text_field($ip),
                'automated_behavior',
                $block_reason,
                $block_score,
                $duration,
                sanitize_text_field($country)
            );
            
            unset($this->behavior_cache[$identifier]);
            delete_transient('botfend_behavior_tracking_' . $identifier);
        }
    }
    
    public function finalize_behavior_analysis() {
        $current_time = time();
        $tracking_ttl = $this->settings['tracking_ttl'];
        
        foreach ($this->behavior_cache as $key => $tracking) {
            if ($current_time - absint($tracking['start_time']) > $tracking_ttl) {
                unset($this->behavior_cache[$key]);
                delete_transient('botfend_behavior_tracking_' . $key);
            }
        }
    }
    
    public function get_statistics($hours = 24) {
        global $wpdb;
        
        $table = $wpdb->prefix . 'botfend_logs';
        $time_threshold = gmdate('Y-m-d H:i:s', strtotime("-{$hours} hours"));
        
        $cache_key = 'behavioral_stats_' . $hours;
        $cached = wp_cache_get($cache_key, 'botfend_defender');
        
        if (false !== $cached) {
            return $cached;
        }
        
        $table_exists = $wpdb->get_var($wpdb->prepare(
            "SHOW TABLES LIKE %s",
            $wpdb->esc_like($table)
        ));
        
        if ($table_exists !== $table) {
            return [
                'active_tracking' => 0,
                'avg_requests_tracked' => 0,
                'avg_behavior_score' => 0,
                'detections' => [],
                'common_patterns' => [],
                'recommendations' => [esc_html__('Logs table not yet created.', 'botfend-anti-bot-firewall')],
                'settings' => $this->settings
            ];
        }
        
        $behavior_logs = $wpdb->get_results($wpdb->prepare(
            "SELECT 
                ip,
                COUNT(*) as detection_count,
                AVG(score) as avg_score,
                MAX(score) as max_score,
                GROUP_CONCAT(DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(reason, 'Patterns: ', -1), ',', 1) SEPARATOR ' | ') as patterns
            FROM `{$table}` 
            WHERE action = %s
            AND created_at >= %s
            GROUP BY ip 
            ORDER BY detection_count DESC 
            LIMIT 10",
            'automated_behavior',
            $time_threshold
        ));
        
        $sanitized_logs = [];
        if ($behavior_logs) {
            foreach ($behavior_logs as $log) {
                $sanitized_logs[] = [
                    'ip' => sanitize_text_field($log->ip),
                    'detection_count' => absint($log->detection_count),
                    'avg_score' => round(floatval($log->avg_score), 2),
                    'max_score' => absint($log->max_score),
                    'patterns' => sanitize_textarea_field($log->patterns)
                ];
            }
        }
        
        $pattern_stats = $wpdb->get_results($wpdb->prepare(
            "SELECT 
                SUBSTRING_INDEX(SUBSTRING_INDEX(reason, 'Patterns: ', -1), ',', 1) as pattern,
                COUNT(*) as count
            FROM `{$table}` 
            WHERE action = %s
            AND created_at >= %s
            AND reason LIKE %s
            GROUP BY pattern
            ORDER BY count DESC
            LIMIT 10",
            'automated_behavior',
            $time_threshold,
            $wpdb->esc_like('Patterns:') . '%'
        ));
        
        $sanitized_patterns = [];
        if ($pattern_stats) {
            foreach ($pattern_stats as $pattern) {
                $sanitized_patterns[] = [
                    'pattern' => sanitize_text_field($pattern->pattern),
                    'count' => absint($pattern->count)
                ];
            }
        }
        
        $active_tracking = count($this->behavior_cache);
        $total_requests = 0;
        $total_score = 0;
        
        foreach ($this->behavior_cache as $tracking) {
            $total_requests += absint($tracking['request_count']);
            $total_score += absint($tracking['total_score']);
        }
        
        $avg_requests = $active_tracking > 0 ? $total_requests / $active_tracking : 0;
        $avg_score = $active_tracking > 0 ? $total_score / $active_tracking : 0;
        
        $stats = [
            'active_tracking' => absint($active_tracking),
            'avg_requests_tracked' => round($avg_requests, 1),
            'avg_behavior_score' => round($avg_score, 1),
            'detections' => $sanitized_logs,
            'common_patterns' => $sanitized_patterns,
            'recommendations' => $this->generate_recommendations($sanitized_patterns),
            'settings' => $this->settings
        ];
        
        wp_cache_set($cache_key, $stats, 'botfend_defender', self::CACHE_TTL);
        
        return $stats;
    }
    
    private function generate_recommendations($pattern_stats) {
        $recommendations = [];
        
        if (empty($pattern_stats)) {
            $recommendations[] = esc_html__('No automated behavior detected recently. Good job!', 'botfend-anti-bot-firewall');
            return $recommendations;
        }
        
        $pattern_counts = [];
        foreach ($pattern_stats as $stat) {
            $pattern_counts[$stat['pattern']] = $stat['count'];
        }
        
        if (isset($pattern_counts['sequential_access']) && $pattern_counts['sequential_access'] > 5) {
            $current_threshold = $this->settings['block_threshold'];
            if ($current_threshold > 8) {
                $recommendations[] = esc_html__('Sequential access patterns detected. Consider lowering auto-block score.', 'botfend-anti-bot-firewall');
            }
        }
        
        if (isset($pattern_counts['burst_pattern']) && $pattern_counts['burst_pattern'] > 3) {
            $recommendations[] = esc_html__('Burst patterns detected. Review rate limit settings.', 'botfend-anti-bot-firewall');
        }
        
        if (isset($pattern_counts['parameter_scanning']) && $pattern_counts['parameter_scanning'] > 2) {
            $recommendations[] = esc_html__('Parameter scanning detected. Ensure WAF is enabled.', 'botfend-anti-bot-firewall');
        }
        
        if (isset($pattern_counts['no_referrer']) && $pattern_counts['no_referrer'] > 10) {
            $recommendations[] = esc_html__('Many requests without referrers. Consider enabling crawler verification.', 'botfend-anti-bot-firewall');
        }
        
        if ($this->settings['sensitivity'] === 'low' && count($pattern_stats) > 5) {
            $recommendations[] = esc_html__('Sensitivity is set to low but many patterns detected. Consider increasing sensitivity.', 'botfend-anti-bot-firewall');
        }
        
        return $recommendations;
    }
    
    public function get_current_analysis($ip = null) {
        if (!$ip) {
            $ip = $this->utilities->get_client_ip();
        }
        
        $identifier = $this->get_session_identifier($ip);
        
        if (!isset($this->behavior_cache[$identifier])) {
            return [
                'score' => 0,
                'patterns' => [],
                'request_count' => 0,
                'tracking_time' => 0,
                'is_suspicious' => false,
                'penalty' => 0
            ];
        }
        
        $tracking = $this->behavior_cache[$identifier];
        
        $penalty = 0;
        if ($this->settings['penalty_enabled']) {
            $penalty_key = 'botfend_behavior_penalty_' . md5($ip);
            $penalty = absint(get_transient($penalty_key) ?: 0);
        }
        
        return [
            'score' => absint($tracking['total_score']),
            'patterns' => array_map('sanitize_text_field', $tracking['patterns_detected']),
            'request_count' => absint($tracking['request_count']),
            'tracking_time' => time() - absint($tracking['start_time']),
            'is_suspicious' => absint($tracking['total_score']) >= $this->settings['block_threshold'],
            'penalty' => $penalty
        ];
    }
    
    public function get_settings() {
        return $this->settings;
    }
    
    public function clear_analysis_data() {
        $this->behavior_cache = [];
        
        global $wpdb;
        // FIXED: Added Object Cache safeguard and escaped SQL wildcards
        if (!wp_using_ext_object_cache()) {
            $like_str = $wpdb->esc_like('_transient_botfend_behavior_') . '%';
            $keys = $wpdb->get_col($wpdb->prepare(
                "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s",
                $like_str
            ));
            
            if (!empty($keys)) {
                foreach ($keys as $key) {
                    $transient_name = str_replace('_transient_', '', $key);
                    delete_transient($transient_name);
                }
            }
        }
        
        return true;
    }
    
    public static function clear_caches() {
        self::$compiled_patterns = null;
    }
    
    public function get_penalty($ip) {
        if (!$this->settings['penalty_enabled']) {
            return 0;
        }
        
        $penalty_key = 'botfend_behavior_penalty_' . md5($ip);
        return absint(get_transient($penalty_key) ?: 0);
    }
    
    public function reset_penalty($ip) {
        $penalty_key = 'botfend_behavior_penalty_' . md5($ip);
        return delete_transient($penalty_key);
    }
}