<?php
/**
 * VMPFence Malware Scanner
 * 
 * Local-only malware detection for WordPress files
 * Detects common malware patterns, backdoors, and suspicious code
 * 
 * @package VMPFence
 * @since 1.0.0
 * @since 2.2.4 -- Lazy loading of API signatures, SQL Query fix
 */

if (!defined('ABSPATH')) {
    exit;
}

// Include required dependencies for enhanced malware detection
require_once plugin_dir_path(__FILE__) . 'class-common-strings-optimizer.php';
require_once plugin_dir_path(__FILE__) . 'class-pattern-harvester.php';
require_once plugin_dir_path(__FILE__) . 'class-binary-detector.php';
require_once plugin_dir_path(__FILE__) . 'class-badstrings-detector.php';

// Step 4: Advanced Memory Management & Process Forking
require_once plugin_dir_path(__FILE__) . 'class-advanced-scan-engine.php';
require_once plugin_dir_path(__FILE__) . 'class-advanced-file-handler.php';

// Step 5: High Sensitivity Mode & Image/Binary File Scanning
require_once plugin_dir_path(__FILE__) . 'class-sensitivity-scanner.php';

// Step 6: Exclusion Pattern System for False Positive Filtering
require_once plugin_dir_path(__FILE__) . 'class-exclusion-system.php';

// Include centralized exclusion manager
require_once plugin_dir_path(__FILE__) . 'class-scan-exclusion-manager.php';

// Step 7: WordPress.org File Integrity Verification
require_once plugin_dir_path(__FILE__) . 'class-wp-integrity-checker.php';

// Step 8: Metrics Tracking & Progress Updates
require_once plugin_dir_path(__FILE__) . 'class-scan-metrics.php';
require_once plugin_dir_path(__FILE__) . 'class-progress-tracker.php';

// Step 9: Regex Performance Optimization
require_once plugin_dir_path(__FILE__) . 'class-pattern-optimizer.php';

// Step 10: Google Safe Browsing URL Detection
require_once plugin_dir_path(__FILE__) . 'class-url-safety-checker.php';

// Step 11: Enhanced Issue Classification & Metadata
require_once plugin_dir_path(__FILE__) . 'class-issue-manager.php';

// Step 12: Advanced File Type Detection
require_once plugin_dir_path(__FILE__) . 'class-file-type-handler.php';

class VMPFence_Malware_Scanner {
    
    private $debug_log = array();
    private $scan_options = null;
    private $scan_type = 'malware';
    private $total_files_scanned = 0;
    private $chunk_size = 1048576; // 1MB chunks for large files
    
    /**
     * Enhanced malware signature patterns with rule structure
     * Advanced rule structure: [rule_id, category, regex_pattern, description, scan_type, log_only, severity, issue_type, common_string_indexes, custom_message]
     */
    private $malware_patterns = array();
    
    /**
     * Binary malware detector for ultra-fast 4-byte prefix detection
     */
    private $binary_detector;
    
    /**
     * Common strings optimizer for performance pre-filtering
     */
    private $common_strings_optimizer;
    
    /**
     * Pattern harvester for dynamic pattern expansion
     */
    private $pattern_harvester;
    
    /**
     * Badstrings detector for suspicious string combinations
     */
    private $badstrings_detector;
    
    /**
     * Advanced scan engine for memory management and process forking
     */
    private $advanced_scan_engine;
    
    /**
     * Advanced file handler for large files and memory optimization
     */
    private $advanced_file_handler;
    
    /**
     * High sensitivity scanner for obfuscation and advanced malware detection
     */
    private $sensitivity_scanner;
    
    /**
     * Exclusion system for false positive filtering
     */
    private $exclusion_system;
    
    /**
     * Centralized exclusion manager for consistent exclusion logic
     */
    private $exclusion_manager;
    
    /**
     * WordPress integrity checker for file verification
     */
    private $wp_integrity_checker;
    
    /**
     * Scan metrics tracker for performance monitoring
     */
    private $scan_metrics;
    
    /**
     * Progress tracker for real-time scan updates
     */
    private $progress_tracker;
    
    /**
     * Pattern optimizer for regex performance optimization
     */
    private $pattern_optimizer;
    
    /**
     * URL safety checker for Google Safe Browsing integration
     */
    private $url_safety_checker;
    
    /**
     * Issue manager for enhanced issue classification and metadata
     */
    private $issue_manager;
    
    /**
     * File type handler for advanced file type detection
     */
    private $file_type_handler;
    
    /**
     * Current sensitivity mode (low/medium/high)
     */
    private $sensitivity_mode = 'medium';
    
    
    public function __construct() {
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Malware Scanner initialized';
        
        // Initialize binary detector for ultra-fast prefix detection
        $this->binary_detector = new VMPFence_Binary_Detector();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Binary detector initialized';
        
        // Initialize badstrings detector for suspicious string combinations (Step 3)
        $this->badstrings_detector = new VMPFence_Badstrings_Detector();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Badstrings detector initialized';
        
        // Step 4: Initialize advanced memory management and process forking
        $this->advanced_scan_engine = new VMPFence_Advanced_Scan_Engine();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Advanced scan engine initialized';
        
        $this->advanced_file_handler = new VMPFence_Advanced_File_Handler();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Advanced file handler initialized';
        
        // Step 5: Initialize high sensitivity scanner
        $this->sensitivity_scanner = new VMPFence_Sensitivity_Scanner();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Sensitivity scanner initialized';
        
        // Step 6: Initialize exclusion system for false positive filtering
        $this->exclusion_system = new VMPFence_Exclusion_System();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Exclusion system initialized';
        
        // Initialize centralized exclusion manager
        $this->exclusion_manager = VMPFence_Scan_Exclusion_Manager::getInstance();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Centralized exclusion manager initialized';
        
        // Step 7: Initialize WordPress integrity checker
        $this->wp_integrity_checker = new VMPFence_WP_Integrity_Checker();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] WP Integrity checker initialized';
        
        // Step 8: Initialize metrics tracking and progress updates
        $this->scan_metrics = new VMPFence_Scan_Metrics();
        $this->progress_tracker = new VMPFence_Progress_Tracker();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Metrics tracking and progress updates initialized';
        
        // Step 9: Initialize pattern optimizer for regex performance optimization
        $this->pattern_optimizer = new VMPFence_Pattern_Optimizer();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Pattern optimizer initialized';
        
        // Step 10: Initialize URL safety checker for Google Safe Browsing integration
        $this->url_safety_checker = new VMPFence_URL_Safety_Checker();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] URL safety checker initialized';
        
        // Step 11: Initialize issue manager for enhanced issue classification and metadata
        $this->issue_manager = new VMPFence_Issue_Manager();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Issue manager initialized';
        
        // Step 12: Initialize file type handler for advanced file type detection
        $this->file_type_handler = new VMPFence_File_Type_Handler();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] File type handler initialized';
        
        $this->init_malware_patterns();
    }
    
    /**
     * Initialize enhanced malware patterns with advanced rule structure
     * Adds pattern compilation and optimization
     * @since 1.0.0
     * @since 2.1.2 json file API signatures support fixed
     */
    private function init_malware_patterns() {
        // Initialize common strings optimizer first
        $this->common_strings_optimizer = new VMPFence_Common_Strings_Optimizer();
        
        // Initialize pattern harvester
        $this->pattern_harvester = new VMPFence_Pattern_Harvester($this->common_strings_optimizer);
        
        // Start with base patterns
        $base_patterns = array(
            // PHP Backdoors and Shells
            array(
                'rule_id' => 'php_backdoor_eval_enhanced',
                'category' => 'php_obfuscation',
                'pattern' => 'eval\s*\(\s*(?:base64_decode|gzinflate|str_rot13|gzuncompress)\s*\(',
                'description' => 'PHP backdoor using eval() with encoding functions (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'critical',
                'issue_type' => 'backdoor',
                'common_string_indexes' => array(0, 1, 2, 3), // eval, base64_decode, gzinflate, str_rot13
                'custom_message' => 'Critical PHP backdoor detected using eval with encoding functions'
            ),
            array(
                'rule_id' => 'php_shell_exec_enhanced',
                'category' => 'backdoors',
                'pattern' => '(?:system|exec|shell_exec|passthru|popen)\s*\(\s*\$_(?:GET|POST|REQUEST|COOKIE)',
                'description' => 'PHP shell execution with user input (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'critical',
                'issue_type' => 'backdoor',
                'common_string_indexes' => array(6, 7, 8, 9, 10, 22, 23, 24, 25), // system, exec, shell_exec, passthru, popen, $_GET, $_POST, $_REQUEST, $_COOKIE
                'custom_message' => 'Critical PHP shell execution with user input detected'
            ),
            array(
                'rule_id' => 'base64_malware_enhanced',
                'category' => 'php_obfuscation',
                'pattern' => 'base64_decode\s*\(\s*["\'][A-Za-z0-9+\/]{100,}["\']',
                'description' => 'Suspicious base64 encoded content (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'high',
                'issue_type' => 'obfuscation',
                'common_string_indexes' => array(1), // base64_decode
                'custom_message' => 'Suspicious base64 encoded content detected'
            ),
            
            // File Upload Exploits (Enhanced)
            array(
                'rule_id' => 'file_upload_bypass_enhanced',
                'category' => 'upload_exploits',
                'pattern' => 'move_uploaded_file\s*\([^,]+,\s*["\'][^"\']*\.(?:php|phtml|php3|php4|php5)',
                'description' => 'Suspicious file upload to PHP extension (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'high',
                'issue_type' => 'upload_exploit',
                'common_string_indexes' => array(13), // move_uploaded_file
                'custom_message' => 'Suspicious file upload to PHP extension detected'
            ),
            
            // WordPress Specific Threats (Enhanced)
            array(
                'rule_id' => 'wp_admin_bypass_enhanced',
                'category' => 'backdoors',
                'pattern' => 'wp_set_current_user\s*\(\s*[0-9]+\s*\).*wp_set_auth_cookie',
                'description' => 'WordPress authentication bypass attempt (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'critical',
                'issue_type' => 'auth_bypass',
                'common_string_indexes' => array(27, 28), // wp_set_current_user, wp_set_auth_cookie
                'custom_message' => 'Critical WordPress authentication bypass detected'
            ),
            array(
                'rule_id' => 'wp_user_creation_enhanced',
                'category' => 'backdoors',
                'pattern' => 'wp_create_user\s*\([^)]*["\'](?:admin|administrator|root)',
                'description' => 'Suspicious admin user creation (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'high',
                'issue_type' => 'privilege_escalation',
                'common_string_indexes' => array(26), // wp_create_user
                'custom_message' => 'Suspicious admin user creation detected'
            ),
            
            // Obfuscated Code (Enhanced)
            array(
                'rule_id' => 'hex_obfuscation_enhanced',
                'category' => 'php_obfuscation',
                'pattern' => '\\\\x[0-9a-fA-F]{2}\\\\x[0-9a-fA-F]{2}\\\\x[0-9a-fA-F]{2}',
                'description' => 'Hex-encoded obfuscated code (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'medium',
                'issue_type' => 'obfuscation',
                'common_string_indexes' => array(21), // \x pattern
                'custom_message' => 'Hex-encoded obfuscated code detected'
            ),
            array(
                'rule_id' => 'chr_obfuscation_enhanced',
                'category' => 'php_obfuscation',
                'pattern' => 'chr\s*\(\s*[0-9]+\s*\)\s*\.\s*chr\s*\(\s*[0-9]+\s*\)\s*\.\s*chr',
                'description' => 'Character-based code obfuscation (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'medium',
                'issue_type' => 'obfuscation',
                'common_string_indexes' => array(20), // chr
                'custom_message' => 'Character-based code obfuscation detected'
            ),
            
            // Remote Inclusion/Execution (Enhanced)
            array(
                'rule_id' => 'file_get_contents_url_enhanced',
                'category' => 'backdoors',
                'pattern' => '(?:<\?php|\$|function\s+|\w+\s*=).*file_get_contents\s*\(\s*["\']https?:\/\/.*(?:eval|system|exec|shell_exec|passthru|\$_(?:GET|POST|REQUEST))',
                'description' => 'Remote file inclusion with code execution (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'medium',
                'issue_type' => 'remote_inclusion',
                'common_string_indexes' => array(11), // file_get_contents
                'custom_message' => 'Remote file inclusion with code execution detected'
            ),
            array(
                'rule_id' => 'curl_suspicious_enhanced',
                'category' => 'backdoors',
                'pattern' => 'curl_exec\s*\([^)]*\).*(?:eval|system|exec)',
                'description' => 'Suspicious cURL execution with code execution (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'high',
                'issue_type' => 'remote_execution',
                'common_string_indexes' => array(36, 0, 6, 7), // curl_exec, eval, system, exec
                'custom_message' => 'Suspicious cURL execution with code execution detected'
            ),
            
            // Additional SQL Injection (Enhanced)
            array(
                'rule_id' => 'sql_injection_enhanced',
                'category' => 'sql_injection',
                'pattern' => '\$_(?:GET|POST|REQUEST|COOKIE)\[[^\]]+\].*(?:SELECT|INSERT|UPDATE|DELETE|DROP|UNION).*FROM',
                'description' => 'Potential SQL injection pattern (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'high',
                'issue_type' => 'injection',
                'common_string_indexes' => array(22, 23, 24, 25, 29, 30, 31, 32, 33, 34, 35), // $_*, SQL keywords
                'custom_message' => 'Potential SQL injection pattern detected'
            ),
            
            // Redirect Malware (Enhanced)
            array(
                'rule_id' => 'malicious_redirect_enhanced',
                'category' => 'backdoors',
                'pattern' => 'header\s*\(\s*["\']location:\s*(?:https?:\/\/)?(?!' . preg_quote(wp_parse_url(home_url(), PHP_URL_HOST), '/') . ')',
                'description' => 'Unauthorized redirect to external domain (Enhanced)',
                'scan_type' => 'file_content',
                'log_only' => false,
                'severity' => 'medium',
                'issue_type' => 'redirect',
                'common_string_indexes' => array(14, 15), // header, location:
                'custom_message' => 'Unauthorized redirect to external domain detected'
            )
        );
        
        // Add base patterns to collection
        $this->malware_patterns = $base_patterns;
        
        // Harvest additional patterns from YARA rules
        $yara_patterns = $this->pattern_harvester->harvest_yara_rules();
        $this->malware_patterns = array_merge($this->malware_patterns, $yara_patterns);
        
        // Harvest additional patterns from GitHub samples
        $github_patterns = $this->pattern_harvester->harvest_github_samples();
        $this->malware_patterns = array_merge($this->malware_patterns, $github_patterns);
        
        // Add user-defined custom signatures (scan_include_extra)
        // error_log('VMPFence Custom: Loading user signatures...');
        $user_signatures = $this->get_user_scan_signatures();
        // error_log('VMPFence Custom: Loaded ' . count($user_signatures) . ' user signatures');
        
        // Log each custom signature pattern
        // foreach ($user_signatures as $sig) {
        //     error_log('VMPFence Custom: Pattern loaded - Rule: ' . $sig['rule_id'] . ', Pattern: "' . $sig['pattern'] . '"');
        // }
        
        $this->malware_patterns = array_merge($this->malware_patterns, $user_signatures);
        
        // Load API signatures from JSON file (if available)
        require_once plugin_dir_path(__FILE__) . 'class-signature-loader.php';
        $signature_loader = VMPFence_Signature_Loader::get_instance();
        
        // Conflict #9 fix: Call get_signatures() directly instead of using is_loaded() gate.
        // With lazy loading, is_loaded() returns false before first get_signatures() call,
        // which would silently skip all 101K API signatures. get_signatures() triggers the
        // lazy load, then we check if we got anything.
        $api_signatures_raw = $signature_loader->get_signatures();
        
        if (!empty($api_signatures_raw)) {
            
            // Handle different JSON formats:
            // Format 1 (API export): {"signatures": [{"signature_id": "...", ...}, ...]}
            // Format 2 (Template): {"signatures": {"category": [...], ...}}
            $api_sigs = array();
            
            if (isset($api_signatures_raw['signatures'])) {
                $sigs_data = $api_signatures_raw['signatures'];
                
                // Check if it's an array of signature objects (API format)
                if (is_array($sigs_data) && !empty($sigs_data)) {
                    // Check first element to determine format
                    $first_element = reset($sigs_data);
                    
                    if (is_array($first_element) && isset($first_element['signature_id'])) {
                        // Format 1: Array of signature objects from API
                        $api_sigs = $sigs_data;
                        $this->debug_log[] = '[' . current_time('H:i:s') . '] Detected API signature format (array of objects)';
                    } elseif (is_string($first_element) || (is_array($first_element) && !isset($first_element['signature_id']))) {
                        // Format 2: Template format with categories
                        $this->debug_log[] = '[' . current_time('H:i:s') . '] Detected template signature format (will skip - not API signatures)';
                        $api_sigs = array(); // Don't try to convert template format
                    }
                }
            } elseif (is_array($api_signatures_raw) && !empty($api_signatures_raw)) {
                // Fallback: Root is array of signatures
                $first_element = reset($api_signatures_raw);
                if (is_array($first_element) && isset($first_element['signature_id'])) {
                    $api_sigs = $api_signatures_raw;
                    $this->debug_log[] = '[' . current_time('H:i:s') . '] Detected API signature format (root array)';
                }
            }
            
            // Convert to scanner format
            if (!empty($api_sigs)) {
                $api_patterns = $this->convert_api_signatures_to_patterns($api_sigs);
                
                if (!empty($api_patterns)) {
                    $this->malware_patterns = array_merge($this->malware_patterns, $api_patterns);
                    $this->debug_log[] = sprintf(
                        '[%s] Loaded %d API signatures from JSON (Total patterns: %d)',
                        current_time('H:i:s'),
                        count($api_patterns),
                        count($this->malware_patterns)
                    );
                } else {
                    $this->debug_log[] = '[' . current_time('H:i:s') . '] WARNING: No usable API signatures found (all non-regex patterns)';
                }
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] INFO: No API signatures in JSON (template format detected or empty)';
            }
        } else {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] INFO: API signatures JSON not loaded, using built-in patterns';
        }
        
        // Optimize common strings for all patterns
        $this->pattern_harvester->optimize_common_strings();
        
        // Step 9: Compile and validate patterns for optimal performance
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Starting pattern optimization (Step 9)...';
        
        // Validate pattern compilation
        $validation_results = $this->pattern_optimizer->validate_pattern_compilation($this->malware_patterns);
        $this->debug_log[] = sprintf(
            'Pattern compilation validation: %d/%d patterns valid (%.1f%% success rate)',
            count($validation_results['valid_patterns']),
            $validation_results['total_patterns'],
            $validation_results['validation_summary']['success_rate']
        );
        
        // Optimize backtrack limits
        $backtrack_optimization = $this->pattern_optimizer->optimize_backtrack_limits($this->malware_patterns);
        $this->debug_log[] = sprintf(
            'Backtrack optimization: Recommended limit %d (was %s)',
            $backtrack_optimization['recommended_limit'],
            $backtrack_optimization['original_limit']
        );
        
        // Benchmark pattern performance
        $benchmark_results = $this->pattern_optimizer->benchmark_pattern_performance($this->malware_patterns, 1000);
        $this->debug_log[] = sprintf(
            'Pattern benchmarking: Average %.6f seconds per pattern, Performance score: %.1f/100',
            $benchmark_results['performance_summary']['average_time_per_pattern'],
            $benchmark_results['performance_summary']['average_performance_score']
        );
        
        // Use optimized compiled patterns
        $compiled_patterns = $this->pattern_optimizer->get_compiled_patterns();
        if (!empty($compiled_patterns)) {
            // Replace patterns with compiled versions for better performance
            foreach ($compiled_patterns as $pattern_id => $compiled_pattern) {
                if (isset($this->malware_patterns[$pattern_id])) {
                    $this->malware_patterns[$pattern_id]['pattern'] = $compiled_pattern;
                    $this->malware_patterns[$pattern_id]['optimized'] = true;
                }
            }
            $this->debug_log[] = sprintf('Applied %d compiled patterns for enhanced performance', count($compiled_patterns));
        }
        
        // Validate all patterns
        $validation_results = $this->pattern_harvester->validate_patterns($this->malware_patterns);
        
        // Log pattern loading results
        $this->debug_log[] = sprintf(
            'Enhanced Pattern System: Loaded %d total patterns (%d valid, %d invalid, %d warnings)',
            $validation_results['total_patterns'],
            $validation_results['valid_patterns'], 
            $validation_results['invalid_patterns'],
            $validation_results['performance_warnings']
        );
        
        // Log comparison with old system
        $this->debug_log[] = sprintf(
            'Pattern Enhancement: Expanded from 13 static patterns to %d dynamic patterns (%.1fx improvement)',
            count($this->malware_patterns),
            count($this->malware_patterns) / 13
        );
    }
    
    /**
     * Process user-defined scan signatures from scan_include_extra option
     * Implements custom malware signatures functionality
     * 
     * @return array Array of user-defined patterns in VMPFence format
     */
    private function get_user_scan_signatures() {
        $signatures = array();
        
        // error_log('[VMPFence Debug] get_user_scan_signatures() method called');
        
        // Get scan_include_extra option value
        $scan_include_extra = '';
        if ($this->scan_options && isset($this->scan_options['scan_include_extra'])) {
            $scan_include_extra = $this->scan_options['scan_include_extra'];
        } else {
            // Fall back to direct config retrieval if not in scan options
            $scan_include_extra = VMPFence_Config::get('scan_include_extra', '');
        }
        
        // error_log('[VMPFence] Custom signatures retrieved: ' . var_export($scan_include_extra, true));
        
        if (empty($scan_include_extra)) {
            // error_log('[VMPFence] No custom signatures found');
            $this->debug_log[] = '[' . current_time('H:i:s') . '] No custom scan signatures defined (scan_include_extra empty)';
            return $signatures;
        }
        
        // error_log('[VMPFence] Processing custom signatures: ' . $scan_include_extra);
        
        // Decode HTML entities that may have been encoded during form submission
        $scan_include_extra = html_entity_decode($scan_include_extra, ENT_QUOTES, 'UTF-8');
        
        // Parse signatures (one per line)
        $regex_patterns = explode("\n", $scan_include_extra);
        $rule_id = 1000001;
        $valid_count = 0;
        $invalid_count = 0;
        
        foreach ($regex_patterns as $pattern) {
            $pattern = trim($pattern, "\r\n\t ");
            
            // Skip empty lines
            if (empty($pattern)) {
                continue;
            }
            
            // Skip comments (lines starting with #)
            if (strpos($pattern, '#') === 0) {
                continue;
            }
            
            // Test if the regex pattern is valid (don't escape for storage - will be escaped at match time)
            // error_log('[VMPFence] Testing pattern: ' . var_export($pattern, true));
            $escaped_pattern = preg_quote($pattern, '#');
            $test_result = @preg_match('#' . $escaped_pattern . '#i', '');
            
            if ($test_result !== false) {
                // error_log('[VMPFence] Pattern is valid, adding to signatures');
                $signatures[] = array(
                    'rule_id' => 'user_custom_' . $rule_id,
                    'category' => 'user_defined',
                    'pattern' => $pattern, // Store the raw pattern, not pre-escaped
                    'description' => 'User defined custom scan pattern',
                    'scan_type' => 'file_content',
                    'log_only' => false,
                    'severity' => 'high',
                    'issue_type' => 'custom_signature',
                    'common_string_indexes' => array(), // No optimization for custom patterns
                    'custom_message' => 'Custom malware signature match detected'
                );
                $valid_count++;
                $rule_id++;
            } else {
                // error_log('[VMPFence] Pattern is invalid, skipping: ' . $pattern);
                $invalid_count++;
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Invalid custom signature pattern skipped: ' . $pattern;
            }
        }
        
        // error_log('[VMPFence] Loaded ' . count($signatures) . ' custom signatures');
        
        $this->debug_log[] = sprintf(
            '[%s] Loaded %d custom scan signatures (%d valid, %d invalid)',
            current_time('H:i:s'),
            $valid_count,
            $valid_count,
            $invalid_count
        );

        return $signatures;
    }
    
    /**
     * Convert API signatures from JSON to scanner pattern format
     * Filters by pattern_format to only include patterns scanner can use
     * 
     * @param array $api_signatures Raw signatures from API JSON
     * @return array Converted patterns in scanner format
     * @since 2.1.2
     */
    private function convert_api_signatures_to_patterns($api_signatures) {
        $converted = array();
        
        if (empty($api_signatures) || !is_array($api_signatures)) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Converter: Invalid input (empty or not array)';
            return $converted;
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Converting ' . count($api_signatures) . ' API signatures...';
        
        $converted_count = 0;
        $skipped_count = 0;
        $error_count = 0;
        
        foreach ($api_signatures as $sig) {
            // Validate signature is an array with required fields
            if (!is_array($sig)) {
                $error_count++;
                continue;
            }
            
            // Must have either signature_id or pattern to be valid
            if (!isset($sig['signature_id']) && !isset($sig['pattern'])) {
                $error_count++;
                continue;
            }
            
            // Skip inactive signatures
            if (isset($sig['is_active']) && !$sig['is_active']) {
                $skipped_count++;
                continue;
            }
            
            // Only convert patterns that scanner can use (regex patterns)
            $pattern_format = isset($sig['pattern_format']) ? $sig['pattern_format'] : 'regex';
            
            // Skip non-regex patterns (URLs, domains, file hashes)
            // These are for different scan types (network monitoring, file hash checks)
            if (in_array($pattern_format, array('url', 'domain', 'ip', 'hash', 'sha256', 'md5'))) {
                $skipped_count++;
                continue;
            }
            
            // Validate pattern exists and is not empty
            if (!isset($sig['pattern']) || empty($sig['pattern'])) {
                $error_count++;
                continue;
            }
            
            // Convert regex patterns to scanner format
            if ($pattern_format === 'regex') {
                $converted[] = array(
                    'rule_id' => 'api_' . (isset($sig['signature_id']) ? $sig['signature_id'] : uniqid()),
                    'category' => $this->map_malware_type_to_category(isset($sig['malware_type']) ? $sig['malware_type'] : 'unknown'),
                    'pattern' => $sig['pattern'], // Already a regex pattern
                    'description' => isset($sig['description']) ? $sig['description'] : 'API malware signature',
                    'scan_type' => 'file_content',
                    'log_only' => false,
                    'severity' => strtolower(isset($sig['severity']) ? $sig['severity'] : 'medium'),
                    'issue_type' => $this->map_malware_type_to_issue_type(isset($sig['malware_type']) ? $sig['malware_type'] : 'unknown'),
                    'common_string_indexes' => array(), // No optimization for API patterns yet
                    'custom_message' => sprintf('API Signature: %s - %s', 
                        isset($sig['malware_family']) ? $sig['malware_family'] : 'Unknown', 
                        isset($sig['description']) ? $sig['description'] : 'Malware detected')
                );
                $converted_count++;
            } else {
                $skipped_count++;
            }
        }
        
        $this->debug_log[] = sprintf(
            '[%s] API signature conversion: %d converted, %d skipped (non-regex), %d errors (invalid format)',
            current_time('H:i:s'),
            $converted_count,
            $skipped_count,
            $error_count
        );
        
        return $converted;
    }
    
    /**
     * Map API malware_type to scanner category
     * 
     * @param string $malware_type Malware type from API
     * @return string Scanner category
     * @since 2.1.2
     */
    private function map_malware_type_to_category($malware_type) {
        $mapping = array(
            'file' => 'backdoors',
            'network' => 'backdoors',
            'webshell' => 'webshells',
            'backdoor' => 'backdoors',
            'trojan' => 'backdoors',
            'exploit' => 'upload_exploits',
            'injection' => 'sql_injection',
            'phishing' => 'backdoors',
            'ransomware' => 'backdoors',
            'unknown' => 'backdoors'
        );
        
        return isset($mapping[$malware_type]) ? $mapping[$malware_type] : 'backdoors';
    }
    
    /**
     * Map API malware_type to scanner issue_type
     * 
     * @param string $malware_type Malware type from API
     * @return string Scanner issue type
     * @since 2.1.2
     */
    private function map_malware_type_to_issue_type($malware_type) {
        $mapping = array(
            'file' => 'malware',
            'network' => 'remote_connection',
            'webshell' => 'webshell',
            'backdoor' => 'backdoor',
            'trojan' => 'trojan',
            'exploit' => 'upload_exploit',
            'injection' => 'sql_injection',
            'phishing' => 'phishing',
            'ransomware' => 'ransomware',
            'unknown' => 'malware'
        );
        
        return isset($mapping[$malware_type]) ? $mapping[$malware_type] : 'malware';
    }
    
    /**
     * Enhanced file type detection and scanning logic
     * Replaces basic extension checking with advanced file type analysis
     */
    
    /**
     * Legacy file extensions (kept for backward compatibility)
     * @deprecated Use advanced file type detection instead
     */
    private $legacy_scannable_extensions = array(
        'php', 'php3', 'php4', 'php5', 'php7', 'phtml', 'phps',
        'js', 'html', 'htm', 'htaccess', 'txt', 'log'
    );
    
    /**
     * Determine if file should be scanned using advanced file type detection
     * 
     * @param string $file_path Path to the file
     * @return array File scanning decision and metadata
     * @since 1.0.0
     * @since 2.1.2 self plugin directory exclusion added dynamically
     */
    private function should_scan_file_advanced($file_path) {
        // Check centralized exclusion manager first
        if ($this->exclusion_manager->should_exclude_file($file_path)) {
            return [
                'should_scan' => false,
                'scan_as_php' => false,
                'file_type' => 'excluded',
                'scan_reasons' => ['Excluded by user exclusion patterns'],
                'metadata' => []
            ];
        }
        
        // Normalize path separators for cross-platform compatibility
        $normalized_path = str_replace('\\', '/', $file_path);
        
        // Get dynamic plugin directory name for exclusion
        $plugin_dir_normalized = str_replace('\\', '/', VMPFENCE_PLUGIN_DIR);
        // Skip our own plugin files first (dynamic exclusion)
        if (strpos($normalized_path, $plugin_dir_normalized) !== false) {
            return [
                'should_scan' => false,
                'scan_as_php' => false,
                'file_type' => 'system',
                'scan_reasons' => ['Skipped - VMPFence plugin files'],
                'patterns_to_use' => [],
                'type_analysis' => [],
            ];
        }
        
        // Skip common development and system files that generate false positives
        $excluded_patterns = [
            '/.git/',
            '/.svn/',
            '/node_modules/',
            '/vendor/',            // Skip composer vendor directories
            '/.vscode/',          // Skip VS Code settings
            '/.DS_Store',
            '/Thumbs.db',
            '/wp-includes/css/',   // Skip WordPress core CSS files
            '/wp-includes/js/',    // Skip WordPress core JS files
            '/wp-includes/images/', // Skip WordPress core image files
            '/wp-admin/css/',      // Skip WordPress admin CSS files
            '/wp-admin/js/',       // Skip WordPress admin JS files
            '/wp-admin/images/',   // Skip WordPress admin image files
            '/wp-includes/ID3/readme.txt', // Skip getID3 documentation
            '/wp-includes/Text/Diff/readme.txt', // Skip Text_Diff documentation
            '/wp-includes/PHPMailer/readme.txt', // Skip PHPMailer documentation
            '/wp-includes/Requests/readme.txt', // Skip Requests library documentation
            '/wp-includes/SimplePie/readme.txt', // Skip SimplePie documentation
        ];
        
        // Skip specific file extensions that are safe binary files
        $safe_extensions = ['woff', 'woff2', 'ttf', 'otf', 'eot', 'mp4', 'avi', 'mov', 'mp3', 'wav', 'mo'];
        $file_ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
        
        if (in_array($file_ext, $safe_extensions)) {
            return [
                'should_scan' => false,
                'scan_as_php' => false,
                'file_type' => 'safe_binary',
                'scan_reasons' => ['Skipped - Safe binary file extension'],
                'patterns_to_use' => [],
                'type_analysis' => [],
            ];
        }
        
        foreach ($excluded_patterns as $pattern) {
            if (strpos($normalized_path, $pattern) !== false) {
                return [
                    'should_scan' => false,
                    'scan_as_php' => false,
                    'file_type' => 'system',
                    'scan_reasons' => ['Skipped - Development/system file'],
                    'patterns_to_use' => [],
                    'type_analysis' => [],
                ];
            }
        }
        
        // Use advanced file type detection
        $detected_type = $this->file_type_handler->detect_file_type_advanced($file_path);
        $scan_recommendations = $this->file_type_handler->get_scanning_recommendations($detected_type);
        
        // Get type-specific rules and analysis
        $file_content = null;
        if (file_exists($file_path) && filesize($file_path) < 5242880) { // 5MB limit for content analysis
            $file_content = file_get_contents($file_path);
        }
        
        $type_analysis = $this->file_type_handler->apply_type_specific_rules($file_path, $detected_type, $file_content);
        
        // Determine if we should scan this file
        $should_scan = false;
        $scan_reasons = [];
        
        // Check if file type should be completely skipped (fonts, videos, audio)
        $type_rules = $this->file_type_handler->get_scanning_rules($detected_type);
        if (isset($type_rules['skip_scanning']) && $type_rules['skip_scanning']) {
            return [
                'should_scan' => false,
                'scan_as_php' => false,
                'file_type' => $detected_type,
                'scan_reasons' => ['Skipped - Safe binary file type'],
                'patterns_to_use' => [],
                'type_analysis' => $type_analysis,
            ];
        }
        
        // Always scan if advanced handler recommends content scanning
        if ($scan_recommendations['scan_content']) {
            $should_scan = true;
            $scan_reasons[] = 'Content scanning recommended for file type';
        }
        
        // Always scan PHP files (including those with PHP code in other file types)
        if ($this->file_type_handler->should_scan_as_php($file_path, $detected_type, $file_content)) {
            $should_scan = true;
            $scan_reasons[] = 'Contains PHP code or is PHP file';
        }
        
        // Scan high-risk file types
        if ($scan_recommendations['security_risk'] === 'high') {
            $should_scan = true;
            $scan_reasons[] = 'High security risk file type';
        }
        
        // Scan files with security concerns identified
        if (!empty($type_analysis['security_concerns'])) {
            $should_scan = true;
            $scan_reasons[] = 'Security concerns detected: ' . implode(', ', $type_analysis['security_concerns']);
        }
        
        // Fallback to legacy extension checking for unknown types
        if ($detected_type === VMPFence_File_Type_Handler::TYPE_UNKNOWN) {
            $extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
            if (in_array($extension, $this->legacy_scannable_extensions)) {
                $should_scan = true;
                $scan_reasons[] = 'Legacy extension match';
            }
        }
        
        return [
            'should_scan' => $should_scan,
            'detected_type' => $detected_type,
            'type_description' => $this->file_type_handler->get_type_description($detected_type),
            'scan_reasons' => $scan_reasons,
            'recommendations' => $scan_recommendations,
            'type_analysis' => $type_analysis,
            'scanning_priority' => $scan_recommendations['priority'],
            'security_risk' => $scan_recommendations['security_risk']
        ];
    }
    
    /**
     * Apply type-specific scanning patterns
     * 
     * @param string $file_path Path to the file
     * @param string $content File content
     * @param array $file_analysis File analysis from should_scan_file_advanced()
     * @return array Additional patterns to apply
     */
    private function get_type_specific_patterns($file_path, $content, $file_analysis) {
        $additional_patterns = [];
        $detected_type = $file_analysis['detected_type'];
        
        // SVG-specific patterns (treat as JavaScript)
        if ($detected_type === VMPFence_File_Type_Handler::TYPE_SVG) {
            $additional_patterns = array_merge($additional_patterns, [
                [
                    'rule_id' => 'svg_script_injection',
                    'category' => 'svg_malware',
                    'pattern' => '<script[^>]*>.*?</script>',
                    'description' => 'JavaScript injection in SVG file',
                    'severity' => 'high',
                    'issue_type' => 'script_injection'
                ],
                [
                    'rule_id' => 'svg_event_handler',
                    'category' => 'svg_malware', 
                    'pattern' => 'on(load|error|click|mouseover|focus|submit)\s*=\s*["\'][^"\']*(?:javascript|eval|alert|document\.|window\.)[^"\']*["\']',
                    'description' => 'Event handler in SVG (potential XSS)',
                    'severity' => 'medium',
                    'issue_type' => 'xss_vector'
                ]
            ]);
        }
        
        // Image files with PHP code
        if ($detected_type === VMPFence_File_Type_Handler::TYPE_IMAGE && 
            $this->file_type_handler->should_scan_as_php($file_path, $detected_type, $content)) {
            $additional_patterns = array_merge($additional_patterns, [
                [
                    'rule_id' => 'image_php_injection',
                    'category' => 'image_malware',
                    'pattern' => '<\?(?:php|=|\s).*?\?>',
                    'description' => 'PHP code embedded in image file',
                    'severity' => 'critical',
                    'issue_type' => 'file_inclusion'
                ]
            ]);
        }
        
        // JavaScript-specific patterns for .js files
        if ($detected_type === VMPFence_File_Type_Handler::TYPE_JAVASCRIPT) {
            $additional_patterns = array_merge($additional_patterns, [
                [
                    'rule_id' => 'js_eval_obfuscated',
                    'category' => 'javascript_malware',
                    'pattern' => 'eval\s*\(\s*(?:unescape|decodeURIComponent|atob)\s*\(',
                    'description' => 'Obfuscated JavaScript eval usage',
                    'severity' => 'high',
                    'issue_type' => 'code_injection'
                ],
                [
                    'rule_id' => 'js_document_write_injection',
                    'category' => 'javascript_malware',
                    'pattern' => 'document\.write\s*\(\s*[^)]*(?:script|iframe)[^)]*\)',
                    'description' => 'Dynamic script/iframe injection via document.write',
                    'severity' => 'medium',
                    'issue_type' => 'dom_injection'
                ]
            ]);
        }
        
        // HTML-specific patterns
        if ($detected_type === VMPFence_File_Type_Handler::TYPE_HTML) {
            $additional_patterns = array_merge($additional_patterns, [
                [
                    'rule_id' => 'html_malicious_iframe',
                    'category' => 'html_malware',
                    'pattern' => '<iframe[^>]*(?:src\s*=\s*["\'](?:https?://)?[^"\']*(?:\.tk|\.ml|\.ga|\.cf)[^"\']*["\']|style\s*=\s*["\'][^"\']*(?:display\s*:\s*none|visibility\s*:\s*hidden)[^"\']*["\'])',
                    'description' => 'Suspicious iframe (hidden or suspicious domain)',
                    'severity' => 'high',
                    'issue_type' => 'malicious_redirect'
                ]
            ]);
        }
        
        return $additional_patterns;
    }
    
    /**
     * Directories to exclude from scanning
     */
    private $excluded_directories = array(
        '/wp-content/uploads/cache/',
        '/wp-content/cache/',
        '/wp-content/backup/',
        '/node_modules/',
        '/.git/',
        '/vendor/'
    );
    
    
    
    /**
     * Main scan execution method
     * @param array $scan_options Optional scan configuration options
     * @return array Detected malware issues
     * @since 1.0.0
     * @since 2.1.1 Added performance controls initialization
     */
    public function scan($scan_options = null) {
        // Initialize performance controls if available
        $use_performance_controls = false;
        if (class_exists('VMPFence_Performance_Manager')) {
            VMPFence_Performance_Manager::init();
            $use_performance_controls = true;
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Malware Scanner: Performance controls initialized';
        }
        
        // If scan options provided, respect them
        if ($scan_options) {
            $this->scan_options = $scan_options;
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Malware Scanner: Scan options loaded';
            
            // Initialize exclusion manager with scan options
            $this->exclusion_manager->initialize($scan_options);
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Starting malware scan...';
        
        // Step 8: Start metrics tracking and progress monitoring
        $this->scan_metrics->track_scan_progress();
        $this->progress_tracker->update_progress('Initializing scan...');
        
        // Step 4: Initialize advanced scan engine
        $this->advanced_scan_engine->start_scan();
        
        $start_time = microtime(true);
        $issues = array();

        try {
            // Clear previous malware scan data
            $this->clear_previous_scan_data();
            
            // CRITICAL FIX: Clear old batch checkpoints at scan start
            // This ensures we don't resume old partial scans from a previous interrupted session
            // unless the scan is explicitly resuming (which would be detected by progress tracker)
            if (!$this->progress_tracker->has_existing_interrupted_scan()) {
                delete_transient('vmpfence_processed_plugins');
                delete_transient('vmpfence_processed_themes');
                delete_transient('vmpfence_scan_needs_resume');
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Starting fresh scan - batch checkpoints cleared';
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Resuming interrupted scan - keeping batch checkpoints';
            }
            
            // Step 8: Count total files for progress tracking
            $total_files = $this->count_total_files_for_scan();
            $this->progress_tracker->set_total_files($total_files);
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Total files to scan: ' . $total_files;
            
            // NOTE: Legacy checkpoint system from advanced_scan_engine is deprecated
            // NEW batching system handles resume automatically via transients:
            // - vmpfence_processed_plugins (tracks completed plugins)
            // - vmpfence_processed_themes (tracks completed themes)
            // - vmpfence_scan_needs_resume (signals partial batch)
            // These are loaded/saved in scan_plugins() and scan_themes() automatically
            
            // 1. Scan WordPress core files
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_malware_core']) || $this->scan_options['scansEnabled_malware_core']) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanning WordPress core files...';
                $core_issues = $this->scan_wordpress_core();
                $issues = array_merge($issues, $core_issues);
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Malware Scanner: Core files scan disabled by configuration';
            }
            
            // Step 4: Monitor memory after core scan
            $memory_status = $this->advanced_scan_engine->monitor_memory_usage();
            if ($memory_status === 'critical') {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Critical memory usage detected, creating checkpoint...';
                $this->advanced_scan_engine->create_scan_checkpoint(array(
                    'stage' => 'after_core_scan',
                    'issues_found' => count($issues)
                ));
            }
            
            // 2. Scan active plugins
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_malware_plugins']) || $this->scan_options['scansEnabled_malware_plugins']) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanning active plugins...';
                $plugin_issues = $this->scan_plugins();
                $issues = array_merge($issues, $plugin_issues);
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Malware Scanner: Plugins scan disabled by configuration';
            }
            
            // Step 4: Monitor memory after plugin scan
            $memory_status = $this->advanced_scan_engine->monitor_memory_usage();
            if ($memory_status === 'critical') {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Critical memory usage detected, creating checkpoint...';
                $this->advanced_scan_engine->create_scan_checkpoint(array(
                    'stage' => 'after_plugin_scan',
                    'issues_found' => count($issues)
                ));
            }
            
            // 3. Scan active theme
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_malware_themes']) || $this->scan_options['scansEnabled_malware_themes']) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanning active theme...';
                $theme_issues = $this->scan_themes();
                $issues = array_merge($issues, $theme_issues);
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Malware Scanner: Themes scan disabled by configuration';
            }
            
            // 4. Scan uploads directory (limited)
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_malware_uploads']) || $this->scan_options['scansEnabled_malware_uploads']) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanning uploads directory for PHP files...';
                $upload_issues = $this->scan_uploads_directory();
                $issues = array_merge($issues, $upload_issues);
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Malware Scanner: Uploads directory scan disabled by configuration';
            }
            
            // Step 10: URL Safety Checking - Extract and verify URLs from scanned files
            // Only run if scansEnabled_fileContentsGSB is enabled
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_fileContentsGSB']) || $this->scan_options['scansEnabled_fileContentsGSB']) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Starting URL safety checking...';
                $url_issues = $this->check_embedded_urls($issues);
                if (!empty($url_issues)) {
                    $issues = array_merge($issues, $url_issues);
                    $this->debug_log[] = '[' . current_time('H:i:s') . '] Found ' . count($url_issues) . ' suspicious URLs';
                }
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] URL safety checking disabled by scan options';
            }
            
            $end_time = microtime(true);
            $scan_duration = round($end_time - $start_time, 2);
            
            // CRITICAL FIX: Clear batch checkpoints on successful scan completion
            delete_transient('vmpfence_processed_plugins');
            delete_transient('vmpfence_processed_themes');
            delete_transient('vmpfence_scan_needs_resume');
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Batch checkpoints cleared - scan cycle complete';
            
            // Step 8: Complete progress tracking and generate metrics report
            $this->progress_tracker->complete_scan([
                'total_issues' => count($issues),
                'scan_duration' => $scan_duration
            ]);
            
            // Step 8: Generate comprehensive metrics report
            $metrics_report = $this->scan_metrics->generate_metrics_report();
            
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Malware scan completed in ' . $scan_duration . ' seconds';
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Found ' . count($issues) . ' potential malware issues';
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanned ' . $this->total_files_scanned . ' files total';
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Performance Grade: ' . ($metrics_report['efficiency_analysis']['performance_grade'] ?? 'N/A');
            
            // Step 4: Complete scan and get performance metrics
            $scan_completion_data = $this->advanced_scan_engine->complete_scan();
            $memory_statistics = $this->advanced_file_handler->get_memory_statistics();
            
            // Log performance metrics
            if (!empty($memory_statistics)) {
                $this->debug_log[] = sprintf(
                    '[%s] Memory Statistics: Peak %.2fMB, Average %.2fMB, Peak Usage %.1f%%',
                    current_time('H:i:s'),
                    $memory_statistics['peak_usage'] / 1024 / 1024,
                    $memory_statistics['average_usage'] / 1024 / 1024,
                    $memory_statistics['max_percentage']
                );
            }
            
            // Save scan results to database (always save, even if no issues found)
            $this->save_scan_results($issues);
            
            // Update statistics collector with files scanned
            if (class_exists('VMPFence_Scan_Statistics_Collector')) {
                $stats_collector = VMPFence_Scan_Statistics_Collector::get_instance();
                $stats_collector->add_files_scanned($this->total_files_scanned);
            }
            
        } catch (Exception $e) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Error during malware scan: ' . $e->getMessage();
            
            // Step 4: Create emergency checkpoint on error
            $this->advanced_scan_engine->create_scan_checkpoint(array(
                'error' => $e->getMessage(),
                'stage' => 'error_recovery',
                'issues_found' => count($issues)
            ));
            
            // error_log('VMPFence Malware Scanner Error: ' . $e->getMessage());
        }
        
        // Apply performance controls to limit issues if enabled
        if (class_exists('VMPFence_Performance_Manager')) {
            $issues = VMPFence_Performance_Manager::limit_issues($issues);
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Performance Manager: Limited issues to ' . count($issues);
        }
        
        return array(
            'issues_found' => count($issues),
            'issues' => $issues,
            'scanned_count' => $this->total_files_scanned,
            'scan_type' => $this->scan_type,
            'debug_log' => $this->debug_log,
            'memory_statistics' => isset($memory_statistics) ? $memory_statistics : array(),
            'performance_metrics' => isset($scan_completion_data) ? $scan_completion_data['performance_metrics'] : array(),
            'exclusion_statistics' => $this->exclusion_system->get_exclusion_stats(),
            'integrity_statistics' => $this->wp_integrity_checker->get_integrity_stats(),
            // Step 8: Include comprehensive metrics report and progress data
            'metrics_report' => isset($metrics_report) ? $metrics_report : array(),
            'progress_data' => $this->progress_tracker->get_progress()
        );
    }
    
    /**
     * Count total files for scan progress tracking
     * Required by Step 8 for accurate progress percentage calculation
     */
    private function count_total_files_for_scan() {
        $total_files = 0;
        
        // Count WordPress core files
        $wp_core_dirs = array(ABSPATH . 'wp-admin', ABSPATH . 'wp-includes');
        foreach ($wp_core_dirs as $dir) {
            if (is_dir($dir)) {
                $total_files += $this->count_files_in_directory($dir);
            }
        }
        
        // Count plugin files
        $plugins_dir = WP_CONTENT_DIR . '/plugins';
        if (is_dir($plugins_dir)) {
            $active_plugins = get_option('active_plugins', array());
            foreach ($active_plugins as $plugin) {
                $plugin_dir = $plugins_dir . '/' . dirname($plugin);
                if (is_dir($plugin_dir)) {
                    $total_files += $this->count_files_in_directory($plugin_dir);
                }
            }
        }
        
        // Count theme files
        $themes_dir = get_theme_root();
        if (is_dir($themes_dir)) {
            $active_theme = get_stylesheet();
            $theme_dir = $themes_dir . '/' . $active_theme;
            if (is_dir($theme_dir)) {
                $total_files += $this->count_files_in_directory($theme_dir);
            }
        }
        
        // Count uploads directory PHP files
        $uploads_dir = wp_upload_dir()['basedir'];
        if (is_dir($uploads_dir)) {
            $total_files += $this->count_php_files_in_directory($uploads_dir);
        }
        
        return $total_files;
    }
    
    /**
     * Count files in directory recursively
     */
    private function count_files_in_directory($directory) {
        $count = 0;
        if (!is_dir($directory)) {
            return 0;
        }
        
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::LEAVES_ONLY
        );
        
        foreach ($iterator as $file) {
            if ($file->isFile() && $this->should_scan_file($file->getPathname())) {
                $count++;
            }
        }
        
        return $count;
    }
    
    /**
     * Count PHP files in directory recursively
     */
    private function count_php_files_in_directory($directory) {
        $count = 0;
        if (!is_dir($directory)) {
            return 0;
        }
        
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::LEAVES_ONLY
        );
        
        foreach ($iterator as $file) {
            if ($file->isFile() && pathinfo($file->getPathname(), PATHINFO_EXTENSION) === 'php') {
                $count++;
            }
        }
        
        return $count;
    }
    
    /**
     * Check if scan needs to resume from batch checkpoint
     * Returns status of batching progress
     * @since 2.1.1 
     */
    public function get_batch_resume_status() {
        $needs_resume = get_transient('vmpfence_scan_needs_resume');
        $processed_plugins = get_transient('vmpfence_processed_plugins');
        $processed_themes = get_transient('vmpfence_processed_themes');
        
        if (!$needs_resume && empty($processed_plugins) && empty($processed_themes)) {
            return array(
                'needs_resume' => false,
                'message' => 'No pending batches'
            );
        }
        
        $all_plugins = function_exists('get_plugins') ? get_plugins() : array();
        $all_themes = function_exists('wp_get_themes') ? wp_get_themes() : array();
        
        $remaining_plugins = count($all_plugins) - (is_array($processed_plugins) ? count($processed_plugins) : 0);
        $remaining_themes = count($all_themes) - (is_array($processed_themes) ? count($processed_themes) : 0);
        
        return array(
            'needs_resume' => true,
            'remaining_plugins' => $remaining_plugins,
            'remaining_themes' => $remaining_themes,
            'processed_plugins' => is_array($processed_plugins) ? count($processed_plugins) : 0,
            'processed_themes' => is_array($processed_themes) ? count($processed_themes) : 0,
            'total_plugins' => count($all_plugins),
            'total_themes' => count($all_themes),
            'message' => sprintf(
                'Resume needed: %d plugins and %d themes remaining',
                $remaining_plugins,
                $remaining_themes
            )
        );
    }
    
    /**
     * Scan WordPress core files for malware
     */
    private function scan_wordpress_core() {
        $issues = array();
        
        // Step 7: File integrity verification before malware scanning
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Starting WordPress core integrity verification...';
        $integrity_issues = $this->wp_integrity_checker->verify_core_files();
        $issues = array_merge($issues, $integrity_issues);
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Core integrity check complete. Found ' . count($integrity_issues) . ' integrity issues';
        
        // Continue with traditional malware scanning
        $wp_core_paths = array(
            ABSPATH . 'wp-admin/',
            ABSPATH . 'wp-includes/',
            ABSPATH . 'wp-config.php',
            ABSPATH . 'index.php'
        );
        
        foreach ($wp_core_paths as $path) {
            if (is_file($path)) {
                $file_issues = $this->scan_file($path, 'WordPress Core');
                $issues = array_merge($issues, $file_issues);
            } elseif (is_dir($path)) {
                $dir_issues = $this->scan_directory($path, 'WordPress Core');
                $issues = array_merge($issues, $dir_issues);
            }
        }
        
        return $issues;
    }
    
    /**
     * Scan plugins for malware with safe batching
     * CRITICAL FIX: Batches at plugin level (not directory level) to prevent timeout
     * @since 1.0.0
     * @since 2.1.1 Added batching and checkpointing logic
     */
    private function scan_plugins() {
        $issues = array();
        
        if (!function_exists('get_plugins')) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        
        // Step 7: Plugin integrity verification before malware scanning
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Starting plugin integrity verification...';
        $plugin_integrity_issues = $this->wp_integrity_checker->verify_plugin_files();
        $issues = array_merge($issues, $plugin_integrity_issues);
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Plugin integrity check complete. Found ' . count($plugin_integrity_issues) . ' integrity issues';
        
        // Continue with traditional malware scanning - scan ALL plugins
        if (!function_exists('get_plugins')) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        
        $all_plugins = get_plugins(); // Get all plugins (active + inactive + custom/premium)
        $active_plugins = get_option('active_plugins', array());
        $plugins_scanned = 0;
        
        // CRITICAL FIX: Safe batching - process plugins in batches of 5
        $batch_size = 5;
        $processed_plugins = get_transient('vmpfence_processed_plugins');
        // CRITICAL FIX: Type safety - ensure always array even if transient corrupted
        if (!is_array($processed_plugins)) {
            $processed_plugins = array();
        }
        
        $total_plugins = count($all_plugins);
        $remaining_plugins = $total_plugins - count($processed_plugins);
        
        $this->debug_log[] = sprintf(
            '[%s] Plugin batching: %d total plugins, %d already processed, %d remaining',
            current_time('H:i:s'),
            $total_plugins,
            count($processed_plugins),
            $remaining_plugins
        );
        
        $plugins_in_batch = 0;
        
        foreach (array_keys($all_plugins) as $plugin_file) {
            // Skip if already processed in previous batch
            if (in_array($plugin_file, $processed_plugins)) {
                continue;
            }
            
            // CRITICAL: Check if batch limit reached
            if ($plugins_in_batch >= $batch_size) {
                $this->debug_log[] = sprintf(
                    '[%s] Batch limit reached (%d plugins). Saving checkpoint for resume...',
                    current_time('H:i:s'),
                    $batch_size
                );
                // Save progress and signal need to resume
                // CRITICAL FIX: Use 6 hours TTL to prevent expiration during long scans
                set_transient('vmpfence_processed_plugins', $processed_plugins, 6 * HOUR_IN_SECONDS);
                set_transient('vmpfence_scan_needs_resume', true, 6 * HOUR_IN_SECONDS);
                break;
            }
            
            $plugin_dir = dirname($plugin_file);
            $status = in_array($plugin_file, $active_plugins) ? 'active' : 'inactive';
            
            if ($plugin_dir !== '.') {
                // Directory-based plugin
                $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_dir;
                if (is_dir($plugin_path)) {
                    $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanning plugin directory (' . $status . '): ' . $plugin_dir;
                    
                    // SAFE: scan_directory returns COMPLETE results for this plugin
                    $plugin_issues = $this->scan_directory($plugin_path, 'Plugin: ' . $plugin_dir . ' (' . $status . ')');
                    $issues = array_merge($issues, $plugin_issues);
                    $plugins_scanned++;
                    $plugins_in_batch++;
                    
                    // Mark as processed
                    $processed_plugins[] = $plugin_file;
                }
            } else {
                // Single-file plugin (like hello.php)
                $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_file;
                if (is_file($plugin_path)) {
                    $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanning single-file plugin (' . $status . '): ' . $plugin_file;
                    
                    // SAFE: scan_single_file returns COMPLETE results for this plugin
                    $plugin_issues = $this->scan_single_file($plugin_path, 'Plugin: ' . $plugin_file . ' (' . $status . ')');
                    $issues = array_merge($issues, $plugin_issues);
                    $plugins_scanned++;
                    $plugins_in_batch++;
                    
                    // Mark as processed
                    $processed_plugins[] = $plugin_file;
                }
            }
        }
        
        // Check if all plugins processed
        if (count($processed_plugins) >= $total_plugins) {
            $this->debug_log[] = sprintf(
                '[%s] All %d plugins processed. Clearing checkpoint.',
                current_time('H:i:s'),
                $total_plugins
            );
            delete_transient('vmpfence_processed_plugins');
            delete_transient('vmpfence_scan_needs_resume');
        } else {
            // Save progress for next batch
            // CRITICAL FIX: Use 6 hours TTL to prevent expiration during long scans
            set_transient('vmpfence_processed_plugins', $processed_plugins, 6 * HOUR_IN_SECONDS);
        }
        
        // NOTE: Statistics already set correctly by collect_wordpress_counts() at scan start
        // which counts ALL plugins. The $plugins_scanned variable tracks this batch only for logging.
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Batch complete: ' . $plugins_scanned . ' plugins scanned in this batch';
        
        return $issues;
    }
    
    /**
     * Scan a single file (for single-file plugins like hello.php)
     */
    private function scan_single_file($file_path, $context = '') {
        $issues = array();
        
        if (!file_exists($file_path)) {
            return $issues;
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanning single file: ' . $file_path;
        
        // Use the same scanning logic as directory scanning
        $file_issues = $this->scan_file($file_path, $context);
        $issues = array_merge($issues, $file_issues);
        
        return $issues;
    }
    
    /**
     * Scan ALL themes for malware (active + inactive) with safe batching
     * CRITICAL FIX: Batches at theme level (not directory level) to prevent timeout
     * @since 1.0.0
     * @since 2.1.1 Added batching and checkpointing logic
     */
    private function scan_themes() {
        $issues = array();
        $all_themes = wp_get_themes(); // Get all themes like file scanner
        $active_theme_slug = get_stylesheet();
        $themes_scanned = 0;
        
        // CRITICAL FIX: Safe batching - process themes in batches of 3 (themes are larger)
        $batch_size = 3;
        $processed_themes = get_transient('vmpfence_processed_themes');
        // CRITICAL FIX: Type safety - ensure always array even if transient corrupted
        if (!is_array($processed_themes)) {
            $processed_themes = array();
        }
        
        $total_themes = count($all_themes);
        $remaining_themes = $total_themes - count($processed_themes);
        
        $this->debug_log[] = sprintf(
            '[%s] Theme batching: %d total themes, %d already processed, %d remaining',
            current_time('H:i:s'),
            $total_themes,
            count($processed_themes),
            $remaining_themes
        );
        
        $themes_in_batch = 0;
        
        foreach ($all_themes as $theme_slug => $theme_obj) {
            // Skip if already processed in previous batch
            if (in_array($theme_slug, $processed_themes)) {
                continue;
            }
            
            // CRITICAL: Check if batch limit reached
            if ($themes_in_batch >= $batch_size) {
                $this->debug_log[] = sprintf(
                    '[%s] Batch limit reached (%d themes). Saving checkpoint for resume...',
                    current_time('H:i:s'),
                    $batch_size
                );
                // Save progress and signal need to resume
                // CRITICAL FIX: Use 6 hours TTL to prevent expiration during long scans
                set_transient('vmpfence_processed_themes', $processed_themes, 6 * HOUR_IN_SECONDS);
                set_transient('vmpfence_scan_needs_resume', true, 6 * HOUR_IN_SECONDS);
                break;
            }
            
            $theme_path = $theme_obj->get_template_directory();
            $status = ($theme_slug === $active_theme_slug) ? 'active' : 'inactive';
            
            if (is_dir($theme_path)) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanning theme (' . $status . '): ' . $theme_obj->get('Name');
                
                // SAFE: scan_directory returns COMPLETE results for this theme
                $theme_issues = $this->scan_directory($theme_path, 'Theme: ' . $theme_obj->get('Name') . ' (' . $status . ')');
                $issues = array_merge($issues, $theme_issues);
                $themes_scanned++;
                $themes_in_batch++;
                
                // Mark as processed
                $processed_themes[] = $theme_slug;
            }
        }
        
        // Check if all themes processed
        if (count($processed_themes) >= $total_themes) {
            $this->debug_log[] = sprintf(
                '[%s] All %d themes processed. Clearing checkpoint.',
                current_time('H:i:s'),
                $total_themes
            );
            delete_transient('vmpfence_processed_themes');
            delete_transient('vmpfence_scan_needs_resume');
        } else {
            // Save progress for next batch
            // CRITICAL FIX: Use 6 hours TTL to prevent expiration during long scans
            set_transient('vmpfence_processed_themes', $processed_themes, 6 * HOUR_IN_SECONDS);
        }
        
        // NOTE: Statistics already set correctly by collect_wordpress_counts() at scan start
        // which counts ALL themes. The $themes_scanned variable tracks this batch only for logging.
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Batch complete: ' . $themes_scanned . ' themes scanned, ' . count($issues) . ' issues found';
        
        return $issues;
    }
    
    /**
     * Scan uploads directory for suspicious PHP files
     */
    private function scan_uploads_directory() {
        $issues = array();
        $upload_dir = wp_upload_dir();
        $upload_path = $upload_dir['basedir'];
        
        if (is_dir($upload_path)) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Scanning uploads directory for PHP files...';
            // Only scan for PHP files in uploads (major security risk)
            $issues = $this->scan_directory($upload_path, 'Uploads Directory', array('php', 'phtml', 'php3', 'php4', 'php5'));
        }
        
        return $issues;
    }
    
    /**
     * Get memory limit in bytes
     * Handles various formats: 128M, 512M, 1G, -1 (unlimited)
     * @since 2.1.1
     */
    private function get_memory_limit_bytes() {
        $memory_limit = ini_get('memory_limit');
        
        if ($memory_limit === '-1') {
            // Unlimited - return large number for calculation purposes
            return 2147483648; // 2GB as reference
        }
        
        $memory_limit = trim($memory_limit);
        $last_char = strtolower($memory_limit[strlen($memory_limit) - 1]);
        $numeric_value = (int)$memory_limit;
        
        switch ($last_char) {
            case 'g':
                return $numeric_value * 1073741824; // GB to bytes
            case 'm':
                return $numeric_value * 1048576; // MB to bytes
            case 'k':
                return $numeric_value * 1024; // KB to bytes
            default:
                return $numeric_value; // Already in bytes
        }
    }
    
    /**
     * Recursively scan directory for malware
     * @since 1.0.0
     * @since 2.1.1 Added memory safety checks and detailed logging
     * @param string $directory Directory path to scan
     */
    private function scan_directory($directory, $location_context, $specific_extensions = null) {
        $issues = array();
        
        if (!is_readable($directory)) {
            return $issues;
        }
        
        // Initialize directory scan logging
        $total_files = 0;
        $scanned_files = 0;
        $skipped_files = 0;
        $subdirectories = array();
        $directory_files = array();
        
        // error_log("[VMPFence Scan] Starting directory scan: $directory ($location_context)");
        
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::SELF_FIRST
        );
        
        foreach ($iterator as $file) {
            if ($file->isFile()) {
                $total_files++;
                $file_path = $file->getPathname();
                $relative_dir = str_replace($directory, '', dirname($file_path));
                $relative_dir = trim($relative_dir, '/\\');
                
                if (empty($relative_dir)) {
                    $relative_dir = '[ROOT]';
                }
                
                if (!isset($directory_files[$relative_dir])) {
                    $directory_files[$relative_dir] = array();
                }
                $directory_files[$relative_dir][] = basename($file_path);
            }
        }
        
        // Log directory structure for summary only
        $total_dirs = count($directory_files);
        $total_files = array_sum(array_map('count', $directory_files));
        if ($total_dirs > 0) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Directory scan: ' . $total_dirs . ' subdirectories with ' . $total_files . ' total files';
        }
        
        // Second pass: actual scanning
        $iterator->rewind();
        foreach ($iterator as $file) {
            if ($file->isFile()) {
                $file_path = $file->getPathname();
                
                // Check if we should scan this file
                if ($this->should_scan_file($file_path, $specific_extensions)) {
                    // Increment counter FIRST so checks use correct count
                    $scanned_files++;
                    
                    // CRITICAL FIX: Memory safety checks every 50 files
                    // Check AFTER incrementing so count is accurate
                    if ($scanned_files % 50 === 0) {
                        $memory_limit = $this->get_memory_limit_bytes();
                        $memory_used = memory_get_usage(true);
                        $memory_percent = ($memory_limit > 0) ? ($memory_used / $memory_limit * 100) : 0;
                        
                        // If memory usage > 80%, log warning and consider pausing
                        if ($memory_percent > 80) {
                            $this->debug_log[] = sprintf(
                                '[%s] HIGH MEMORY WARNING: %.1f%% used (%.2fMB / %.2fMB) at file %d in %s',
                                current_time('H:i:s'),
                                $memory_percent,
                                $memory_used / 1024 / 1024,
                                $memory_limit / 1024 / 1024,
                                $scanned_files,
                                basename($directory)
                            );
                            
                            // Force garbage collection to free memory
                            if (function_exists('gc_collect_cycles')) {
                                gc_collect_cycles();
                            }
                            
                            // Recheck after GC
                            $memory_used_after = memory_get_usage(true);
                            $memory_freed = $memory_used - $memory_used_after;
                            if ($memory_freed > 0) {
                                $this->debug_log[] = sprintf(
                                    '[%s] Garbage collection freed %.2fMB',
                                    current_time('H:i:s'),
                                    $memory_freed / 1024 / 1024
                                );
                            }
                        }
                    }
                    
                    // CRITICAL FIX: Run garbage collection every 100 files to prevent memory leaks
                    if ($scanned_files % 100 === 0) {
                        if (function_exists('gc_collect_cycles')) {
                            $collected = gc_collect_cycles();
                            if ($collected > 0) {
                                $this->debug_log[] = sprintf(
                                    '[%s] Garbage collection: %d cycles freed at file %d',
                                    current_time('H:i:s'),
                                    $collected,
                                    $scanned_files
                                );
                            }
                        }
                    }
                    
                    $file_issues = $this->scan_file($file_path, $location_context);
                    $issues = array_merge($issues, $file_issues);
                } else {
                    $skipped_files++;
                }
            }
        }
        
        // Log directory scan summary to debug log instead of error log
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Directory scan complete: ' . basename($directory) . " ($location_context) - Scanned: $scanned_files, Skipped: $skipped_files, Issues: " . count($issues);
        
        return $issues;
    }
    
    /**
     * Determine if file should be scanned using enhanced file type detection
     * Step 12: Replaces basic extension checking with advanced file analysis
     */
    private function should_scan_file($file_path, $specific_extensions = null) {
        // Step 12: Use advanced file type detection instead of basic extension checking
        $file_analysis = $this->should_scan_file_advanced($file_path);
        
        // Log detailed analysis for this file
        $relative_path = str_replace(ABSPATH, '', $file_path);
        

        
        // Check excluded directories
        foreach ($this->excluded_directories as $excluded_dir) {
            if (strpos($file_path, $excluded_dir) !== false) {
                // Only log PHP files that are excluded
                $extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
                if (in_array($extension, ['php', 'phtml', 'php3', 'php4', 'php5', 'php7', 'phps'])) {
                    // error_log("[VMPFence Scan] PHP file excluded by directory rule: $relative_path (excluded dir: $excluded_dir)");
                }
                return false;
            }
        }
        
        // Check file size (skip very large files > 10MB for performance)
        $file_size = filesize($file_path);
        if ($file_size > 10485760) {
            // Only log PHP files that are excluded by size
            $extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
            if (in_array($extension, ['php', 'phtml', 'php3', 'php4', 'php5', 'php7', 'phps'])) {
                // error_log("[VMPFence Scan] PHP file excluded by size rule: $relative_path (size: " . round($file_size/1024/1024, 2) . "MB > 10MB limit)");
            }
            return false;
        }
        
        // If specific extensions are provided, use them
        if ($specific_extensions !== null) {
            $extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
            if (!in_array($extension, $specific_extensions)) {
                // Only log if it's a PHP file being excluded (since we care about PHP scanning)
                // if (in_array($extension, ['php', 'phtml', 'php3', 'php4', 'php5', 'php7', 'phps'])) {
                //     error_log("[VMPFence Scan] PHP file excluded by extension rule: $relative_path (extension: .$extension not in allowed: " . implode(', ', $specific_extensions) . ")");
                // }
                return false;
            } else {
                // Only log when file is rejected, not when it matches
                // error_log("[VMPFence Scan] File matches extension rule: $relative_path (extension: .$extension is in allowed: " . implode(', ', $specific_extensions) . ")");
            }
        }
        
        // Log the advanced analysis result
        $should_scan = $file_analysis['should_scan'];
        $scan_reasons = isset($file_analysis['scan_reasons']) ? implode(', ', $file_analysis['scan_reasons']) : 'No reasons provided';
        
        if ($should_scan) {
            // Only log rejected files, not approved ones
            // error_log("[VMPFence Scan] File APPROVED for scanning: $relative_path (reasons: $scan_reasons)");
        } else {
            // Only log PHP files that are rejected by advanced analysis
            $extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
            if (in_array($extension, ['php', 'phtml', 'php3', 'php4', 'php5', 'php7', 'phps'])) {
                // error_log("[VMPFence Scan] PHP file REJECTED by advanced analysis: $relative_path (reasons: $scan_reasons)");
            }
        }
        
        // Return based on advanced file type analysis
        return $should_scan;
    }
    
    /**
     * Scan individual file for malware patterns
     * @since 1.0.0
     * @since 2.1.1 Added per-file timeout and memory-efficient file handling
     * @param string $file_path Full file path to scan
     */
    private function scan_file($file_path, $location_context) {
        $issues = array();
        $this->total_files_scanned++;
        
        // Step 8: Track file processing start time for metrics
        $file_start_time = microtime(true);
        
        // CRITICAL FIX: Per-file timeout protection (30 seconds max per file)
        $file_timeout = 30;
        
        try {
            // Step 8: Update progress tracker with current file
            $this->progress_tracker->update_progress($file_path, $this->total_files_scanned);
            
            // Step 4: Use advanced file handler for memory-efficient file processing
            if (!$this->advanced_file_handler->can_process_file($file_path)) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Skipping file (cannot process): ' . basename($file_path);
                
                // Step 8: Track skipped file metrics (early return bypasses final tracking)
                $file_processing_time = microtime(true) - $file_start_time;
                $this->scan_metrics->update_file_progress($file_path, $file_processing_time, 'skipped');
                
                return $issues;
            }
            
            // Step 4: Handle files using advanced file handler with memory management
            $file_result = $this->advanced_file_handler->handle_large_files($file_path);
            
            if ($file_result === false) {
                // Track failed file processing
                $file_processing_time = microtime(true) - $file_start_time;
                $this->scan_metrics->update_file_progress($file_path, $file_processing_time, 'skipped');
                return $issues;
            }
            
            // Extract file content from handler result
            $file_content = '';
            if (isset($file_result['content'])) {
                $file_content = $file_result['content'];
            } elseif (isset($file_result['content_samples'])) {
                // For large files processed with samples, combine samples
                foreach ($file_result['content_samples'] as $sample) {
                    $file_content .= $sample . "\n";
                }
            }
            
            if (empty($file_content)) {
                // Track empty file
                $file_processing_time = microtime(true) - $file_start_time;
                $this->scan_metrics->update_file_progress($file_path, $file_processing_time, 'skipped');
                return $issues;
            }
            
            // Step 4: Monitor memory usage during file processing
            $memory_stats = $this->advanced_file_handler->monitor_memory_usage();
            
            // Log file processing method for debugging
            if (isset($file_result['method']) && isset($file_result['size']) && $file_result['size'] > 1024 * 1024) {
                $this->debug_log[] = sprintf(
                    '[%s] Large file processed using %s method: %s (%.2fMB, Memory: %.1f%%)',
                    current_time('H:i:s'),
                    $file_result['method'],
                    basename($file_path),
                    $file_result['size'] / 1024 / 1024,
                    $memory_stats['percentage']
                );
            }
            
            // STEP 2: Binary malware prefix detection (ultra-fast 4-byte signatures)
            // Only run if scansEnabled_malware is enabled
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_malware']) || $this->scan_options['scansEnabled_malware']) {
                // Check timeout before continuing
                if ((microtime(true) - $file_start_time) > $file_timeout) {
                    $this->debug_log[] = sprintf(
                        '[%s] File scan timeout after %.1fs: %s',
                        current_time('H:i:s'),
                        microtime(true) - $file_start_time,
                        basename($file_path)
                    );
                    return $issues; // Return what we have so far
                }
                
                // Check if this is high sensitivity mode for webshell detection
                $is_high_sensitivity = $this->is_high_sensitivity_scan();
                $binary_result = $this->check_binary_patterns($file_path, $file_content, $is_high_sensitivity);
                if (!empty($binary_result)) {
                    $issues = array_merge($issues, $binary_result);
                }
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Binary malware signature scanning disabled for: ' . basename($file_path);
            }
            
            // STEP 3: Badstrings detection for suspicious string combinations
            // Only run if scansEnabled_fileContents is enabled
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_fileContents']) || $this->scan_options['scansEnabled_fileContents']) {
                // Check timeout before continuing
                if ((microtime(true) - $file_start_time) > $file_timeout) {
                    $this->debug_log[] = sprintf(
                        '[%s] File scan timeout after %.1fs (badstrings stage): %s',
                        current_time('H:i:s'),
                        microtime(true) - $file_start_time,
                        basename($file_path)
                    );
                    return $issues;
                }
                
                $badstrings_result = $this->check_badstrings_patterns($file_path, $file_content, $location_context);
                if (!empty($badstrings_result)) {
                    $issues = array_merge($issues, $badstrings_result);
                }
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] File contents scanning (badstrings) disabled for: ' . basename($file_path);
            }
            
            // STEP 5: High sensitivity mode scanning (obfuscation, context analysis, base64 detection)
            // Only run if scansEnabled_fileContents is enabled
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_fileContents']) || $this->scan_options['scansEnabled_fileContents']) {
                // Check timeout before continuing
                if ((microtime(true) - $file_start_time) > $file_timeout) {
                    $this->debug_log[] = sprintf(
                        '[%s] File scan timeout after %.1fs (high sensitivity stage): %s',
                        current_time('H:i:s'),
                        microtime(true) - $file_start_time,
                        basename($file_path)
                    );
                    return $issues;
                }
                
                $this->scan_with_high_sensitivity($file_path, $file_content, $issues);
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] High sensitivity scanning disabled for: ' . basename($file_path);
            }
            
            // STEP 5: Binary file scanning (images, PDFs, archives, executables)
            // Only run if scansEnabled_scanImages is enabled
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_scanImages']) || $this->scan_options['scansEnabled_scanImages']) {
                $this->scan_binary_file($file_path, $issues);
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Binary/image file scanning disabled for: ' . basename($file_path);
            }
            
            // Step 12: Get enhanced file type analysis and type-specific patterns
            $file_analysis = $this->should_scan_file_advanced($file_path);
            $type_specific_patterns = $this->get_type_specific_patterns($file_path, $file_content, $file_analysis);
            
            // Log enhanced file type information for debugging
            if (!empty($type_specific_patterns)) {
                $this->debug_log[] = sprintf(
                    '[%s] File type detected as %s with %d type-specific patterns: %s',
                    current_time('H:i:s'),
                    $file_analysis['type_description'],
                    count($type_specific_patterns),
                    basename($file_path)
                );
            }
            
            // Enhanced pattern matching with common strings pre-filtering and advanced rule structure
            // Initialize pattern counters
            $patterns_processed = 0;
            $patterns_skipped = 0;
            
            // Only run if scansEnabled_malware is enabled
            if (!$this->scan_options || !isset($this->scan_options['scansEnabled_malware']) || $this->scan_options['scansEnabled_malware']) {
                // Check timeout before pattern matching (most CPU-intensive stage)
                if ((microtime(true) - $file_start_time) > $file_timeout) {
                    $this->debug_log[] = sprintf(
                        '[%s] File scan timeout after %.1fs (before pattern matching): %s',
                        current_time('H:i:s'),
                        microtime(true) - $file_start_time,
                        basename($file_path)
                    );
                    return $issues;
                }
                
                // Step 12: First process type-specific patterns with higher priority
                $all_patterns = array_merge($type_specific_patterns, $this->malware_patterns);
                
                // Get file extension for filtering
                $file_extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
                $is_documentation_file = in_array($file_extension, ['txt', 'md', 'readme', 'log', 'rst', 'doc']);
                
                foreach ($all_patterns as $pattern_info) {
                // Skip code-based patterns for documentation files
                if ($is_documentation_file && isset($pattern_info['category'])) {
                    $code_based_categories = ['php_obfuscation', 'backdoors', 'upload_exploits', 'webshells', 'code_injection'];
                    if (in_array($pattern_info['category'], $code_based_categories)) {
                        $patterns_skipped++;
                        $this->debug_log[] = '[' . current_time('H:i:s') . '] Skipping code pattern "' . $pattern_info['rule_id'] . '" for documentation file: ' . basename($file_path);
                        continue;
                    }
                }
                
                // Get common string indexes for this pattern
                $common_string_indexes = isset($pattern_info['common_string_indexes']) ? $pattern_info['common_string_indexes'] : array();
                
                // Use common strings optimizer for pre-filtering (90% performance boost)
                if (!empty($common_string_indexes)) {
                    if (!$this->common_strings_optimizer->prefilter_before_regex($file_content, $common_string_indexes)) {
                        // Skip expensive regex - required common strings not found
                        $patterns_skipped++;
                        continue;
                    }
                }
                
                $patterns_processed++;
                
                // Apply regex pattern (only if pre-filter passed)
                $pattern_regex = isset($pattern_info['pattern']) ? $pattern_info['pattern'] : $pattern_info['regex_pattern'];
                
                // Debug custom signatures
                // if (isset($pattern_info['rule_id']) && strpos($pattern_info['rule_id'], 'user_custom_') === 0) {
                //     error_log('VMPFence Custom: Testing pattern "' . $pattern_regex . '" against file: ' . basename($file_path));
                //     error_log('VMPFence Custom: File content preview: "' . substr($file_content, 0, 200) . '"');
                // }
                
                // Handle pattern matching - custom patterns may already have delimiters
                $match_result = false;
                if (isset($pattern_info['rule_id']) && strpos($pattern_info['rule_id'], 'user_custom_') === 0) {
                    // For custom patterns, check if they already have delimiters (from pattern optimizer)
                    if (preg_match('/^[^a-zA-Z0-9\\\\\x00].*[^a-zA-Z0-9\\\\\x00][imsxuAJD]*$/', $pattern_regex)) {
                        // Pattern already has delimiters (e.g., ~pattern~i), use directly
                        // error_log('VMPFence Custom: Using pattern with existing delimiters: ' . $pattern_regex);
                        $match_result = @preg_match($pattern_regex, $file_content, $matches);
                        if ($match_result === false) {
                            // error_log('VMPFence Custom: Pattern regex error: ' . (preg_last_error_msg() ?? 'Unknown error'));
                        }
                    } else {
                        // Pattern needs delimiters
                        // error_log('VMPFence Custom: Adding # delimiters to pattern: #' . $pattern_regex . '#i');
                        $match_result = @preg_match('#' . $pattern_regex . '#i', $file_content, $matches);
                    }
                } else {
                    // Built-in patterns need # delimiters
                    $match_result = @preg_match('#' . $pattern_regex . '#i', $file_content, $matches);
                }
                
                if ($match_result) {
                    
                    // Log custom signature matches
                    // if (isset($pattern_info['rule_id']) && strpos($pattern_info['rule_id'], 'user_custom_') === 0) {
                    //     error_log('VMPFence Custom: MATCH FOUND! Pattern "' . $pattern_regex . '" matched in ' . $file_path);
                    //     error_log('VMPFence Custom: Match content: "' . substr($matches[0], 0, 100) . '"');
                    // }
                    
                    // STEP 6: Check exclusions before flagging as malware (False positive filtering)
                    $exclusion_result = $this->exclusion_system->check_exclusions(
                        $file_path, 
                        $file_content, 
                        $pattern_info['rule_id'] ?? $pattern_info['id']
                    );
                    
                    if ($exclusion_result['should_exclude']) {
                        // File/pattern excluded - log but don't flag as malware
                        $this->debug_log[] = '[' . current_time('H:i:s') . '] EXCLUDED: ' . 
                            ($pattern_info['rule_id'] ?? $pattern_info['id']) . ' in ' . 
                            basename($file_path) . ' - Reason: ' . $exclusion_result['reason'];
                        
                        if (isset($pattern_info['rule_id']) && strpos($pattern_info['rule_id'], 'user_custom_') === 0) {
                            // error_log('VMPFence Custom: Match EXCLUDED - Reason: ' . $exclusion_result['reason']);
                        }
                        continue; // Skip creating malware issue
                    }
                    
                    // Log that we're proceeding to create the issue
                    // if (isset($pattern_info['rule_id']) && strpos($pattern_info['rule_id'], 'user_custom_') === 0) {
                    //     error_log('VMPFence Custom: Creating malware issue for match...');
                    // }
                    
                    // Step 11: Use enhanced issue creation with detailed metadata generation
                    $match_position = strpos($file_content, $matches[0]);
                    $line_info = $this->get_line_number_and_context($file_content, $match_position, $matches[0]);
                    
                    $match_info = [
                        'pattern' => $pattern_regex,
                        'position' => $match_position,
                        'line_number' => $line_info['line_number'],
                        'line_content' => $line_info['line_content'],
                        'highlighted_line' => $line_info['highlighted_line'],
                        'context_lines' => $line_info['context_lines'],
                        'matches' => $matches,
                        'count' => 1,
                        'method' => 'regex'
                    ];
                    
                    // Generate comprehensive metadata using issue manager
                    $issue_metadata = $this->issue_manager->generate_issue_metadata(
                        $file_content,
                        $file_path,
                        $pattern_info['rule_id'] ?? $pattern_info['id'],
                        $match_info
                    );
                    
                    // Classify severity and type using advanced classification
                    $classified_severity = $this->issue_manager->classify_issue_severity($file_content, $file_path, $match_info);
                    $classified_type = $this->issue_manager->classify_issue_type($file_content, $pattern_info['rule_id'] ?? $pattern_info['id']);
                    
                    // Extract code context around the match
                    $code_context = $this->issue_manager->extract_code_context($file_content, $match_info['position'], 5);
                    
                    // Create enhanced issue with comprehensive metadata (Step 11)
                    
                    // For custom signatures, create a detailed description
                    $issue_description = $pattern_info['description'];
                    $filename = basename($file_path);
                    
                    // Set title and description based on pattern type
                    if (isset($pattern_info['rule_id']) && strpos($pattern_info['rule_id'], 'user_custom_') === 0) {
                        // Custom signature format
                        $clean_pattern = $matches[0]; // Use the actual matched text instead of the regex
                        $issue_title = 'Malware Pattern Detected.';
                        $issue_description = 'Custom malware signature "' . $clean_pattern . '" detected in the content in file ' . $filename . ' at line ' . $line_info['line_number'];
                    } else {
                        // Built-in pattern format
                        $issue_title = 'Malware Pattern Detected. ' . ucfirst($pattern_info['issue_type'] ?? $pattern_info['type'] ?? 'unknown') . ' (Line ' . $line_info['line_number'] . ')';
                        $issue_description = $pattern_info['description'];
                    }
                    
                    $enhanced_issue = array(
                        // Basic issue information (legacy compatibility)
                        'type' => 'malware_detected',
                        'severity' => $classified_severity,
                        'title' => $issue_title,
                        'description' => $issue_description,
                        'location' => str_replace(ABSPATH, '', $file_path),
                        'details' => 'Malware Pattern Detected ' . ($pattern_info['rule_id'] ?? $pattern_info['id']) . ' (Line ' . $line_info['line_number'] . '): ' . ($pattern_info['rule_id'] ?? $pattern_info['id']) . ' | File: ' . $filename . ' | Line: ' . $line_info['line_number'] . ' | Pattern: ' . ($pattern_info['category'] ?? 'unknown') . ' | Match: ' . substr($matches[0], 0, 100),
                        'context' => $location_context,
                        'pattern_id' => $pattern_info['rule_id'] ?? $pattern_info['id'],
                        'pattern_category' => $pattern_info['category'] ?? 'unknown',
                        'matched_code' => substr($matches[0], 0, 200),
                        'line_number' => $line_info['line_number'],
                        'line_content' => $line_info['line_content'],
                        'highlighted_line' => $line_info['highlighted_line'],
                        'context_lines' => $line_info['context_lines'],
                        'custom_message' => $pattern_info['custom_message'] ?? $pattern_info['description'],
                        'scan_type' => $pattern_info['scan_type'] ?? 'file_content',
                        'log_only' => $pattern_info['log_only'] ?? false,
                        'recommendation' => 'Review this file immediately and remove malicious code if confirmed. Pattern detected: ' . ($pattern_info['rule_id'] ?? $pattern_info['id']) . ' at line ' . $line_info['line_number'],
                        
                        // Step 11: Enhanced metadata from issue manager
                        'issue_classification' => $classified_type,
                        'classified_severity' => $classified_severity,
                        'code_context' => $code_context,
                        'comprehensive_metadata' => $issue_metadata,
                        'threat_indicators' => $issue_metadata['threat_indicators'],
                        'risk_assessment' => $issue_metadata['risk_assessment'],
                        'remediation_suggestions' => $issue_metadata['remediation_suggestions'],
                        'confidence_score' => $issue_metadata['confidence_score'],
                        'false_positive_indicators' => $issue_metadata['false_positive_indicators'],
                        'file_info' => $issue_metadata['file_info'],
                        'code_analysis' => $issue_metadata['code_analysis'],
                        'similar_patterns' => $issue_metadata['similar_patterns'],
                        'pattern_metadata' => $issue_metadata['pattern_metadata'] ?? [],
                        
                        // Detailed reporting
                        'detailed_analysis' => [
                            'entropy_score' => $issue_metadata['code_analysis']['entropy_score'],
                            'obfuscation_level' => $issue_metadata['code_analysis']['obfuscation_level'],
                            'file_location_risk' => $this->assess_file_location_risk($file_path),
                            'pattern_specificity' => $this->calculate_pattern_specificity($pattern_info),
                            'temporal_analysis' => [
                                'file_modified' => $issue_metadata['file_info']['modified'] ?? 'unknown',
                                'detection_timestamp' => $issue_metadata['timestamp']
                            ]
                        ]
                    );
                    
                    // Add the enhanced issue to the issues array
                    $issues[] = $enhanced_issue;
                    
                    // Debug custom signature issue creation
                    // if (isset($pattern_info['rule_id']) && strpos($pattern_info['rule_id'], 'user_custom_') === 0) {
                    //     error_log('VMPFence Custom: Issue created and added to results! Title: ' . $enhanced_issue['title']);
                    // }
                    
                    $this->debug_log[] = '[' . current_time('H:i:s') . '] ENHANCED MALWARE DETECTION: ' . ($pattern_info['rule_id'] ?? $pattern_info['id']) . ' (' . $classified_type . '/' . $classified_severity . ') in ' . basename($file_path) . ' - Confidence: ' . number_format($issue_metadata['confidence_score'], 1) . '%';
                }
            }
            
                // Log performance metrics for common strings optimization
                if ($patterns_processed + $patterns_skipped > 0) {
                    $skip_percentage = ($patterns_skipped / ($patterns_processed + $patterns_skipped)) * 100;
                    $this->debug_log[] = sprintf(
                        '[%s] Performance: %d patterns processed, %d skipped (%.1f%% skip rate) for %s',
                        current_time('H:i:s'),
                        $patterns_processed,
                        $patterns_skipped, 
                        $skip_percentage,
                        basename($file_path)
                    );
                }
            } else {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Malware pattern scanning disabled for: ' . basename($file_path);
            } // End scansEnabled_malware check
            
        } catch (Exception $e) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Error scanning file ' . basename($file_path) . ': ' . $e->getMessage();
            
            // Step 8: Track error metrics
            $file_processing_time = microtime(true) - $file_start_time;
            $this->scan_metrics->update_file_progress($file_path, $file_processing_time, 'error');
            
            // CRITICAL: Return empty issues array to prevent null return breaking array_merge()
            return array();
        }
        
        // Step 8: Track file processing completion with metrics
        $file_processing_time = microtime(true) - $file_start_time;
        $result = 'clean';
        if (!empty($issues)) {
            $result = 'threat_detected';
        }
        $this->scan_metrics->update_file_progress($file_path, $file_processing_time, $result);
        
        return $issues;
    }
    
    /**
     * Check if this is a high sensitivity scan
     */
    private function is_high_sensitivity_scan() {
        return ($this->scan_options && isset($this->scan_options['scan_type']) && 
                (is_array($this->scan_options['scan_type']) && in_array('high_sensitivity', $this->scan_options['scan_type']) ||
                 $this->scan_options['scan_type'] === 'high_sensitivity'));
    }

    /**
     * Check file for binary malware patterns using ultra-fast 4-byte prefix detection
     * Implements Step 2: Binary Malware Prefix Detection System
     */
    private function check_binary_patterns($file_path, $file_content, $is_high_sensitivity = false) {
        $issues = array();
        
        try {
            // Use binary detector for ultra-fast detection
            $binary_result = $this->binary_detector->check_binary_signatures($file_path, $file_content);
            
            if ($binary_result['detected']) {
                $this->debug_log[] = sprintf('[%s] Binary malware detected in %s: %d signatures', 
                    current_time('H:i:s'), basename($file_path), count($binary_result['detections']));
                
                foreach ($binary_result['detections'] as $detection) {
                    //  Filter webshell detections unless high sensitivity mode
                    if ($detection['type'] === 'WEBSHELL' && !$is_high_sensitivity) {
                        $this->debug_log[] = sprintf('[%s] Skipping WEBSHELL detection (not high sensitivity): %s', 
                            current_time('H:i:s'), basename($file_path));
                        continue;
                    }
                    
                    $issues[] = array(
                        'file' => $file_path,
                        'line' => $this->get_line_number_from_position($file_content, $detection['position']),
                        'issue_type' => 'malware',
                        'severity' => $this->map_binary_severity($detection['severity']),
                        'pattern' => 'binary_prefix_' . $detection['prefix'],
                        'title' => 'Binary Malware Signature', // Add missing title field
                        'context' => $this->extract_context_around_position($file_content, $detection['position'], 3),
                        'description' => sprintf('Binary malware signature detected: %s (%s confidence)', 
                            $detection['type'], $detection['confidence']) . 
                            ($detection['type'] === 'WEBSHELL' && $is_high_sensitivity ? 
                             ' This file was detected because you have enabled HIGH SENSITIVITY scanning. This option is more aggressive and may cause false positives.' : ''),
                        'location' => $this->get_scan_location($file_path),
                        'timestamp' => current_time('mysql'),
                        'detection_method' => 'binary_prefix',
                        'binary_info' => array(
                            'prefix' => $detection['prefix'],
                            'position' => $detection['position'],
                            'type' => $detection['type'],
                            'confidence' => $detection['confidence']
                        )
                    );
                }
            }
            
        } catch (Exception $e) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Binary detection error in ' . basename($file_path) . ': ' . $e->getMessage();
        }
        
        return $issues;
    }
    
    /**
     * Map binary severity levels to VMPFence severity
     */
    private function map_binary_severity($binary_severity) {
        switch ($binary_severity) {
            case 5: return 'Critical';
            case 4: return 'High';
            case 3: return 'Medium';
            case 2: return 'Low';
            case 1: return 'Info';
            default: return 'Medium';
        }
    }
    
    /**
     * Get line number from byte position in file content
     */
    private function get_line_number_from_position($content, $position) {
        if ($position <= 0) return 1;
        
        $before_position = substr($content, 0, $position);
        return substr_count($before_position, "\n") + 1;
    }
    
    /**
     * Extract context around a specific position
     */
    private function extract_context_around_position($content, $position, $lines_context = 3) {
        $lines = explode("\n", $content);
        $line_number = $this->get_line_number_from_position($content, $position) - 1; // 0-based
        
        $start_line = max(0, $line_number - $lines_context);
        $end_line = min(count($lines) - 1, $line_number + $lines_context);
        
        $context_lines = array();
        for ($i = $start_line; $i <= $end_line; $i++) {
            $prefix = ($i == $line_number) ? '>>> ' : '    ';
            $context_lines[] = $prefix . ($i + 1) . ': ' . (isset($lines[$i]) ? $lines[$i] : '');
        }
        
        return implode("\n", $context_lines);
    }
    
    /**
     * Check file for badstrings patterns and suspicious combinations
     * Implements Step 3: Badstrings Detection System
     */
    private function check_badstrings_patterns($file_path, $file_content, $location_context) {
        $issues = array();
        
        try {
            // Use badstrings detector for suspicious string combinations
            $badstrings_result = $this->badstrings_detector->detect_eval_badstring_combinations($file_content, $file_path);
            
            if (!empty($badstrings_result)) {
                $this->debug_log[] = sprintf('[%s] Badstrings detected in %s: %d combinations', 
                    current_time('H:i:s'), basename($file_path), count($badstrings_result));
                
                // Convert badstrings detections to VMPFence issues format
                foreach ($badstrings_result as $detection) {
                    $issues[] = array(
                        'type' => 'malware_detected',
                        'file' => $file_path,
                        'line' => isset($detection['position']) ? $this->get_line_number_from_position($file_content, $detection['position']) : 1,
                        'issue_type' => 'badstrings_' . $detection['type'],
                        'severity' => $this->map_badstrings_severity($detection['risk_level']),
                        'pattern' => 'badstrings_' . $detection['type'],
                        'title' => 'Suspicious Code Pattern: ' . ucfirst(str_replace('_', ' ', $detection['type'])),
                        'context' => isset($detection['context']) ? $detection['context'] : $location_context,
                        'description' => $this->generate_badstrings_description($detection),
                        'location' => $this->get_scan_location($file_path),
                        'timestamp' => current_time('mysql'),
                        'detection_method' => 'badstrings',
                        'badstrings_info' => $detection,
                        'recommendation' => $this->generate_badstrings_recommendation($detection),
                        'matched_code' => isset($detection['pattern']) ? substr($detection['pattern'], 0, 200) : (isset($detection['context']) ? substr($detection['context'], 0, 200) : 'N/A')
                    );
                }
                
                // Log badstrings performance statistics
                $stats = $this->badstrings_detector->get_performance_stats();
                $this->debug_log[] = sprintf('[%s] Badstrings performance: %d files analyzed, %d combinations found, %d false positives filtered', 
                    current_time('H:i:s'), $stats['files_analyzed'], $stats['badstring_combinations_found'], $stats['false_positives_filtered']);
            }
            
        } catch (Exception $e) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Badstrings detection error in ' . basename($file_path) . ': ' . $e->getMessage();
        }
        
        return $issues;
    }
    
    /**
     * Map badstrings risk levels to VMPFence severity
     */
    private function map_badstrings_severity($risk_level) {
        switch ($risk_level) {
            case 'high': return 'High';
            case 'medium': return 'Medium';
            case 'low': return 'Low';
            default: return 'Medium';
        }
    }
    
    /**
     * Generate human-readable description for badstrings detection
     */
    private function generate_badstrings_description($detection) {
        switch ($detection['type']) {
            case 'eval_encoding_combination':
                return sprintf('Suspicious combination of eval() with %s encoding detected. This pattern often indicates obfuscated malware attempting to hide its true purpose.', 
                    ucfirst($detection['encoding_type']));
                
            case 'multiple_encoding_layers':
                return sprintf('Multiple encoding functions detected in close proximity (%s). This layered obfuscation is commonly used by malware to evade detection.', 
                    implode(', ', $detection['functions']));
                
            case 'obfuscated_variable_eval':
                return 'Obfuscated variable names combined with eval() function detected. This technique is frequently used to hide malicious code execution.';
                
            case 'concatenated_function_name':
                return sprintf('Function name concatenation detected: "%s" formed from parts. This obfuscation technique is used to bypass simple string-based detection.', 
                    $detection['function']);
                
            case 'badstring_function_cluster':
                return sprintf('Cluster of suspicious functions from category "%s" detected: %s. High concentration of risky functions indicates potential malware.', 
                    $detection['category'], implode(', ', array_keys($detection['function_counts'])));
                
            default:
                return 'Suspicious string pattern combination detected that matches known malware behavior.';
        }
    }
    
    /**
     * Generate specific recommendations for badstrings detections
     */
    private function generate_badstrings_recommendation($detection) {
        switch ($detection['type']) {
            case 'eval_encoding_combination':
                return 'IMMEDIATE ACTION REQUIRED: This is a strong indicator of malware. Review the encoded content carefully and remove if malicious. Consider using WordPress security plugins for additional protection.';
                
            case 'multiple_encoding_layers':
                return 'HIGH PRIORITY: Multiple encoding layers are rarely used in legitimate code. Decode the content layer by layer to understand its purpose and remove if malicious.';
                
            case 'obfuscated_variable_eval':
                return 'CRITICAL: Obfuscated eval() usage is almost always malicious. This file should be quarantined immediately and replaced with a clean version.';
                
            case 'concatenated_function_name':
                return 'REVIEW REQUIRED: Function name obfuscation may indicate an attempt to hide malicious functionality. Verify this is legitimate code for your application.';
                
            case 'badstring_function_cluster':
                return 'INVESTIGATE: High concentration of risky functions requires investigation. Ensure these functions are necessary for legitimate functionality and not part of a backdoor.';
                
            default:
                return 'Review this pattern carefully. If you did not intentionally add complex code patterns to this file, it may be compromised.';
        }
    }
    
    /**
     * Get scan location context for a file path
     */
    private function get_scan_location($file_path) {
        $wp_path = ABSPATH;
        
        if (strpos($file_path, $wp_path . 'wp-admin/') === 0) {
            return 'WordPress Admin';
        } elseif (strpos($file_path, $wp_path . 'wp-includes/') === 0) {
            return 'WordPress Core';
        } elseif (strpos($file_path, $wp_path . 'wp-content/plugins/') === 0) {
            // Extract plugin name
            $plugin_path = str_replace($wp_path . 'wp-content/plugins/', '', $file_path);
            $plugin_name = explode('/', $plugin_path)[0];
            return 'Plugin: ' . $plugin_name;
        } elseif (strpos($file_path, $wp_path . 'wp-content/themes/') === 0) {
            // Extract theme name
            $theme_path = str_replace($wp_path . 'wp-content/themes/', '', $file_path);
            $theme_name = explode('/', $theme_path)[0];
            return 'Theme: ' . $theme_name;
        } elseif (strpos($file_path, $wp_path . 'wp-content/uploads/') === 0) {
            return 'Uploads Directory';
        } elseif (strpos($file_path, $wp_path . 'wp-content/') === 0) {
            return 'WordPress Content';
        } else {
            return 'WordPress Root';
        }
    }
    
    /**
     * Clear previous malware scan data
     */
    private function clear_previous_scan_data() {
        global $wpdb;
        
        // Clear previous scan issues from new table structure
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table names from WordPress prefix
        $issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        
        $deleted_issues = $wpdb->query($wpdb->prepare(
            "DELETE FROM {$issues_table} WHERE issue_type = %s AND status != 'ignored'", 'malware'
        ));
        
        // Clear previous scan results
        $results_table = $wpdb->prefix . 'vmpfence_scan_results';
        $deleted_results = $wpdb->query($wpdb->prepare(
            "DELETE FROM {$results_table} WHERE scan_type = %s", 'malware'
        ));
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Cleared previous malware scan data from both issues and results tables';
    }
    
    /**
     * Save malware scan results to database
     */
    private function save_scan_results($issues) {
        global $wpdb;
        
        // Save scan summary to scan_results table
        $scan_results_table = $wpdb->prefix . 'vmpfence_scan_results';
        $scan_result_id = $wpdb->insert(
            $scan_results_table,
            array(
                'scan_type' => 'malware',
                'scan_time' => current_time('mysql'),
                'total_files' => $this->total_files_scanned,
                'issues_found' => count($issues),
                'scan_status' => 'completed',
                'scan_data' => wp_json_encode(array(
                    'patterns_used' => count($this->malware_patterns),
                    'directories_scanned' => array('core', 'plugins', 'themes', 'uploads'),
                    'file_types_supported' => $this->file_type_handler->get_supported_types(),
                    'legacy_extensions' => $this->legacy_scannable_extensions
                ))
            )
        );
        
        if ($scan_result_id === false) {
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Error saving malware scan summary: ' . $wpdb->last_error;
            return;
        }
        
        $scan_id = $wpdb->insert_id;
        
        // Save individual issues to scan_issues table
        $scan_issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        
        foreach ($issues as $issue) {
            // Add fallback for missing title field
            $title = isset($issue['title']) ? $issue['title'] : 'Malware Detection';
            $description = $title . ' ' . $issue['description'];
            
            // Get file location with fallback for different key names
            $file_location = '';
            if (isset($issue['location'])) {
                $file_location = $issue['location'];
            } elseif (isset($issue['file'])) {
                $file_location = str_replace(ABSPATH, '', $issue['file']);
            } elseif (isset($issue['file_path'])) {
                $file_location = str_replace(ABSPATH, '', $issue['file_path']);
            } else {
                // Skip issues without file location
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- Debug logging for malware scanner diagnostics
                $this->debug_log[] = '[' . current_time('H:i:s') . '] SKIP: Issue without file location - ' . print_r($issue, true);
                continue;
            }
            
            // First check if this issue should be recreated as ignored
            if ($this->handle_ignored_issue($file_location, 'malware', $description, $scan_id)) {
                continue; // Issue was handled as ignored, skip normal processing
            }
            
            // Check if this issue is currently ignored (skip normal creation)
            if ($this->is_issue_ignored($file_location, 'malware', $description)) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] SKIP: Malware issue already ignored - ' . $file_location;
                continue;
            }

            $insert_result = $wpdb->insert(
                $scan_issues_table,
                array(
                    'scan_id' => $scan_id,
                    'file_path' => $file_location,
                    'issue_type' => 'malware',
                    'type' => $this->get_malware_type_from_issue($issue),
                    'severity' => $this->map_issue_type_to_severity('malware'),
                    'description' => $description,
                    'detected_time' => current_time('mysql'),
                    'status' => 'new'
                )
            );
            
            if ($insert_result === false) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Error saving malware issue: ' . $wpdb->last_error;
            }
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Saved malware scan summary (ID: ' . $scan_id . ') and ' . count($issues) . ' malware issues to database';
    }
    
    /**
     * Extract specific malware type from issue data
     * 
     * @param array $issue Issue data array
     * @return string Specific malware type
     */
    private function get_malware_type_from_issue($issue) {
        // Check for specific type field first
        if (isset($issue['type'])) {
            return $issue['type'];
        }
        
        // Check for pattern_id (from badstrings detection)
        if (isset($issue['pattern_id'])) {
            return $issue['pattern_id'];
        }
        
        // Check for signature name (from signature detection)
        if (isset($issue['signature_name'])) {
            return $issue['signature_name'];
        }
        
        // Extract from title if available
        if (isset($issue['title'])) {
            $title = $issue['title'];
            if (strpos($title, 'SVG') !== false) {
                return 'svg_malware';
            } elseif (strpos($title, 'Binary Malware') !== false) {
                return 'binary_signature';
            } elseif (strpos($title, 'Modified Plugin') !== false) {
                return 'modified_plugin';
            } elseif (strpos($title, 'Eval') !== false || strpos($title, 'encoding') !== false) {
                return 'eval_encoding';
            }
        }
        
        // Extract from description as fallback
        if (isset($issue['description'])) {
            $desc = strtolower($issue['description']);
            if (strpos($desc, 'base64') !== false) {
                return 'eval_base64';
            } elseif (strpos($desc, 'gzinflate') !== false) {
                return 'eval_gzinflate';
            } elseif (strpos($desc, 'rot13') !== false) {
                return 'eval_rot13';
            } elseif (strpos($desc, 'svg') !== false) {
                return 'svg_xss';
            } elseif (strpos($desc, 'upload') !== false) {
                return 'upload_exploit';
            } elseif (strpos($desc, 'dom_injection') !== false) {
                return 'dom_injection';
            }
        }
        
        // Default fallback
        return 'generic_malware';
    }

    /**
     * Check if an issue is already ignored
     */
    private function is_issue_ignored($file_path, $issue_type, $description) {
        global $wpdb;
        
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from WordPress prefix
        $issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        
        $count = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$issues_table} WHERE file_path = %s AND issue_type = %s AND description = %s AND status = 'ignored'",
            $file_path,
            $issue_type,
            $description
        ));
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        
        return $count > 0;
    }
    
    /**
     * Handle previously ignored issues - recreate them in current scan as ignored
     *
     * @param string $file_path File path
     * @param string $issue_type Issue type
     * @param string $description Issue description
     * @param int $scan_id Current scan ID
     * @return bool Whether issue was handled
     */
    private function handle_ignored_issue($file_path, $issue_type, $description, $scan_id) {
        global $wpdb;
        
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from WordPress prefix
        $issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        
        // Check if this exact issue was previously ignored
        $ignored_issue = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$issues_table} WHERE file_path = %s AND issue_type = %s AND description = %s AND status = 'ignored' ORDER BY detected_time DESC LIMIT 1",
            $file_path,
            $issue_type,
            $description
        ));
        
        if ($ignored_issue) {
            // Recreate the ignored issue in current scan
            $insert_result = $wpdb->insert(
                $issues_table,
                [
                    'scan_id' => $scan_id,
                    'file_path' => $file_path,
                    'issue_type' => $issue_type,
                    'severity' => $this->map_issue_type_to_severity($issue_type),
                    'description' => $description,
                    'status' => 'ignored',
                    'detected_time' => current_time('mysql'),
                    'resolved_time' => current_time('mysql')
                ],
                ['%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s']
            );
            
            if ($insert_result) {
                // Clean up old ignored entries for this same issue (keep only the latest)
                $wpdb->query($wpdb->prepare(
                    "DELETE FROM {$issues_table} WHERE file_path = %s AND issue_type = %s AND description = %s AND status = 'ignored' AND id != %d",
                    $file_path,
                    $issue_type,
                    $description,
                    $wpdb->insert_id
                ));
                // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
                
                $this->debug_log[] = '[' . current_time('H:i:s') . '] PRESERVED: Recreated ignored malware - ' . $file_path;
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Map issue type to severity level
     *
     * @param string $issue_type Issue type
     * @return string Severity level
     */
    private function map_issue_type_to_severity($issue_type) {
        switch ($issue_type) {
            case 'malware':
                return 'critical';
            default:
                return 'high';
        }
    }
    
    /**
     * Get scan type identifier
     */
    public function get_scan_type() {
        return $this->scan_type;
    }
    
    /**
     * TODO: Future API integration methods
     * These will be implemented when external malware API is available
     */
    
    /*
    private function enhance_with_external_api($issues) {
        // TODO: Implement external API calls for enhanced malware detection
        // Should send: File hashes, suspicious patterns, metadata
        // Should receive: Enhanced threat intelligence, zero-day patterns, reputation data
        $this->debug_log[] = '[TODO] enhance_with_external_api() - External API integration pending';
        
        // Potential API endpoints:
        // - Malware signature updates
        // - File hash reputation checking  
        // - Zero-day pattern downloads
        // - Threat intelligence feeds
    }
    
    private function check_file_with_external_api($file_path, $file_content, &$issues) {
        // TODO: Send file hash and suspicious snippets to external API
        // Should send: SHA256 hash, code snippets, file metadata
        // Should receive: Malware classification, confidence score, remediation advice
        $this->debug_log[] = '[TODO] check_file_with_external_api() - API file checking pending';
        
        // Implementation would:
        // 1. Generate file hash
        // 2. Extract suspicious code snippets
        // 3. Send to malware analysis API
        // 4. Process response and add to $issues
    }
    
    private function update_malware_signatures() {
        // TODO: Download latest malware signatures from external API
        // Should call: GET /api/v1/malware-signatures
        // Should receive: Updated regex patterns, severity levels, descriptions
        $this->debug_log[] = '[TODO] update_malware_signatures() - Signature updates pending';
        
        // Implementation would:
        // 1. Call external API for signature updates
        // 2. Validate and sanitize received patterns  
        // 3. Update local $malware_patterns array
        // 4. Cache signatures for offline use
    }
    */
    
    /**
     * Step 5: Set sensitivity mode (Roadmap requirement)
     */
    public function set_sensitivity_mode($mode) {
        $valid_modes = array('low', 'medium', 'high');
        
        if (!in_array($mode, $valid_modes)) {
            $mode = 'medium'; // Default fallback
        }
        
        $this->sensitivity_mode = $mode;
        
        // Enable high sensitivity mode in sensitivity scanner
        if ($mode === 'high') {
            $this->sensitivity_scanner->enable_high_sensitivity();
            $this->debug_log[] = '[' . current_time('H:i:s') . '] High sensitivity mode enabled';
        }
        
        return array(
            'mode' => $this->sensitivity_mode,
            'settings' => $this->sensitivity_scanner->get_sensitivity_settings()
        );
    }
    
    /**
     * Step 5: Scan file with context analysis and high sensitivity
     */
    private function scan_with_high_sensitivity($file_path, $file_content, &$issues) {
        if ($this->sensitivity_mode !== 'high') {
            return; // Only run in high sensitivity mode
        }
        
        // Use sensitivity scanner for context analysis
        $context_results = $this->sensitivity_scanner->scan_with_context($file_content, $file_path);
        
        // Process context analysis results
        if (!empty($context_results['context_issues'])) {
            foreach ($context_results['context_issues'] as $context_issue) {
                $issues[] = array(
                    'type' => 'context_analysis',
                    'severity' => $this->map_risk_to_severity($context_issue['risk_level']),
                    'description' => 'Suspicious code context detected: ' . $context_issue['function'],
                    'file' => $file_path,
                    'line' => $context_issue['line'],
                    'code' => $context_issue['match'],
                    'details' => array(
                        'function' => $context_issue['function'],
                        'risk_level' => $context_issue['risk_level'],
                        'before_context' => $context_issue['before_context'],
                        'after_context' => $context_issue['after_context']
                    )
                );
            }
        }
        
        // Process obfuscation detection results
        if ($context_results['obfuscation_detected']) {
            $obfuscation = $context_results['obfuscation_details'];
            $issues[] = array(
                'type' => 'obfuscation',
                'severity' => $obfuscation['confidence_score'] >= 70 ? 'high' : 'medium',
                'description' => 'Code obfuscation detected',
                'file' => $file_path,
                'code' => 'Obfuscated content detected',
                'details' => array(
                    'obfuscation_types' => $obfuscation['obfuscation_types'],
                    'confidence_score' => $obfuscation['confidence_score'],
                    'entropy_score' => $obfuscation['entropy_score'],
                    'suspicious_functions' => $obfuscation['suspicious_functions']
                )
            );
        }
        
        // Process base64 malware detection results
        if (!empty($context_results['base64_issues'])) {
            foreach ($context_results['base64_issues'] as $base64_issue) {
                $issues[] = array(
                    'type' => 'base64_malware',
                    'severity' => 'high',
                    'description' => 'Suspicious base64 encoded malware detected',
                    'file' => $file_path,
                    'code' => $base64_issue['encoded_preview'],
                    'details' => array(
                        'encoded_length' => $base64_issue['encoded_length'],
                        'decoded_length' => $base64_issue['decoded_length'],
                        'analysis' => $base64_issue['analysis']
                    )
                );
            }
        }
        
        // Process entropy analysis results
        if (!empty($context_results['entropy_analysis']) && $context_results['entropy_analysis']['suspicious']) {
            $entropy_data = $context_results['entropy_analysis'];
            $issues[] = array(
                'type' => 'entropy_analysis',
                'severity' => $entropy_data['confidence'] >= 70 ? 'high' : 'medium',
                'description' => $entropy_data['recommendation'],
                'file' => $file_path,
                'code' => 'High entropy content detected',
                'details' => array(
                    'entropy' => $entropy_data['entropy'],
                    'confidence' => $entropy_data['confidence'],
                    'recommendation' => $entropy_data['recommendation']
                )
            );
        }
    }
    
    /**
     * Scan binary and image files for malware
     */
    private function scan_binary_file($file_path, &$issues) {
        $file_extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
        $binary_extensions = array('jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'pdf', 'zip', 'rar', '7z', 'exe', 'dll');
        
        if (!in_array($file_extension, $binary_extensions)) {
            return; // Not a binary file we can scan
        }
        
        // Read file content for analysis (limit to 10MB for safety)
        $file_content = '';
        if (is_readable($file_path) && filesize($file_path) < 10485760) {
            $file_content = file_get_contents($file_path);
        }
        
        // Scan binary signatures
        $signature_results = $this->binary_detector->check_binary_signatures($file_path);
        if ($signature_results['detected']) {
            foreach ($signature_results['detections'] as $detection) {
                $issues[] = array(
                    'type' => 'binary_malware',
                    'severity' => $detection['severity'],
                    'description' => 'Binary malware signature detected: ' . $detection['type'],
                    'file' => $file_path,
                    'code' => 'Binary signature: ' . $detection['prefix'] . ' at position ' . $detection['position'],
                    'details' => array(
                        'signature_name' => $detection['type'],
                        'signature_type' => $detection['type'],
                        'offset' => $detection['position'],
                        'confidence' => $detection['confidence'],
                        'scan_time' => $signature_results['scan_time']
                    )
                );
            }
        }
        
        // Special handling for SVG files (can contain JavaScript)
        if ($file_extension === 'svg' && !empty($file_content)) {
            // Check for actual malicious JavaScript patterns in SVG files
            $malicious_patterns = [
                '/<script[\s>]/i',                          // Script tags
                '/javascript\s*:/i',                        // JavaScript protocol
                '/on(load|error|click|mouseover|focus)\s*=/i', // Specific dangerous event handlers
                '/eval\s*\(/i',                            // Eval functions
                '/document\.(write|createElement)/i',       // DOM manipulation
                '/alert\s*\(/i',                           // Alert calls (often used in XSS)
                '/window\.(open|location)/i'               // Window manipulation
            ];
            
            $found_malicious = false;
            $matched_pattern = '';
            
            foreach ($malicious_patterns as $pattern) {
                if (preg_match($pattern, $file_content, $matches)) {
                    $found_malicious = true;
                    $matched_pattern = isset($matches[0]) ? $matches[0] : 'JavaScript pattern';
                    break;
                }
            }
            
            if ($found_malicious) {
                $issues[] = array(
                    'type' => 'svg_malware',
                    'severity' => 'high',
                    'title' => 'Malicious SVG File Detected',
                    'description' => 'Potentially malicious JavaScript found in SVG file',
                    'location' => str_replace(ABSPATH, '', $file_path),
                    'details' => 'SVG files should not contain script tags or JavaScript - Pattern: ' . $matched_pattern,
                    'pattern_id' => 'svg_javascript_detection',
                    'pattern_category' => 'file_type_specific',
                    'matched_code' => 'SVG with JavaScript content',
                    'custom_message' => 'SVG files should not contain executable JavaScript code',
                    'scan_type' => 'file_type',
                    'log_only' => false,
                    'recommendation' => 'Remove JavaScript code from SVG file or replace with safer alternative'
                );
            }
        }
        
        return $issues;
    }
    
    /**
     * Map risk levels to severity levels
     */
    private function map_risk_to_severity($risk_level) {
        switch ($risk_level) {
            case 'high':
                return 'high';
            case 'medium':
                return 'medium';
            case 'low':
            default:
                return 'low';
        }
    }
    
    /**
     * Get sensitivity scanner settings
     */
    public function get_sensitivity_settings() {
        return array(
            'current_mode' => $this->sensitivity_mode,
            'scanner_settings' => $this->sensitivity_scanner->get_sensitivity_settings(),
            'binary_detector_formats' => $this->binary_detector->get_supported_formats()
        );
    }
    
    /**
     * Check embedded URLs in scanned files for malicious reputation
     * Extract URLs from scanned files and verify reputation
     */
    private function check_embedded_urls($existing_issues) {
        $url_issues = array();
        $all_urls = array();
        $files_to_check = array();
        
        // Extract URLs from files that were already flagged as suspicious
        foreach ($existing_issues as $issue) {
            if (isset($issue['file']) && !in_array($issue['file'], $files_to_check)) {
                $files_to_check[] = $issue['file'];
            }
        }
        
        // Also check a sample of clean files for hidden malicious URLs
        $sample_files = $this->get_random_file_sample(100); // Check 100 random files
        $files_to_check = array_merge($files_to_check, $sample_files);
        $files_to_check = array_unique($files_to_check);
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Checking URLs in ' . count($files_to_check) . ' files';
        
        // Extract URLs from all target files
        $processed_files = 0;
        foreach ($files_to_check as $file_path) {
            if (!file_exists($file_path) || !is_readable($file_path)) {
                continue;
            }
            
            // Performance throttling for file processing
            if (class_exists('VMPFence_Performance_Manager')) {
                VMPFence_Performance_Manager::throttle_processing($processed_files);
            }
            $processed_files++;
            
            // Only check files under 1MB to avoid memory issues
            if (filesize($file_path) > 1048576) {
                continue;
            }
            
            try {
                $content = file_get_contents($file_path);
                if ($content === false) {
                    continue;
                }
                
                // Extract URLs from file content
                $file_urls = $this->url_safety_checker->extract_urls_from_content($content);
                
                if (!empty($file_urls)) {
                    foreach ($file_urls as $url) {
                        $all_urls[$url] = $file_path; // Map URL to source file
                    }
                }
                
            } catch (Exception $e) {
                $this->debug_log[] = '[' . current_time('H:i:s') . '] Error extracting URLs from ' . $file_path . ': ' . $e->getMessage();
            }
        }
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Extracted ' . count($all_urls) . ' unique URLs for safety checking';
        
        // Batch check all URLs for efficiency
        if (!empty($all_urls)) {
            $url_list = array_keys($all_urls);
            $safety_results = $this->url_safety_checker->batch_check_urls($url_list);
            
            // Process results and create issues for unsafe URLs
            foreach ($safety_results as $url => $result) {
                if ($result['safe'] === false) {
                    $source_file = $all_urls[$url];
                    
                    $url_issues[] = array(
                        'type' => 'malicious_url',
                        'severity' => $this->get_url_threat_severity($result['threat_type']),
                        'description' => 'Malicious URL detected: ' . $result['threat_type'],
                        'file' => $source_file,
                        'code' => $url,
                        'details' => array(
                            'url' => $url,
                            'threat_type' => $result['threat_type'],
                            'safe_browsing_response' => $result['details'],
                            'scan_type' => 'url_reputation_check',
                            'api_checked_at' => $result['details']['checked_at'] ?? current_time('mysql')
                        )
                    );
                    
                    $this->debug_log[] = '[' . current_time('H:i:s') . '] Malicious URL detected: ' . $url . ' (Type: ' . $result['threat_type'] . ')';
                }
            }
        }
        
        // Get API usage stats for monitoring
        $api_stats = $this->url_safety_checker->get_api_stats();
        $this->debug_log[] = '[' . current_time('H:i:s') . '] URL API Usage: ' . $api_stats['requests_made'] . '/' . $api_stats['rate_limit'] . ' requests';
        
        return $url_issues;
    }
    
    /**
     * Get random sample of files for URL checking
     * Helper method for comprehensive URL scanning
     * @since 1.0.0
     * @since 2.1.1
     */
    private function get_random_file_sample($count) {
        $sample_files = array();
        $directories_to_check = array(
            ABSPATH . 'wp-content/themes',
            ABSPATH . 'wp-content/plugins',
            ABSPATH . 'wp-includes'
        );
        
        foreach ($directories_to_check as $directory) {
            if (!is_dir($directory)) {
                continue;
            }
            
            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS)
            );
            
            $files = array();
            foreach ($iterator as $file) {
                if ($file->isFile() && in_array($file->getExtension(), array('php', 'js', 'html', 'htm'))) {
                    $files[] = $file->getPathname();
                }
                
                // Limit to prevent memory issues
                if (count($files) >= $count * 3) {
                    break;
                }
            }
            
            // Randomly select files from this directory
            if (!empty($files)) {
                $random_files = array_rand($files, min((int)($count / 3), count($files)));
                if (!is_array($random_files)) {
                    $random_files = array($random_files);
                }
                
                foreach ($random_files as $index) {
                    $sample_files[] = $files[$index];
                }
            }
        }
        
        return array_slice($sample_files, 0, $count);
    }
    
    /**
     * Map Google Safe Browsing threat types to severity levels
     * Convert API threat types to VMPFence severity levels
     */
    private function get_url_threat_severity($threat_type) {
        switch ($threat_type) {
            case 'MALWARE':
                return 'critical';
            case 'SOCIAL_ENGINEERING':
                return 'high';
            case 'UNWANTED_SOFTWARE':
                return 'medium';
            case 'POTENTIALLY_HARMFUL_APPLICATION':
                return 'medium';
            default:
                return 'low';
        }
    }
    
    /**
     * Assess file location risk for enhanced metadata
     * 
     * @param string $file_path File path to assess
     * @return string Risk level (low, medium, high, critical)
     */
    private function assess_file_location_risk($file_path) {
        // WordPress core directories - highest risk if modified
        if (strpos($file_path, ABSPATH . 'wp-admin') === 0 || strpos($file_path, ABSPATH . 'wp-includes') === 0) {
            return 'critical';
        }
        
        // Uploads directory - high risk for executable files
        $upload_dir = wp_upload_dir();
        if (strpos($file_path, $upload_dir['basedir']) === 0) {
            return 'high';
        }
        
        // Active plugins - medium risk
        if (strpos($file_path, WP_PLUGIN_DIR) === 0) {
            return 'medium';
        }
        
        // Active theme - medium risk
        if (strpos($file_path, get_theme_root()) === 0) {
            return 'medium';
        }
        
        // Other locations - low risk
        return 'low';
    }
    
    /**
     * Calculate pattern specificity score for confidence assessment
     * 
     * @param array $pattern_info Pattern information
     * @return float Specificity score (0.0 - 1.0)
     */
    private function calculate_pattern_specificity($pattern_info) {
        $specificity = 0.5; // Base specificity
        
        // More specific patterns get higher scores
        $pattern = $pattern_info['pattern'] ?? $pattern_info['regex_pattern'] ?? '';
        
        // Check for very specific malicious patterns
        if (strpos($pattern, 'eval.*base64_decode') !== false) {
            $specificity += 0.4;
        } elseif (strpos($pattern, 'eval') !== false) {
            $specificity += 0.2;
        }
        
        // Check for user input patterns
        if (strpos($pattern, '\$_(?:GET|POST|REQUEST)') !== false) {
            $specificity += 0.2;
        }
        
        // Check for obfuscation patterns
        if (preg_match('/base64_decode.*gzinflate/i', $pattern)) {
            $specificity += 0.3;
        }
        
        // Severity also affects specificity
        $severity = $pattern_info['severity'] ?? 'medium';
        switch ($severity) {
            case 'critical':
                $specificity += 0.1;
                break;
            case 'high':
                $specificity += 0.05;
                break;
        }
        
        return min(1.0, max(0.0, $specificity));
    }
    
    /**
     * Get line number and context for a malware match
     *
     * @param string $file_content The complete file content
     * @param int $byte_position The byte position of the match
     * @param string $matched_text The matched malicious text
     * @return array Array with line number, line content, highlighted line, and context
     */
    private function get_line_number_and_context($file_content, $byte_position, $matched_text) {
        // Split content into lines
        $lines = explode("\n", $file_content);
        
        // Find which line contains the match
        $current_position = 0;
        $line_number = 1;
        $found_line = '';
        
        foreach ($lines as $line_index => $line) {
            $line_end_position = $current_position + strlen($line) + 1; // +1 for newline
            
            if ($byte_position >= $current_position && $byte_position < $line_end_position) {
                $line_number = $line_index + 1;
                $found_line = $line;
                break;
            }
            
            $current_position = $line_end_position;
        }
        
        // Create highlighted version of the line
        $highlighted_line = $found_line;
        if (!empty($matched_text) && strpos($found_line, $matched_text) !== false) {
            $highlighted_line = str_replace(
                $matched_text, 
                '**[MALWARE: ' . $matched_text . ']**', 
                $found_line
            );
        }
        
        // Get context lines (2 before and 2 after)
        $context_start = max(0, $line_number - 3);
        $context_end = min(count($lines), $line_number + 2);
        $context_lines = [];
        
        for ($i = $context_start; $i < $context_end; $i++) {
            $display_line_num = $i + 1;
            $line_content = $lines[$i] ?? '';
            $marker = ($display_line_num == $line_number) ? '>>> ' : '    ';
            
            if ($display_line_num == $line_number) {
                $context_lines[] = $marker . $display_line_num . ': ' . $highlighted_line;
            } else {
                $context_lines[] = $marker . $display_line_num . ': ' . $line_content;
            }
        }
        
        return [
            'line_number' => $line_number,
            'line_content' => $found_line,
            'highlighted_line' => $highlighted_line,
            'context_lines' => $context_lines
        ];
    }
}
