<?php
/**
 * Bot signature detection engine for BotFend Anti-Bot Firewall
 *
 * @package BotFend\Detection
 * @since 4.4.1 - Fixed WPDB prepare syntax for LIKE clauses
 * @version 4.8.3 - Rebranded from SafeBot
 */

namespace BotFend\Detection;

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

defined('ABSPATH') || exit;

/**
 * Class Signatures
 *
 * Handles bot signature detection with confidence-based scoring
 */
class Signatures {

    private $config;
    private $database;
    private $signatures = [];
    private $behavioral_patterns = [];
    private $enabled = false;
    
    private static $compiled_signatures = null;
    private static $compiled_behavioral = null;
    
    private $normalized_headers = [];
    private $canonicalized_uri = null;
    
    const SIGNATURE_TYPES = [
        'ua_pattern' => 1,
        'header_pattern' => 2,
        'request_pattern' => 3,
        'behavioral' => 4,
        'temporal' => 5
    ];
    
    const CONFIDENCE_LEVELS = [
        'low' => 1,      // 1-3 points - needs other signals
        'medium' => 2,   // 4-7 points - contributes to block
        'high' => 3      // 8-10 points - can block independently
    ];
    
    const MAX_SCORE = 10;
    const CACHE_TTL = 300;
    
    const BLOCK_SCORE_HIGH = 8;     
    const BLOCK_SCORE_MEDIUM = 10;   
    const BLOCK_SCORE_LOW = 10;      
    
    public function __construct($database = null) {
        $this->config = Config::get_instance();
        $this->enabled = $this->config->get_bool('enable_signatures', true);
        $this->database = $database;
        
        if ($this->enabled) {
            $this->load_default_signatures();
            $this->load_behavioral_patterns();
        }
    }
    
    /**
     * Load default bot signatures (With Persistent DB Support)
     */
    private function load_default_signatures() {
        if (self::$compiled_signatures !== null) {
            $this->signatures = self::$compiled_signatures;
            return;
        }
        
        // Load from Database to preserve toggled states and custom signatures
        $saved_signatures = get_option('botfend_engine_signatures', false);
        if (is_array($saved_signatures) && !empty($saved_signatures)) {
            $this->signatures = $saved_signatures;
            self::$compiled_signatures = $this->signatures;
            return;
        }
        
        $this->signatures = [
            [
                'type' => self::SIGNATURE_TYPES['ua_pattern'],
                'pattern' => '/bot|crawler|spider|scraper|curl|wget/i',
                'score' => 3,
                'name' => esc_html__('Generic Bot UA', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'description' => esc_html__('Common bot user agent keywords', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['ua_pattern'],
                'pattern' => '/python-requests|java\/|go-http-client|php\/|ruby|perl/i',
                'score' => 4,
                'name' => esc_html__('Script/Program UA', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['medium'],
                'description' => esc_html__('Programming language HTTP clients', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['ua_pattern'],
                'pattern' => '/masscan|zgrab|nmap|sqlmap|nikto|acunetix|nessus/i',
                'score' => 10,
                'name' => esc_html__('Security Scanner', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['high'],
                'description' => esc_html__('Known security scanning tools', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['ua_pattern'],
                'pattern' => '/headless|phantom|puppeteer|selenium|playwright/i',
                'score' => 8,
                'name' => esc_html__('Headless Browser', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['high'],
                'description' => esc_html__('Automated browser frameworks', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['ua_pattern'],
                'pattern' => '/scrapy|beautifulsoup|lxml|guzzle|httrack/i',
                'score' => 5,
                'name' => esc_html__('Web Scraper', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['medium'],
                'description' => esc_html__('Web scraping frameworks', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['ua_pattern'],
                'pattern' => '/semrush|ahrefs|moz|majestic|seo/i',
                'score' => 2,
                'name' => esc_html__('SEO Tool', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'description' => esc_html__('SEO analysis tools', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['header_pattern'],
                'header' => 'x-forwarded-for',
                'pattern' => '/\d+\.\d+\.\d+\.\d+,\s*\d+\.\d+\.\d+\.\d+/',
                'score' => 2,
                'name' => esc_html__('Multiple Proxy Headers', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'description' => esc_html__('Multiple IPs in X-Forwarded-For header', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['header_pattern'],
                'header' => 'accept',
                'pattern' => '/^\*\/\*$/',
                'score' => 3,
                'name' => esc_html__('Generic Accept Header', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'description' => esc_html__('Wildcard Accept header (*/*)', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['header_pattern'],
                'header' => 'accept-language',
                'pattern' => '/^$/',
                'score' => 1,
                'name' => esc_html__('Missing Accept-Language', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'description' => esc_html__('No Accept-Language header', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['header_pattern'],
                'header' => 'from',
                'check' => 'exists',
                'score' => 2,
                'name' => esc_html__('From Header Present', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'description' => esc_html__('From header (common in bots)', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['header_pattern'],
                'header' => 'referer',
                'pattern' => '/(test|local|127\.0\.0\.1|192\.168\.)/i',
                'score' => 4,
                'name' => esc_html__('Suspicious Referer', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['medium'],
                'description' => esc_html__('Local/internal referer URLs', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['request_pattern'],
                'pattern' => '/\.(bak|old|backup|sql|zip|tar|gz)$/i',
                'score' => 5,
                'name' => esc_html__('Backup File Scanning', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['high'],
                'description' => esc_html__('Attempt to access backup files', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['request_pattern'],
                'pattern' => '/\/(wp-admin|wp-login|administrator|phpmyadmin|mysql-admin)/i',
                'score' => 3,
                'name' => esc_html__('Admin Interface Scanning', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'description' => esc_html__('Admin panel access attempts', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['request_pattern'],
                'pattern' => '/\.(env|config\.php|htaccess|wp-config\.php)$/i',
                'score' => 6,
                'name' => esc_html__('Configuration File Scanning', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['high'],
                'description' => esc_html__('Configuration file access attempts', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['request_pattern'],
                'pattern' => '/\.(git|svn|hg)\//i',
                'score' => 5,
                'name' => esc_html__('Version Control Scanning', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['high'],
                'description' => esc_html__('Version control directory access', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['request_pattern'],
                'pattern' => '/(union\s+select|select\s+.*\s+from|insert\s+into|update\s+.*\s+set|delete\s+from)/i',
                'score' => 8,
                'name' => esc_html__('SQL Injection Pattern', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['high'],
                'description' => esc_html__('SQL injection attempt patterns', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['request_pattern'],
                'pattern' => '/(<script|javascript:|alert\s*\(|on\w+\s*=)/i',
                'score' => 7,
                'name' => esc_html__('XSS Pattern', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['high'],
                'description' => esc_html__('Cross-site scripting patterns', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['request_pattern'],
                'pattern' => '/(\.\.\/|\.\.\\\\)/',
                'score' => 6,
                'name' => esc_html__('Directory Traversal', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['high'],
                'description' => esc_html__('Directory traversal attempts', 'botfend-anti-bot-firewall')
            ],
            [
                'type' => self::SIGNATURE_TYPES['request_pattern'],
                'pattern' => '/\?.*=.*(&.*=.*){5,}/',
                'score' => 2,
                'name' => esc_html__('Parameter Fuzzing', 'botfend-anti-bot-firewall'),
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'description' => esc_html__('Multiple parameter testing', 'botfend-anti-bot-firewall')
            ]
        ];
        
        self::$compiled_signatures = $this->signatures;
    }
    
    private function load_behavioral_patterns() {
        if (self::$compiled_behavioral !== null) {
            $this->behavioral_patterns = self::$compiled_behavioral;
            return;
        }

        // Load from DB to preserve user toggles
        $saved_patterns = get_option('botfend_engine_behavioral', false);
        if (is_array($saved_patterns) && !empty($saved_patterns)) {
            $this->behavioral_patterns = $saved_patterns;
            self::$compiled_behavioral = $this->behavioral_patterns;
            return;
        }
        
        $this->behavioral_patterns = [
            'burst_pattern' => [
                'description' => esc_html__('Rapid successive requests', 'botfend-anti-bot-firewall'),
                'threshold' => 10,
                'window' => 2,
                'score' => 6,
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['medium'],
                'category' => 'rate'
            ],
            'fixed_interval' => [
                'description' => esc_html__('Requests at exact intervals', 'botfend-anti-bot-firewall'),
                'threshold' => 0.1,
                'sample_size' => 5,
                'score' => 7,
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['medium'],
                'category' => 'timing'
            ],
            'no_referer' => [
                'description' => esc_html__('No referer header on internal links', 'botfend-anti-bot-firewall'),
                'threshold' => 0.8,
                'score' => 2,
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'category' => 'headers'
            ],
            'sequential_scanning' => [
                'description' => esc_html__('Sequential ID scanning', 'botfend-anti-bot-firewall'),
                'pattern' => '/(page|id|p)=\d+(&(page|id|p)=\d+){2,}/',
                'score' => 6,
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['medium'],
                'category' => 'request'
            ],
            'odd_hours' => [
                'description' => esc_html__('Activity during odd hours (2AM-5AM local time)', 'botfend-anti-bot-firewall'),
                'score' => 1,
                'enabled' => false,
                'confidence' => self::CONFIDENCE_LEVELS['low'],
                'category' => 'temporal',
                'require_correlation' => true
            ],
            'multiple_404s' => [
                'description' => esc_html__('Multiple 404 errors in short time', 'botfend-anti-bot-firewall'),
                'threshold' => 10,
                'window' => 60,
                'score' => 5,
                'enabled' => true,
                'confidence' => self::CONFIDENCE_LEVELS['medium'],
                'category' => 'error'
            ]
        ];
        
        self::$compiled_behavioral = $this->behavioral_patterns;
    }
    
    private function normalize_headers($headers) {
        if (empty($this->normalized_headers)) {
            $this->normalized_headers = [];
            foreach ($headers as $key => $value) {
                $this->normalized_headers[strtolower($key)] = $value;
            }
        }
        return $this->normalized_headers;
    }
    
    private function canonicalize_uri($uri) {
        if ($this->canonicalized_uri !== null) {
            return $this->canonicalized_uri;
        }
        
        $uri = urldecode($uri);
        $uri = preg_replace('#/{2,}#', '/', $uri);
        $uri = str_replace('\\', '/', $uri);
        
        if ($uri !== '/' && substr($uri, -1) === '/') {
            $uri = substr($uri, 0, -1);
        }
        
        $this->canonicalized_uri = $uri;
        return $uri;
    }
    
    private function get_confidence_from_score($score) {
        if ($score >= 8) return self::CONFIDENCE_LEVELS['high'];
        if ($score >= 4) return self::CONFIDENCE_LEVELS['medium'];
        return self::CONFIDENCE_LEVELS['low'];
    }
    
    public function analyze_request($ip, $user_agent, $headers, $request_uri) {
        if (!$this->enabled) {
            return [
                'score' => 0,
                'detections' => [],
                'signature_count' => 0,
                'details' => [],
                'enabled' => false,
                'confidence' => 'low',
                'block_recommendation' => false
            ];
        }
        
        if (!is_array($headers)) $headers = [];
        
        $normalized_headers = $this->normalize_headers($headers);
        $canonical_uri = $this->canonicalize_uri($request_uri);
        
        $detections = [];
        $details = [];
        $total_score = 0;
        $temporal_signals = [];
        
        // Massive performance upgrade. O(1) loop instead of O(3N)
        foreach ($this->signatures as $sig) {
            if (empty($sig['enabled'])) {
                continue;
            }

            $matched = false;

            switch ($sig['type']) {
                case self::SIGNATURE_TYPES['ua_pattern']:
                    if (preg_match($sig['pattern'], $user_agent)) {
                        $matched = true;
                    }
                    break;

                case self::SIGNATURE_TYPES['header_pattern']:
                    $header_name = strtolower($sig['header']);
                    $header_value = $normalized_headers[$header_name] ?? '';
                    
                    if (isset($sig['check']) && $sig['check'] === 'exists') {
                        if ($header_value !== '') $matched = true;
                    } elseif ($header_value !== '' && preg_match($sig['pattern'], $header_value)) {
                        $matched = true;
                    }
                    break;

                case self::SIGNATURE_TYPES['request_pattern']:
                    if (preg_match($sig['pattern'], $canonical_uri)) {
                        $matched = true;
                    }
                    break;
            }

            if ($matched) {
                $detections[] = $sig['name'];
                $details[] = [
                    'type'        => array_search($sig['type'], self::SIGNATURE_TYPES),
                    'name'        => $sig['name'],
                    'score'       => $sig['score'],
                    'confidence'  => $sig['confidence'] ?? $this->get_confidence_from_score($sig['score']),
                    'description' => $sig['description'] ?? $sig['name']
                ];
                $total_score += $sig['score'];

                if ($total_score >= self::MAX_SCORE) {
                    break;
                }
            }
        }
        
        if ($total_score < self::MAX_SCORE) {
            $behavioral_results = $this->analyze_behavior($ip, $canonical_uri, $normalized_headers);
            if ($behavioral_results['score'] > 0) {
                $detections = array_merge($detections, $behavioral_results['detections']);
                $details = array_merge($details, $behavioral_results['details']);
                $total_score += $behavioral_results['score'];
                
                if (!empty($behavioral_results['temporal_signals'])) {
                    $temporal_signals = $behavioral_results['temporal_signals'];
                }
            }
        }
        
        if ($total_score < self::MAX_SCORE) {
            $temporal_results = $this->analyze_temporal_patterns($ip, $temporal_signals);
            if ($temporal_results['score'] > 0) {
                $detections = array_merge($detections, $temporal_results['detections']);
                $details = array_merge($details, $temporal_results['details']);
                $total_score += $temporal_results['score'];
            }
        }
        
        $total_score = min(self::MAX_SCORE, $total_score);
        
        $has_high_confidence_signal = false;
        $has_medium_confidence_signal = false;
        $medium_count = 0;
        
        foreach ($details as $detail) {
            $confidence = $detail['confidence'] ?? self::CONFIDENCE_LEVELS['low'];
            if ($confidence === self::CONFIDENCE_LEVELS['high']) {
                $has_high_confidence_signal = true;
            } elseif ($confidence === self::CONFIDENCE_LEVELS['medium']) {
                $has_medium_confidence_signal = true;
                $medium_count++;
            }
        }
        
        if ($has_high_confidence_signal && $total_score >= self::BLOCK_SCORE_HIGH) {
            $confidence_level = 'high';
            $block_recommendation = true;
        } elseif ($has_medium_confidence_signal && $total_score >= self::BLOCK_SCORE_MEDIUM) {
            $confidence_level = 'medium';
            $block_recommendation = true;
        } elseif ($total_score >= self::BLOCK_SCORE_LOW && $medium_count >= 2) {
            $confidence_level = 'low';
            $block_recommendation = true;
        } else {
            $confidence_level = $has_high_confidence_signal ? 'high' : ($has_medium_confidence_signal ? 'medium' : 'low');
            $block_recommendation = false;
        }
        
        if ($total_score >= 3 && $this->database) {
            $this->log_detection($ip, $total_score, $detections, $user_agent, $block_recommendation);
        }
        
        return [
            'score' => $total_score,
            'detections' => array_unique($detections),
            'signature_count' => count(array_unique($detections)),
            'details' => $details,
            'enabled' => true,
            'confidence' => $confidence_level,
            'block_recommendation' => $block_recommendation
        ];
    }
    
    private function log_detection($ip, $score, $signatures, $user_agent, $block_recommendation = false) {
        $cache_key = 'botfend_signature_detection_' . md5($ip . gmdate('Y-m-d-H')) . '_' . get_current_blog_id();
        $detections_today = get_transient($cache_key) ?: 0;
        $detections_today++;
        
        if ($detections_today === 1) {
            $factors = [
                sprintf(esc_html__('Signature detection: %s', 'botfend-anti-bot-firewall'), implode(', ', array_slice($signatures, 0, 3)))
            ];
            
            if ($this->database && method_exists($this->database, 'log_request')) {
                $action = $block_recommendation ? 'signature_high_confidence' : 'signature_detected';
                
                $this->database->log_request(
                    $ip,
                    $score,
                    $action,
                    $factors,
                    $user_agent,
                    false,
                    null
                );
            }
            
            set_transient($cache_key, $detections_today, 3600);
        }
    }
    
    private function analyze_behavior($ip, $request_uri, $headers) {
        $cache_key = 'botfend_behavior_' . md5($ip) . '_' . get_current_blog_id();
        $behavior_data = get_transient($cache_key) ?: [];
        
        $current_time = microtime(true);
        $behavior_data[] = [
            'time' => $current_time,
            'uri' => $request_uri,
            'referer' => isset($headers['referer']) ? $headers['referer'] : ''
        ];
        
        if (count($behavior_data) > 50) {
            array_shift($behavior_data);
        }
        
        set_transient($cache_key, $behavior_data, self::CACHE_TTL);
        
        $score = 0;
        $detections = [];
        $details = [];
        $temporal_signals = [];
        
        if (count($behavior_data) >= 5 && $this->behavioral_patterns['burst_pattern']['enabled']) {
            $last_five = array_slice($behavior_data, -5);
            $time_diff = $last_five[4]['time'] - $last_five[0]['time'];
            
            if ($time_diff < $this->behavioral_patterns['burst_pattern']['window']) {
                $score += $this->behavioral_patterns['burst_pattern']['score'];
                $detections[] = esc_html__('Burst request pattern', 'botfend-anti-bot-firewall');
                $details[] = [
                    'type' => 'behavior',
                    'name' => esc_html__('Burst Pattern', 'botfend-anti-bot-firewall'),
                    'score' => $this->behavioral_patterns['burst_pattern']['score'],
                    'confidence' => $this->behavioral_patterns['burst_pattern']['confidence'] ?? self::CONFIDENCE_LEVELS['medium'],
                    'description' => $this->behavioral_patterns['burst_pattern']['description']
                ];
                $temporal_signals[] = 'burst';
            }
        }
        
        if ($this->behavioral_patterns['sequential_scanning']['enabled']) {
            if (preg_match($this->behavioral_patterns['sequential_scanning']['pattern'], $request_uri)) {
                $score += $this->behavioral_patterns['sequential_scanning']['score'];
                $detections[] = esc_html__('Sequential scanning', 'botfend-anti-bot-firewall');
                $details[] = [
                    'type' => 'behavior',
                    'name' => esc_html__('Sequential Scanning', 'botfend-anti-bot-firewall'),
                    'score' => $this->behavioral_patterns['sequential_scanning']['score'],
                    'confidence' => $this->behavioral_patterns['sequential_scanning']['confidence'] ?? self::CONFIDENCE_LEVELS['medium'],
                    'description' => $this->behavioral_patterns['sequential_scanning']['description']
                ];
            }
        }
        
        if ($this->behavioral_patterns['odd_hours']['enabled']) {
            $hour = (int) gmdate('H');
            if ($hour >= 2 && $hour <= 5) {
                $temporal_signals[] = 'odd_hours';
                
                if (!empty($temporal_signals) && count($temporal_signals) > 1) {
                    $score += $this->behavioral_patterns['odd_hours']['score'];
                    $detections[] = esc_html__('Odd hour activity', 'botfend-anti-bot-firewall');
                    $details[] = [
                        'type' => 'temporal',
                        'name' => esc_html__('Odd Hours', 'botfend-anti-bot-firewall'),
                        'score' => $this->behavioral_patterns['odd_hours']['score'],
                        'confidence' => self::CONFIDENCE_LEVELS['low'],
                        'description' => $this->behavioral_patterns['odd_hours']['description']
                    ];
                }
            }
        }
        
        if ($this->behavioral_patterns['no_referer']['enabled'] && count($behavior_data) >= 10) {
            $no_referer_count = 0;
            foreach ($behavior_data as $request) {
                if (empty($request['referer']) && strpos($request['uri'], 'http') === false) {
                    $no_referer_count++;
                }
            }
            
            $no_referer_ratio = $no_referer_count / count($behavior_data);
            if ($no_referer_ratio > $this->behavioral_patterns['no_referer']['threshold']) {
                $score += $this->behavioral_patterns['no_referer']['score'];
                $detections[] = esc_html__('No referer pattern', 'botfend-anti-bot-firewall');
                $details[] = [
                    'type' => 'behavior',
                    'name' => esc_html__('No Referer', 'botfend-anti-bot-firewall'),
                    'score' => $this->behavioral_patterns['no_referer']['score'],
                    'confidence' => $this->behavioral_patterns['no_referer']['confidence'] ?? self::CONFIDENCE_LEVELS['low'],
                    'description' => $this->behavioral_patterns['no_referer']['description']
                ];
            }
        }
        
        if ($this->behavioral_patterns['multiple_404s']['enabled'] && $this->database) {
            if (method_exists($this->database, 'is_404_abuser')) {
                if ($this->database->is_404_abuser($ip)) {
                    $score += $this->behavioral_patterns['multiple_404s']['score'];
                    $detections[] = esc_html__('Multiple 404 errors', 'botfend-anti-bot-firewall');
                    $details[] = [
                        'type' => 'behavior',
                        'name' => esc_html__('Multiple 404s', 'botfend-anti-bot-firewall'),
                        'score' => $this->behavioral_patterns['multiple_404s']['score'],
                        'confidence' => $this->behavioral_patterns['multiple_404s']['confidence'] ?? self::CONFIDENCE_LEVELS['medium'],
                        'description' => $this->behavioral_patterns['multiple_404s']['description']
                    ];
                }
            }
        }
        
        return [
            'score' => $score,
            'detections' => $detections,
            'details' => $details,
            'temporal_signals' => $temporal_signals
        ];
    }
    
    private function analyze_temporal_patterns($ip, $existing_temporal_signals = []) {
        $cache_key = 'botfend_temporal_' . md5($ip) . '_' . get_current_blog_id();
        $request_times = get_transient($cache_key) ?: [];
        
        $current_time = time();
        $request_times[] = $current_time;
        
        $request_times = array_filter($request_times, function($time) use ($current_time) {
            return $current_time - $time < 3600;
        });
        
        set_transient($cache_key, $request_times, 3600);
        
        $score = 0;
        $detections = [];
        $details = [];
        
        if (!$this->behavioral_patterns['fixed_interval']['enabled'] || 
            count($request_times) < $this->behavioral_patterns['fixed_interval']['sample_size']) {
            return [
                'score' => $score,
                'detections' => $detections,
                'details' => $details
            ];
        }
        
        $intervals = [];
        for ($i = 1; $i < count($request_times); $i++) {
            $intervals[] = $request_times[$i] - $request_times[$i - 1];
        }
        
        $unique_intervals = array_unique($intervals);
        if (count($unique_intervals) < 3 && count($intervals) > 5 && !empty($existing_temporal_signals)) {
            $score += $this->behavioral_patterns['fixed_interval']['score'];
            $detections[] = esc_html__('Fixed interval pattern', 'botfend-anti-bot-firewall');
            $details[] = [
                'type' => 'temporal',
                'name' => esc_html__('Fixed Interval', 'botfend-anti-bot-firewall'),
                'score' => $this->behavioral_patterns['fixed_interval']['score'],
                'confidence' => $this->behavioral_patterns['fixed_interval']['confidence'] ?? self::CONFIDENCE_LEVELS['medium'],
                'description' => $this->behavioral_patterns['fixed_interval']['description']
            ];
        }
        
        return [
            'score' => $score,
            'detections' => $detections,
            'details' => $details
        ];
    }
    
    public function get_signatures() {
        return [
            'signatures' => $this->signatures,
            'behavioral_patterns' => $this->behavioral_patterns,
            'enabled' => $this->enabled,
            'statistics' => $this->get_statistics()
        ];
    }
    
    public function toggle_signature($index, $enable) {
        $index = absint($index);
        if (isset($this->signatures[$index])) {
            $this->signatures[$index]['enabled'] = (bool) $enable;
            self::$compiled_signatures = null;
            // Save state to database so it doesn't revert on refresh
            update_option('botfend_engine_signatures', $this->signatures, false);
            return true;
        }
        return false;
    }
    
    public function toggle_behavioral_pattern($pattern_name, $enable) {
        $pattern_name = sanitize_text_field($pattern_name);
        if (isset($this->behavioral_patterns[$pattern_name])) {
            $this->behavioral_patterns[$pattern_name]['enabled'] = (bool) $enable;
            self::$compiled_behavioral = null;
            // Save state to database
            update_option('botfend_engine_behavioral', $this->behavioral_patterns, false);
            return true;
        }
        return false;
    }
    
    public function add_custom_signature($type, $pattern, $score, $name, $description = '', $confidence = null) {
        if (!is_string($pattern) || !is_string($name)) {
            return false;
        }
        
        $test_result = @preg_match($pattern, '');
        if ($test_result === false || preg_last_error() !== PREG_NO_ERROR) {
            return false;
        }
        
        $dangerous_patterns = [
            '/[\'"]?\s*[;{}]|\$\{|\(\?\{/',
            '/(?{)/',
            '/(??{)/',
            '/[\\\\]e\b/',
            '/\*{10,}/',
        ];
        
        foreach ($dangerous_patterns as $danger) {
            if (preg_match($danger, $pattern)) {
                return false;
            }
        }
        
        if (strlen($pattern) > 1000) {
            return false;
        }
        
        if (!in_array($type, array_keys(self::SIGNATURE_TYPES))) {
            return false;
        }
        
        if ($confidence === null) {
            $confidence = $this->get_confidence_from_score($score);
        }
        
        $new_signature = [
            'type' => self::SIGNATURE_TYPES[$type],
            'pattern' => $pattern,
            'score' => min(10, max(1, (int) $score)),
            'name' => sanitize_text_field($name),
            'description' => sanitize_text_field($description),
            'enabled' => true,
            'confidence' => min(3, max(1, (int) $confidence)),
            'custom' => true
        ];
        
        $this->signatures[] = $new_signature;
        self::$compiled_signatures = null;
        
        // Ensure custom signatures are saved to DB
        update_option('botfend_engine_signatures', $this->signatures, false);
        
        return true;
    }
    
    public function remove_custom_signature($index) {
        $index = absint($index);
        if (isset($this->signatures[$index]) && isset($this->signatures[$index]['custom'])) {
            unset($this->signatures[$index]);
            $this->signatures = array_values($this->signatures);
            self::$compiled_signatures = null;
            // Update DB after removal
            update_option('botfend_engine_signatures', $this->signatures, false);
            return true;
        }
        return false;
    }
    
    public function get_statistics() {
        global $wpdb;
        
        $logs_table = $wpdb->prefix . 'botfend_logs';
        $signature_detections = 0;
        
        $table_exists = $wpdb->get_var($wpdb->prepare(
            "SHOW TABLES LIKE %s",
            $wpdb->esc_like($logs_table)
        ));
        
        if ($table_exists) {
            // FIXED: Used $wpdb->esc_like() to safely prepare the LIKE clause wildcard
            $like_pattern = '%' . $wpdb->esc_like('signature') . '%';
            
            // Using UTC_TIMESTAMP() instead of NOW() to respect strict WP Timezone handling
            $signature_detections = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT COUNT(*) FROM {$logs_table} 
                     WHERE (factors LIKE %s OR action = %s OR action = %s)
                     AND created_at > DATE_SUB(UTC_TIMESTAMP(), INTERVAL 24 HOUR)",
                    $like_pattern,
                    'signature_detected',
                    'signature_high_confidence'
                )
            ) ?: 0;
        }
        
        $enabled_signatures = 0;
        foreach ($this->signatures as $sig) {
            if ($sig['enabled']) $enabled_signatures++;
        }
        
        $enabled_patterns = 0;
        foreach ($this->behavioral_patterns as $pattern) {
            if ($pattern['enabled']) $enabled_patterns++;
        }
        
        return [
            'total_signatures' => count($this->signatures),
            'enabled_signatures' => $enabled_signatures,
            'behavioral_patterns' => count($this->behavioral_patterns),
            'enabled_patterns' => $enabled_patterns,
            'detections_24h' => (int) $signature_detections
        ];
    }
    
    public function reset_to_defaults() {
        self::$compiled_signatures = null;
        self::$compiled_behavioral = null;
        
        // Clear WP DB states to actually restore defaults
        delete_option('botfend_engine_signatures');
        delete_option('botfend_engine_behavioral');
        
        $this->load_default_signatures();
        $this->load_behavioral_patterns();
        return true;
    }
    
    public static function clear_caches() {
        self::$compiled_signatures = null;
        self::$compiled_behavioral = null;
    }
}