<?php
defined('ABSPATH') || exit;

require_once dirname(__FILE__) . '/engines/signature.php';
require_once dirname(__FILE__) . '/engines/pattern.php';
require_once dirname(__FILE__) . '/engines/heuristic.php';
require_once dirname(__FILE__) . '/engines/anomaly.php';
require_once dirname(__FILE__) . '/whitelist.php';
require_once dirname(__FILE__) . '/webhooks.php';

// Advanced scanning engines
require_once dirname(__FILE__) . '/advanced.php';
require_once dirname(__FILE__) . '/engines/advanced-potential.php';
require_once dirname(__FILE__) . '/engines/advanced-htaccess.php';
require_once dirname(__FILE__) . '/engines/advanced-database.php';
require_once dirname(__FILE__) . '/engines/advanced-login.php';
require_once dirname(__FILE__) . '/advanced-firewall.php';

// Helper function to check if a file is a test malware file
function wpsec_is_test_malware_file($file_path) {
    if (empty($file_path)) {
        return false;
    }
    
    $file_path = strtolower($file_path);
    return (strpos($file_path, 'test-malware') !== false || 
            strpos($file_path, 'test_malware') !== false ||
            strpos($file_path, 'testmalware') !== false ||
            strpos($file_path, 'i-am-hacking') !== false ||
            strpos($file_path, 'malware-detection') !== false ||
            strpos($file_path, 'malware_detection') !== false);
}

function wpsec_run_scan($scan_id = null, $force_deep_scan = false, $verbose_logging = false, $resume_from_position = 0, $test_files_only = false) {
    // Initialize tracking array for every stage
    global $wpsec_test_file_tracking;
    $wpsec_test_file_tracking = [
        'scan_queue' => [],
        'detected_raw' => [],
        'after_filtering' => [],
        'after_standardization' => [],
        'final_results' => []
    ];
    
    wpsec_debug_log(' CRITICAL DIAGNOSTICS: Starting comprehensive test file tracking', 'critical');
    
    // Set the global deep scan flag and verbose logging flag
    global $wpsec_force_deep_scan, $wpsec_verbose_logging, $wpsec_test_files_only;
    $wpsec_force_deep_scan = $force_deep_scan;
    $wpsec_verbose_logging = $verbose_logging;
    $wpsec_test_files_only = $test_files_only;
    
    // Also load from options - this ensures parameters work even when scan is resumed
    if ($scan_id) {
        $option_deep_scan = get_option('wpsec_scan_' . $scan_id . '_force_deep_scan', false);
        $option_verbose = get_option('wpsec_scan_' . $scan_id . '_verbose_logging', false);
        $option_test_files_only = get_option('wpsec_scan_' . $scan_id . '_test_files_only', false);
        
        // CRITICAL: Add debug logging to trace test_files_only flag
        wpsec_debug_log('🔧 SCAN DEBUG: test_files_only parameter=' . ($test_files_only ? 'TRUE' : 'FALSE') . 
                  ', option_test_files_only=' . ($option_test_files_only ? 'TRUE' : 'FALSE'), 'debug');
        
        // Options override function parameters if they exist
        if ($option_deep_scan) {
            $force_deep_scan = true;
            $wpsec_force_deep_scan = true;
        }
        
        if ($option_verbose) {
            $verbose_logging = true;
            $wpsec_verbose_logging = true;
        }
        
        // CRITICAL FIX: Force test_files_only to FALSE for all production scans regardless of options
        // This prevents test-only functionality from interfering with normal scan operation
        $test_files_only = false;
        $wpsec_test_files_only = false;
        if (isset($_REQUEST['scan_test_files_only']) && $_REQUEST['scan_test_files_only'] === '1') {
            $test_files_only = true;
            $wpsec_test_files_only = true;
            wpsec_debug_log('🧪 TEST FILES ONLY MODE enabled by explicit request parameter', 'info');
        } else {
            wpsec_debug_log('✅ PRODUCTION SCAN MODE - test_files_only disabled for scan ID: ' . $scan_id, 'info');
        }
    } else {
        // CRITICAL: If no scan_id, ensure test_files_only defaults to FALSE
        if (!$test_files_only) {
            $wpsec_test_files_only = false;
            wpsec_debug_log('✅ PRODUCTION SCAN MODE - test_files_only disabled (no scan_id)', 'info');
        }
    }
    
    // Enhanced logging about scan configuration
    wpsec_debug_log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", 'info');
    wpsec_debug_log(" WPFort SCAN STARTING", 'info');
    wpsec_debug_log("• Scan ID: {$scan_id}", 'info');
    wpsec_debug_log("• Deep scan: " . ($force_deep_scan ? ' ENABLED' : ' DISABLED'), 'info');
    wpsec_debug_log("• Verbose logging: " . ($verbose_logging ? ' ENABLED' : ' DISABLED'), 'info');
    if ($resume_from_position > 0) {
        wpsec_debug_log("• Resuming from position: {$resume_from_position}", 'info');
    }
    wpsec_debug_log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", 'info');
    
    // Check if force_deep_scan was passed via URL parameter
    if (isset($_REQUEST['force_deep_scan']) && $_REQUEST['force_deep_scan'] == 1) {
        $force_deep_scan = true;
    }
    
    // Clear cache if requested via URL parameter (useful for testing and maintenance)
    if (isset($_REQUEST['clear_cache']) && $_REQUEST['clear_cache'] == 1) {
        if (function_exists('wpsec_clear_file_hash_cache')) {
            wpsec_clear_file_hash_cache();
            wpsec_debug_log(" WPFort: File hash cache cleared before scan (clear_cache=1)", 'info');
        } else {
            wpsec_debug_log(" WPFort: Cache clear requested but function not available", 'info');
        }
    }
    
    // Check if verbose_logging was passed via URL parameter
    if (isset($_REQUEST['verbose_logging']) && $_REQUEST['verbose_logging'] == 1) {
        $verbose_logging = true;
        wpsec_debug_log(" WPFort: VERBOSE LOGGING mode enabled - all file scans will be logged", 'info');
    }
    
    $wpsec_force_deep_scan = $force_deep_scan;
    
    wpsec_debug_log(' WPFort: ' . ($force_deep_scan ? 'DEEP SCAN mode enabled - bypassing ALL caching' : 'Normal scan mode'), 'info');
    
    // Detect server environment to optimize scan parameters
    $server_environment = wpsec_detect_server_environment();
    wpsec_debug_log(' WPFort: Detected server environment: ' . $server_environment['type'] . 
              ' (CPU: ' . $server_environment['cpu_load'] . ', Memory: ' . $server_environment['memory_available'] . ')', 'info');
    
    // Adjust chunk size based on server environment
    $chunk_size = wpsec_get_optimal_chunk_size($server_environment);
    wpsec_debug_log(' WPFort: Using chunk size of ' . $chunk_size . ' files per batch', 'info');
    
    wpsec_debug_log(' WPFort Background scan ' . ($resume_from_position > 0 ? 'resumed' . ($scan_id ? ' with ID: ' . $scan_id : '') : 'started') . ' at ' . gmdate('Y-m-d H:i:s') . 
              ($force_deep_scan ? ' (DEEP SCAN)' : ''), 'info');

    // Set resource limits
    if (function_exists('set_time_limit')) {
        @set_time_limit(0);
    }
    
    // Set memory limit but respect system settings
    $current_limit = ini_get('memory_limit');
    $current_bytes = wp_convert_hr_to_bytes($current_limit);
    if ($current_bytes < 512 * 1024 * 1024) { // Only increase if less than 512MB
        @ini_set('memory_limit', '512M');
    }

    // Enable garbage collection
    if (!gc_enabled()) {
        gc_enable();
    }

    $scan_start_time = time();
    $memory_peak = 0;
    
    try {
        // Set global scan ID for use in other functions
        global $wpsec_current_scan_id;
        $wpsec_current_scan_id = $scan_id;
        
        // Initialize scan status and other tracking options
        if ($scan_id) {
            // Set scan status to 'scanning' to ensure it's properly tracked
            update_option('wpsec_scan_' . $scan_id . '_status', 'scanning');
            update_option('wpsec_scan_' . $scan_id . '_last_update', time());
            update_option('wpsec_scan_' . $scan_id . '_progress', 0);
            
            wpsec_debug_log(" WPFort: Set scan {$scan_id} status to 'scanning'", 'info');
        }
        
        // Load detection databases with error handling
        $signatures = wpsec_load_malware_signatures();
        $patterns = wpsec_load_malware_patterns();
        
        // Always ensure advanced definitions are loaded with fallback to empty structure if needed
        $advanced_definitions = wpsec_load_advanced_definitions();
        if (empty($advanced_definitions) || !is_array($advanced_definitions)) {
            wpsec_debug_log(' Advanced definitions not loaded correctly, creating fallback structure', 'info');
            $advanced_definitions = [
                'potential' => [],
                'firewall' => [],
                'db_scan' => [],
                'htaccess' => [],
                'known' => [],
                'wp_login' => []
            ];
        }
        
        if (!$signatures || !$patterns) {
            throw new Exception('Failed to load malware detection databases');
        }
        
        // Log advanced definitions status (only in verbose mode)
        if ($verbose_logging) {
            wpsec_debug_log(' Advanced definitions loaded successfully', 'info');
        }
        // Count definitions by type (only log in verbose mode)
        if ($verbose_logging) {
            $definition_counts = [];
            foreach ($advanced_definitions as $type => $defs) {
                $definition_counts[$type] = count($defs);
            }
            wpsec_debug_log(' Advanced definitions count: ' . json_encode($definition_counts), 'info');
        }

        // Build scan queue with priorities
        $scan_queue_result = wpsec_build_scan_queue();
        $scan_queue = $scan_queue_result['queue'];
        $total_files = $scan_queue_result['total_files'];
        
        // If resuming, we need to restore previous detection results
        $infected_files = [];
        if ($resume_from_position > 0 && $scan_id) {
            try {
                $previous_results_json = get_option('wpsec_scan_' . $scan_id . '_partial_results', '[]');
                $infected_files = json_decode($previous_results_json, true);
                wpsec_debug_log(' WPFort: Resuming scan with ' . count($infected_files) . " previously detected issues", 'info');
            } catch (Exception $e) {
                wpsec_debug_log(' WPFort: Error restoring previous results: ' . $e->getMessage(), 'error');
                // Start with empty results if we can't restore
                $infected_files = [];
            }
        }
        
        // Initialize counters
        $processed = (int) $resume_from_position; // CRITICAL FIX: Ensure integer value, default to 0
        $skipped = 0;
        $cached = 0;
        $errors = 0;
        $files_in_chunk = 0;
        $chunk_counter = 0;
        $chunk_start_time = microtime(true);
        $last_progress_check = time();
        $last_progress_value = $scan_id ? get_option('wpsec_scan_' . $scan_id . '_last_progress_value', 0) : 0;
        $last_webhook_time = $scan_id ? get_option('wpsec_scan_' . $scan_id . '_last_webhook_time', 0) : 0;
        $scan_should_pause = false; // Flag to signal early exit due to resource constraints
        $last_processed_count = -1; // Track the last processed count to detect when files are processed
        
        // CRITICAL: Force initial progress update and webhook
        if ($scan_id) {
            update_option('wpsec_scan_' . $scan_id . '_progress', $processed > 0 ? max(1, round(($processed / $total_files) * 100)) : 0);
            update_option('wpsec_scan_' . $scan_id . '_files_scanned', $processed);
            update_option('wpsec_scan_' . $scan_id . '_last_progress_update', time());
            
            // Send initial webhook to ensure we're tracking from the start
            if (function_exists('wpsec_send_scan_progress_webhook')) {
                wpsec_send_scan_progress_webhook($scan_id);
                update_option('wpsec_scan_' . $scan_id . '_last_webhook_time', time());
            }
        }
        
        if ($verbose_logging) {
            wpsec_debug_log(' WPFort: Starting main file scan loop with ' . count($scan_queue) . ' files', 'info');
            if ($force_deep_scan) {
                wpsec_debug_log(' WPFort: DEEP SCAN MODE ENABLED - Bypassing whitelist and cache', 'info');
            }
        }
        
        // MAIN FILE PROCESSING LOOP
        // Process each file in the scan queue, starting from resume position
        $current_position = 0;
        foreach ($scan_queue as $file_path => $priority) {
            // Check if we need to exit early due to resource constraints
            if ($scan_should_pause) {
                wpsec_debug_log(' WPFort: Exiting main scan loop early due to resource constraints. Will resume from position ' . $processed, 'info');
                break;
            }
            
            // Skip files we've already processed if resuming
            if ($current_position < $resume_from_position) {
                $current_position++;
                continue;
            }
            
            // Process this file
            try {
                if ($verbose_logging) {
                    wpsec_debug_log(sprintf(' Processing file: %s (priority: %s)', $file_path, $priority), 'info');
                }
                
                // Scan the file
                $scan_result = wpsec_scan_single_file($file_path, $signatures, $patterns, $priority);
                
                // Process scan results
                if ($scan_result) {
                    // Critical diagnostic for test files - track exact processing flow
                    if (wpsec_is_test_malware_file($file_path)) {
                        wpsec_debug_log(' TRACE: Processing scan result for test file: ' . $file_path, 'info');
                        wpsec_debug_log('   - Raw scan result: ' . json_encode($scan_result, JSON_UNESCAPED_SLASHES), 'info');
                        wpsec_debug_log('   - Is infected flag set: ' . (isset($scan_result['infected']) && $scan_result['infected'] ? 'YES' : 'NO'), 'info');
                        wpsec_debug_log('   - Is skipped flag set: ' . (isset($scan_result['skipped']) && $scan_result['skipped'] ? 'YES' : 'NO'), 'info');
                        wpsec_debug_log('   - Contains detections: ' . (isset($scan_result['detections']) && !empty($scan_result['detections']) ? 'YES - ' . count($scan_result['detections']) : 'NO'), 'info');
                    }
                    
                    if ($verbose_logging && isset($scan_result['cached']) && $scan_result['cached']) {
                        wpsec_debug_log(' Used cached result for: ' . $file_path, 'info');
                        $cached++;
                    }
                    
                    if (isset($scan_result['infected']) && $scan_result['infected']) {
                        if ($verbose_logging) {
                            wpsec_debug_log(' Detected issue in: ' . $file_path, 'info');
                        }
                        // Add the detection to our results
                        $infected_files[] = $scan_result;
                        
                        // Critical logging when adding test files to infected_files array
                        if (wpsec_is_test_malware_file($file_path)) {
                            $current_position = count($infected_files) - 1;
                            wpsec_debug_log(' TRACE: Added test file to infected_files array at position ' . $current_position, 'info');
                            
                            // VERIFY the file actually got added correctly by checking the array
                            $added_result = $infected_files[$current_position];
                            wpsec_debug_log('   - VERIFICATION: File path in array matches: ' . ($added_result['file_path'] === $file_path ? 'YES' : 'NO'), 'info');
                            wpsec_debug_log('   - VERIFICATION: Detections count: ' . (isset($added_result['detections']) ? count($added_result['detections']) : 0), 'info');
                        }
                    } else if (isset($scan_result['skipped']) && $scan_result['skipped']) {
                        if ($verbose_logging) {
                            wpsec_debug_log(' Skipped: ' . $file_path . ' (Reason: ' . ($scan_result['skip_reason'] ?? 'Unknown') . ')', 'info');
                        }
                        $skipped++;
                    }
                }
            } catch (Exception $e) {
                $error_msg = $e->getMessage();
                wpsec_debug_log(" Error scanning {$file_path}: " . $error_msg, 'error');
                
                // Record detailed error information
                if ($scan_id) {
                    // Get existing error list or initialize a new one
                    $file_errors = json_decode(get_option('wpsec_scan_' . $scan_id . '_file_errors', '[]'), true);
                    
                    // Add this error with context
                    $file_errors[] = [
                        'file' => $file_path,
                        'message' => $error_msg,
                        'time' => gmdate('Y-m-d H:i:s'),
                        'progress' => round(($processed / $total_files) * 100, 1),
                        'memory' => round(memory_get_usage(true) / 1024 / 1024, 2) . 'MB'
                    ];
                    
                    // Limit array to prevent it from getting too large (keep most recent 50 errors)
                    if (count($file_errors) > 50) {
                        $file_errors = array_slice($file_errors, -50);
                    }
                    
                    // Save updated error list
                    update_option('wpsec_scan_' . $scan_id . '_file_errors', json_encode($file_errors));
                }
                
                $errors++;
            }
            
            $processed++;
            
            // CRITICAL: Update the files_scanned option to ensure it's available for status endpoints
            if ($scan_id && ($processed % 10 == 0 || $processed === $total_files)) {
                update_option('wpsec_scan_' . $scan_id . '_files_scanned', $processed);
            }
            
            $files_in_chunk++;
            $current_position++;
            
            // CRITICAL DEBUG: Track progress counter increment
            if ($processed % 5 === 0 || $processed <= 10) {
                wpsec_debug_log(" PROGRESS DEBUG: processed={$processed}, current_position={$current_position}, total_files={$total_files}", 'debug');
            }
            
            // Update progress at regular intervals - every 100 files or 30 seconds
            // This is the working pattern from the original implementation
            if ($scan_id && ($processed % 100 == 0 || $processed === $total_files || time() - $last_progress_check >= 30)) {
                $last_progress_check = time();
                
                // Calculate progress percentage (simple calculation without forced minimum)
                $progress = $total_files > 0 ? round(($processed / $total_files) * 100) : 0;
                
                // Log critical progress data for debugging
                wpsec_debug_log(sprintf(
                    '🚀 PROGRESS UPDATE: %d%% (%d/%d files) - Time since last update: %d seconds',
                    $progress,
                    $processed,
                    $total_files,
                    time() - $last_progress_check
                ), 'info');
                $current_memory = memory_get_usage(true);
                $memory_peak = max($memory_peak, $current_memory);
                $last_progress_value = get_option('wpsec_scan_' . $scan_id . '_last_progress_value', 0);
                
                update_option('wpsec_scan_' . $scan_id . '_progress', $progress);
                update_option('wpsec_scan_' . $scan_id . '_files_scanned', $processed);
                update_option('wpsec_scan_' . $scan_id . '_files_skipped', $skipped);
                update_option('wpsec_scan_' . $scan_id . '_files_cached', $cached);
                update_option('wpsec_scan_' . $scan_id . '_errors', $errors);
                update_option('wpsec_scan_' . $scan_id . '_memory_usage', $current_memory);
                update_option('wpsec_scan_' . $scan_id . '_memory_peak', $memory_peak);
                update_option('wpsec_scan_' . $scan_id . '_last_progress_update', time());
                
                // Save partial results for potential resume
                if (count($infected_files) > 0) {
                    update_option('wpsec_scan_' . $scan_id . '_partial_results', json_encode(array_values($infected_files)));
                }
                
                // Log progress update
                wpsec_debug_log(sprintf(
                    ' WPFort Scan: Progress update - %d%% complete (%d/%d files scanned)',
                    $progress,
                    $processed,
                    $total_files
                ), 'info');
                
                // Get the timestamp of the last webhook call
                $last_webhook_time = get_option('wpsec_scan_' . $scan_id . '_last_webhook_time', 0);
                $time_since_last_webhook = time() - $last_webhook_time;
                $min_webhook_interval = 5; // Minimum 5 seconds between webhook calls
                
                // Send webhook update if:
                // 1. Progress has increased by at least 5% AND at least 5 seconds have passed since last call, OR
                // 2. This is the completion update (100% or all files processed)
                if ((($progress - $last_progress_value) >= 5 && $time_since_last_webhook >= $min_webhook_interval) || 
                    $progress === 100 || $processed === $total_files) {
                    
                    // CRITICAL: Ensure webhook function is called if it exists
                    if (function_exists('wpsec_send_scan_progress_webhook')) {
                        wpsec_debug_log(sprintf(
                            ' WPFort Scan: Triggering progress webhook at %d%% (last sent: %d%%, time since last: %ds)',
                            $progress,
                            $last_progress_value,
                            $time_since_last_webhook
                        ), 'info');
                        wpsec_send_scan_progress_webhook($scan_id);
                        update_option('wpsec_scan_' . $scan_id . '_last_progress_value', $progress);
                        update_option('wpsec_scan_' . $scan_id . '_last_webhook_time', time());
                    }
                }
                
                // Force garbage collection periodically
                if ($processed % 1000 === 0) {
                    gc_collect_cycles();
                }
            }
            
            // Check if we need to pause for a chunk break
            $chunk_duration = microtime(true) - $chunk_start_time;
            
            // If we've processed the chunk size or if a chunk has been running too long (30 seconds),
            // save progress and reset chunk counters
            if ($files_in_chunk >= $chunk_size || $chunk_duration > 30) {
                $chunk_counter++;
                
                // Calculate actual scan rate for this chunk
                $chunk_scan_rate = $files_in_chunk / max(0.001, $chunk_duration);
                
                wpsec_debug_log(sprintf(
                    ' WPFort Scan: Completed chunk %d with %d files in %.2f seconds (rate: %.2f files/sec, progress: %d%%)',
                    $chunk_counter,
                    $files_in_chunk,
                    $chunk_duration,
                    $chunk_scan_rate,
                    $progress
                ), 'info');
                
                // Reset chunk counters
                $files_in_chunk = 0;
                $chunk_start_time = microtime(true);
                
                // Update progress tracking more frequently (every 100 files instead of 500)
                // This ensures more responsive monitoring without automatic pausing
                if ($processed % 100 == 0 || time() - $last_progress_check >= 30) {
                    $last_progress_check = time();
                    
                    // Update status, position, and progress information
                    update_option('wpsec_scan_' . $scan_id . '_last_update', time());
                    update_option('wpsec_scan_' . $scan_id . '_resume_position', $processed);
                    update_option('wpsec_scan_' . $scan_id . '_progress', $progress);
                    update_option('wpsec_scan_' . $scan_id . '_files_scanned', $processed);
                    
                    // Check for resource bottlenecks that would require pausing
                    $server_env = wpsec_detect_server_environment();
                    
                    // Log progress statistics for monitoring
                    $server_env = wpsec_detect_server_environment();
                    $scan_rate = $processed / max(1, microtime(true) - $start_time);
                    $memory_usage = round(memory_get_usage(true) / 1024 / 1024, 2);
                    
                    wpsec_debug_log(sprintf(' WPFort Scan: %d%% - Files: %d/%d - CPU: %d%% - Rate: %.2f files/sec - Mem: %dMB', 
                        $progress, $processed, $total_files, $server_env['cpu_load'], $scan_rate, $memory_usage), 'info');
                    
                    // Check for severe resource constraints that would require pausing the scan
                    // Only pause if we've processed a minimum number of files (1000) OR resource usage is critical
                    $minimum_files_before_pause = 1000;
                    $is_critical_resource_usage = ($server_env['cpu_load'] > 95 || $memory_usage > ($server_env['memory_limit'] * 0.9));
                    $is_high_resource_usage = ($server_env['cpu_load'] > 90 || $memory_usage > ($server_env['memory_limit'] * 0.85));
                    
                    if (($processed >= $minimum_files_before_pause && $is_high_resource_usage) || $is_critical_resource_usage) {
                        wpsec_debug_log(" WPFort: Detected resource constraints. Pausing scan for recovery.", 'info');
                        wpsec_debug_log(sprintf('Resource metrics - CPU: %d%%, Memory: %dMB/%sMB, Files processed: %d', 
                            $server_env['cpu_load'], $memory_usage, $server_env['memory_limit'], $processed), 'info');
                            
                        // Transition to paused state
                        update_option('wpsec_scan_' . $scan_id . '_status', 'paused');
                        update_option('wpsec_scan_' . $scan_id . '_resume_position', $processed);
                        update_option('wpsec_scan_' . $scan_id . '_paused_reason', 'resource_constraints');
                        
                        // Schedule immediate resumption via the recovery system
                        wpsec_schedule_scan_resume($scan_id, $processed);
                        
                        // Exit the scan loop - recovery will continue from here
                        // Use a flag to signal we need to exit all loops
                        $scan_should_pause = true;
                        break; // Break out of the immediate loop
                    }
                    
                    // Force garbage collection every 2000 files to maintain performance
                    if ($processed % 2000 === 0 && function_exists('gc_collect_cycles')) {
                        gc_collect_cycles();
                    }
                }
            }
        }
        
        if ($verbose_logging) {
            wpsec_debug_log(' WPFort: Main file scan loop completed', 'info');
            wpsec_debug_log(sprintf(' WPFort: Processed %d files, skipped %d, cached %d, errors %d', 
                $processed, $skipped, $cached, $errors), 'error');
        }

        // Always run advanced scanning engines
        $advanced_results = [];
        
        // Only log in verbose mode to reduce noise
        if ($verbose_logging) {
            wpsec_debug_log(' Running advanced scanning engines', 'info');
        }
        
        // Potential malware scanning
        if (isset($advanced_definitions['potential']) && !empty($advanced_definitions['potential'])) {
            // Only log in verbose mode
            if ($verbose_logging) {
                wpsec_debug_log(' Running potential malware scan', 'info');
            }
            $potential_results = wpsec_scan_potential_malware($scan_queue, $advanced_definitions['potential']);
            
            // CRITICAL DIAGNOSTIC: Inspect potential_results before standardization
            wpsec_debug_log(' CRITICAL DIAGNOSTIC: Found ' . count($potential_results) . " total potential malware results before standardization", 'critical');
            
            if (!empty($potential_results)) {
                $advanced_results = array_merge($advanced_results, $potential_results);
            }
            
            if ($verbose_logging) {
                wpsec_debug_log(' Potential malware scan complete: ' . count($potential_results) . " detections", 'info');
            }
        } else if ($verbose_logging) {
            wpsec_debug_log(' Skipping potential malware scan - no definitions available', 'info');
        }
        if (isset($advanced_definitions['htaccess']) && !empty($advanced_definitions['htaccess'])) {
            if ($verbose_logging) {
                wpsec_debug_log(' Running .htaccess scan', 'info');
            }
            $htaccess_results = wpsec_scan_htaccess_files($scan_queue, $advanced_definitions['htaccess']);
            
            // Collect raw htaccess results without standardization
            $advanced_results = array_merge($advanced_results, $htaccess_results);
            
            if ($verbose_logging) {
                wpsec_debug_log(' .htaccess scan complete: ' . count($htaccess_results) . " detections", 'info');
            }
        } else if ($verbose_logging) {
            wpsec_debug_log(' Skipping .htaccess scan - no definitions available', 'info');
        }
        
        // WordPress login file scanning
        if (isset($advanced_definitions['wp_login']) && !empty($advanced_definitions['wp_login'])) {
            if ($verbose_logging) {
                wpsec_debug_log(' Running WordPress login files scan', 'info');
            }
            $login_results = wpsec_scan_login_files($scan_queue, $advanced_definitions['wp_login']);
            
            // Collect raw login results without standardization
            $advanced_results = array_merge($advanced_results, $login_results);
            
            if ($verbose_logging) {
                wpsec_debug_log(' WordPress login files scan complete: ' . count($login_results) . " detections", 'info');
            }
        } else if ($verbose_logging) {
            wpsec_debug_log(' Skipping login files scan - no definitions available', 'info');
        }
        
        // Database scanning with enhanced integration and error handling
        if (false && isset($advanced_definitions['db_scan']) && !empty($advanced_definitions['db_scan'])) {
            // Only log in verbose mode
            if ($verbose_logging) {
                wpsec_debug_log(' WPFort: Running database content scan with enhanced integration', 'info');
            }
            
            try {
                // Use our new generalized function if available
                if (function_exists('wpsec_scan_db_with_advanced_definitions')) {
                    $db_results = wpsec_scan_db_with_advanced_definitions($advanced_definitions);
                } else {
                    // Fallback to original function with memory-safe implementation
                    $db_results = wpsec_scan_database($advanced_definitions['db_scan']);
                }
                
                // Collect raw database results without standardization
                $advanced_results = array_merge($advanced_results, $db_results);
                
                if ($verbose_logging) {
                    wpsec_debug_log(' Database content scan complete: ' . count($db_results) . " detections", 'info');
                }
            } catch (Exception $e) {
                // Always log critical errors, even in non-verbose mode
                wpsec_debug_log(' Critical scan error: ' . $e->getMessage(), 'critical');
                
                if ($verbose_logging) {
                    wpsec_debug_log(' WPFort: Continuing scan despite database error', 'error');
                }
            }
        } else if ($verbose_logging) {
            wpsec_debug_log(' Skipping database scan - no definitions available', 'info');
        }
        
        if ($verbose_logging) {
            wpsec_debug_log(' All advanced scans complete: ' . count($advanced_results) . " total detections", 'info');
        }
        
        // CRITICAL FIX: Apply standardization to ALL results in single pass
        // This prevents multiple standardization calls from overwriting each other
        if (!empty($advanced_results)) {
            wpsec_debug_log(' STANDARDIZATION: Processing ' . count($advanced_results) . " advanced results in single pass", 'info');
            $advanced_results = wpsec_standardize_advanced_detection_results($advanced_results);
            wpsec_debug_log(' STANDARDIZATION: Completed - now have ' . count($advanced_results) . " standardized results", 'info');
        }
        
        // CRITICAL AGGREGATION FIX: Include ALL engine results in final merge
        // $infected_files contains pattern engine detections  
        // $advanced_results contains advanced engine detections
        wpsec_debug_log(' AGGREGATION: Merging results - infected_files: ' . count($infected_files) . ', advanced_results: ' . count($advanced_results), 'info');
        $filtered_results = array_merge($infected_files, $advanced_results);
        wpsec_debug_log(' AGGREGATION: Final merged results count: ' . count($filtered_results), 'info');
        
        // Simplified detection aggregation with robust handling of malformed data
        $aggregated_results = [];
        
        // Flatten and normalize all detection results first
        $normalized_results = [];
        foreach ($filtered_results as $result) {
            if (isset($result['file_path'])) {
                // Handle nested detection arrays (fix malformed data)
                if (isset($result['detections']) && is_array($result['detections'])) {
                    $clean_detections = [];
                    foreach ($result['detections'] as $detection) {
                        if (is_array($detection)) {
                            // If this detection is actually a nested result object, extract it
                            if (isset($detection['file_path']) && isset($detection['detections'])) {
                                // This is a nested result object, merge its detections
                                if (is_array($detection['detections'])) {
                                    $clean_detections = array_merge($clean_detections, $detection['detections']);
                                }
                                // Also update threat score and confidence from nested object
                                if (isset($detection['threat_score'])) {
                                    $result['threat_score'] = max($result['threat_score'] ?? 0, $detection['threat_score']);
                                }
                                if (isset($detection['confidence'])) {
                                    $result['confidence'] = max($result['confidence'] ?? 0, $detection['confidence']);
                                }
                            } else {
                                // This is a normal detection object
                                $clean_detections[] = $detection;
                            }
                        }
                    }
                    $result['detections'] = $clean_detections;
                }
                
                // Group results by file path for aggregation
                $file_path = $result['file_path'];
                if (!isset($normalized_results[$file_path])) {
                    $normalized_results[$file_path] = [];
                }
                $normalized_results[$file_path][] = $result;
            }
        }
        
        // Now aggregate the normalized results grouped by file path
        foreach ($normalized_results as $file_path => $results) {
            if (count($results) > 1) {
                // Multiple results for same file - merge them
                $merged_result = $results[0];
                $all_detections = $merged_result['detections'] ?? [];
                $max_threat_score = $merged_result['threat_score'] ?? 0;
                $max_confidence = $merged_result['confidence'] ?? 0;
                
                for ($i = 1; $i < count($results); $i++) {
                    $all_detections = array_merge($all_detections, $results[$i]['detections'] ?? []);
                    $max_threat_score = max($max_threat_score, $results[$i]['threat_score'] ?? 0);
                    $max_confidence = max($max_confidence, $results[$i]['confidence'] ?? 0);
                }
                
                // Deduplicate detections
                $deduplicated_detections = [];
                foreach ($all_detections as $detection) {
                    $detection_hash = md5(json_encode($detection));
                    if (!isset($deduplicated_detections[$detection_hash])) {
                        $deduplicated_detections[$detection_hash] = $detection;
                    }
                }
                
                $merged_result['detections'] = array_values($deduplicated_detections);
                $merged_result['threat_score'] = $max_threat_score;
                $merged_result['confidence'] = $max_confidence;
                $aggregated_results[] = $merged_result;
            } else {
                // Deduplicate single-file results
                $deduplicated_detections = [];
                foreach ($results[0]['detections'] as $detection) {
                    $detection_hash = md5(json_encode($detection));
                    if (!isset($deduplicated_detections[$detection_hash])) {
                        $deduplicated_detections[$detection_hash] = $detection;
                    }
                }
                $results[0]['detections'] = array_values($deduplicated_detections);
                $aggregated_results[] = $results[0];
            }
        }
        
        //  TEST FILE DEBUGGING: Check for test files after aggregation
        wpsec_debug_log(' TEST FILE DEBUG: Post-aggregation check with ' . count($aggregated_results) . " final results", 'debug');
        
        foreach ($test_files as $test_file) {
            $found_in_final = false;
            foreach ($aggregated_results as $result) { // FIX: iterate over values, not keys
                if (strpos($result['file_path'], $test_file) !== false) {
                    $found_in_final = true;
                    wpsec_debug_log(' TEST FILE FINAL: ' . $test_file . " found in final results with threat_score=" . 
                             ($result['threat_score'] ?? 'none') . ', detections=' . count($result['detections'] ?? []), 'info');
                    break;
                }
            }
            if (!$found_in_final) {
                wpsec_debug_log(' TEST FILE LOST: ' . $test_file . " missing from final aggregated results", 'info');
            }
        }
        
        wpsec_debug_log(' FINAL AGGREGATION: Completed with ' . count($aggregated_results) . " unique infected files", 'info');
        
        // CRITICAL FIX: Apply standardization to ALL results to ensure consistent structure
        if (!empty($infected_files)) {
            wpsec_debug_log(' STANDARDIZATION: Processing infected_files - ' . count($infected_files) . " items", 'info');
            $infected_files = wpsec_standardize_advanced_detection_results($infected_files);
            wpsec_debug_log(' STANDARDIZATION: Completed infected_files - now have ' . count($infected_files) . " standardized results", 'info');
        }
        
        if (!empty($advanced_results)) {
            wpsec_debug_log(' STANDARDIZATION: Processing advanced_results - ' . count($advanced_results) . " items", 'info');
            $advanced_results = wpsec_standardize_advanced_detection_results($advanced_results);
            wpsec_debug_log(' STANDARDIZATION: Completed advanced_results - now have ' . count($advanced_results) . " standardized results", 'info');
        }
        
        // Save final results to WordPress options
        update_option('wpsec_scan_' . $scan_id . '_infected_files', json_encode(array_values($aggregated_results)));
        update_option('wpsec_scan_' . $scan_id . '_infected_count', count($aggregated_results));
        
        // Send scan complete webhook
        wpsec_send_scan_complete_webhook($scan_id);
        
        // Log detailed completion stats - concise by default, detailed in verbose mode
        $duration = microtime(true) - $scan_start_time;
        wpsec_debug_log(sprintf(' Scan completed in %d seconds with %d issues found', $duration, count($aggregated_results)), 'info');
        
        if ($verbose_logging) {
            wpsec_debug_log(sprintf(
                ' Scan details: Processed: %d files | Skipped: %d | Errors: %d | Memory: %.2f MB',
                $processed,
                $skipped,
                $errors,
                $memory_peak / 1024 / 1024
            ), 'error');
        }
        
        // Update scan status to 'completed'
        if ($scan_id) {
            update_option('wpsec_scan_' . $scan_id . '_status', 'completed');
            update_option('wpsec_scan_' . $scan_id . '_end', time());
            update_option('wpsec_scan_' . $scan_id . '_files_scanned', $total_files);
            
            // Ensure final results are saved with proper JSON encoding to the scan-specific option
            $final_results_json = json_encode($aggregated_results, JSON_PRETTY_PRINT);
            if ($final_results_json === false) {
                wpsec_debug_log(' Failed to JSON encode final results', 'info');
                $final_results_json = '[]';
            }
            
            // Save to scan-specific options that the results endpoint expects
            update_option('wpsec_scan_' . $scan_id . '_infected_files', $final_results_json);
            update_option('wpsec_scan_' . $scan_id . '_infected_count', count($aggregated_results));
            
            // Also save to global option for backward compatibility
            update_option('wpsec_infected_files', $final_results_json);
            
            wpsec_debug_log(' Final results saved: ' . count($aggregated_results) . " infected files to scan-specific options", 'info');
        }
        
        return array_values($aggregated_results);
        
    } catch (Exception $e) {
        $error_message = $e->getMessage();
        $trace = $e->getTraceAsString();
        wpsec_debug_log(' Critical scan error: ' . $error_message, 'critical');
        wpsec_debug_log($trace, 'info');
        
        if ($scan_id) {
            // Get current progress for context
            $progress = get_option('wpsec_scan_' . $scan_id . '_progress', 0);
            $last_file = get_option('wpsec_scan_' . $scan_id . '_last_scanned_file', 'Unknown');
            
            // Store comprehensive error information
            $critical_error = [
                'message' => $error_message,
                'trace' => $trace,
                'last_file' => $last_file,
                'progress' => $progress,
                'time' => gmdate('Y-m-d H:i:s'),
                'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2) . 'MB'
            ];
            
            update_option('wpsec_scan_' . $scan_id . '_status', 'error');
            update_option('wpsec_scan_' . $scan_id . '_error', $error_message);
            update_option('wpsec_scan_' . $scan_id . '_critical_error', json_encode($critical_error));
            
            // Send scan failed webhook
            wpsec_send_scan_failed_webhook($scan_id, $error_message);
        }
        
        throw $e;
    }
}

function wpsec_build_scan_queue() {
    global $wpsec_test_files_only;
    
    $scan_queue = [];
    $total_files = 0;
    
    // Debug the global variable state
    wpsec_debug_log('🔍 QUEUE DEBUG: wpsec_test_files_only isset=' . (isset($wpsec_test_files_only) ? 'YES' : 'NO') . 
              ', value=' . (isset($wpsec_test_files_only) ? ($wpsec_test_files_only ? 'TRUE' : 'FALSE') : 'UNSET'), 'debug');
    
    // Check if we're in test-files-only mode
    if (isset($wpsec_test_files_only) && $wpsec_test_files_only) {
        wpsec_debug_log('🧪 TEST FILES ONLY MODE: Building queue with test files only', 'info');
        
        // Define known test files to scan
        $test_files = [
            'i-am-hacking.php',
            'I-am-infecting-with-js.php', 
            'eicar-new.php',
            'test-signature-malware.php',
            'test-anomaly-malware.php',
            'test-heuristic-malware.php',
            'test-pattern-malware.php',
            'test-advanced-potential.php',
            'test-advanced-known.php',
            'test-advanced-htaccess.php',
            'test-advanced-db-scan.php'
        ];
        
        // Search for test files across WordPress directories
        $search_dirs = [
            ABSPATH,
            WP_CONTENT_DIR,
            WP_CONTENT_DIR . '/uploads',
            WP_CONTENT_DIR . '/plugins',
            WP_CONTENT_DIR . '/themes'
        ];
        
        foreach ($search_dirs as $search_dir) {
            if (!file_exists($search_dir)) continue;
            
            foreach ($test_files as $test_file) {
                // Use recursive search to find test files
                $found_files = wpsec_find_test_files($search_dir, $test_file);
                foreach ($found_files as $file_path) {
                    if (!array_key_exists($file_path, $scan_queue)) {
                        $scan_queue[$file_path] = 'high';  // Use file path as key, priority as value
                        $total_files++;
                        wpsec_debug_log('🧪 TEST FILE FOUND: Added ' . $file_path . ' to test scan queue', 'info');
                    }
                }
            }
        }
        
        wpsec_debug_log('🧪 TEST FILES ONLY: Queue built with ' . $total_files . " test files", 'info');
        return ['queue' => $scan_queue, 'total_files' => $total_files];
    }
    
    // High priority directories (wp-content/uploads, wp-content/plugins, wp-content/themes)
    $high_priority = [
        WP_CONTENT_DIR . '/uploads',
        WP_CONTENT_DIR . '/plugins',
        WP_CONTENT_DIR . '/themes'
    ];

    // Medium priority (wp-content, wp-includes, wp-admin)
    $medium_priority = [
        WP_CONTENT_DIR,
        ABSPATH . 'wp-includes',
        ABSPATH . 'wp-admin'
    ];

    // Low priority (everything else in WordPress root)
    $low_priority = [ABSPATH];
    
    // Debug log the priority directories
    if (isset($_REQUEST['verbose_logging']) && $_REQUEST['verbose_logging'] == 1) {
        wpsec_debug_log('[INFO] WPFort: High priority scan directories: ' . json_encode($high_priority), 'info');
        wpsec_debug_log('[INFO] WPFort: Medium priority scan directories: ' . json_encode($medium_priority), 'info');
        wpsec_debug_log('[INFO] WPFort: Low priority scan directories: ' . json_encode($low_priority), 'info');
    }

    // Process high priority directories first
    foreach ($high_priority as $dir) {
        if (file_exists($dir)) {
            $files = wpsec_get_directory_files($dir);
            
            // DIAGNOSTIC: Check for test malware files in high priority directories
            if (defined('WPSEC_TRACE_TEST_FILES')) {
                foreach ($files as $file_path) {
                    if (wpsec_is_test_malware_file($file_path)) {
                        global $wpsec_test_file_tracking;
                        $wpsec_test_file_tracking['scan_queue'][] = $file_path;
                        wpsec_debug_log(' TRACE: Test malware file added to scan queue (HIGH priority): ' . $file_path, 'info');
                    }
                }
            }
            
            $scan_queue = array_merge($scan_queue, array_fill_keys($files, 'high'));
            $total_files += count($files);
            
            if (isset($_REQUEST['verbose_logging']) && $_REQUEST['verbose_logging'] == 1) {
                wpsec_debug_log('[INFO] WPFort: Added ' . count($files) . " high priority files from " . $dir, 'info');
            }
        }
    }

    // Process medium priority - don't exclude wp-admin and wp-includes
    foreach ($medium_priority as $dir) {
        if (file_exists($dir)) {
            // Don't exclude critical system directories
            $exclusions = [];
            foreach ($high_priority as $exclude_dir) {
                // Only add to exclusions if not a critical directory
                if (strpos($exclude_dir, ABSPATH . 'wp-admin') !== 0 && 
                    strpos($exclude_dir, ABSPATH . 'wp-includes') !== 0) {
                    $exclusions[] = $exclude_dir;
                }
            }
            
            $files = wpsec_get_directory_files($dir, $exclusions);
            $scan_queue = array_merge($scan_queue, array_fill_keys($files, 'medium'));
            $total_files += count($files);
            
            if (isset($_REQUEST['verbose_logging']) && $_REQUEST['verbose_logging'] == 1) {
                wpsec_debug_log('[INFO] WPFort: Added ' . count($files) . " medium priority files from " . $dir, 'info');
            }
        }
    }

    // Process low priority - ensure wp-admin and wp-includes are not excluded
    foreach ($low_priority as $dir) {
        if (file_exists($dir)) {
            // Create exclusions list without wp-admin and wp-includes
            $exclusions = [];
            $all_dirs = array_merge($high_priority, $medium_priority);
            foreach ($all_dirs as $exclude) {
                // Only add to exclusions if not a critical directory
                if (strpos($exclude, ABSPATH . 'wp-admin') !== 0 && 
                    strpos($exclude, ABSPATH . 'wp-includes') !== 0) {
                    $exclusions[] = $exclude;
                }
            }
            
            $files = wpsec_get_directory_files($dir, $exclusions);
            $scan_queue = array_merge($scan_queue, array_fill_keys($files, 'low'));
            $total_files += count($files);
            
            if (isset($_REQUEST['verbose_logging']) && $_REQUEST['verbose_logging'] == 1) {
                wpsec_debug_log('[INFO] WPFort: Added ' . count($files) . " low priority files from " . $dir, 'info');
            }
        }
    }

    return [
        'queue' => $scan_queue,
        'total_files' => $total_files
    ];
}

// Helper function to recursively find test files
function wpsec_find_test_files($directory, $filename) {
    $found_files = [];
    
    if (!is_dir($directory) || !is_readable($directory)) {
        return $found_files;
    }
    
    try {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::LEAVES_ONLY
        );
        
        foreach ($iterator as $file) {
            if ($file->isFile() && $file->getFilename() === $filename) {
                $found_files[] = $file->getRealPath();
            }
        }
    } catch (Exception $e) {
        wpsec_debug_log('🧪 TEST FILE SEARCH ERROR: ' . $e->getMessage() . ' in directory: ' . $directory, 'error');
    }
    
    return $found_files;
}

function wpsec_get_directory_files($dir, $exclude_dirs = []) {
    $files = [];
    // Include all potential security-relevant file types including htaccess
    $allowed_extensions = ['php', 'js', 'html', 'htm', 'phtml', 'inc', 'tpl', 'txt', 'css', 'json', 'xml', 'svg', 'htaccess'];
    
    // Verbose logging for debugging
    $verbose_logging = isset($_REQUEST['verbose_logging']) && $_REQUEST['verbose_logging'] == 1;
    if ($verbose_logging) {
        wpsec_debug_log('[INFO] WPFort: Scanning directory: ' . $dir, 'info');
        if (!empty($exclude_dirs)) {
            wpsec_debug_log('[INFO] WPFort: Excluding directories: ' . json_encode($exclude_dirs), 'info');
        }
    }
    
    try {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($iterator as $file) {
            // Skip if it's a directory
            if ($file->isDir()) {
                continue;
            }

            $path = $file->getPathname();
            $should_exclude = false;
            
            // Skip files that have previously caused stalls
            global $excluded_stall_files;
            if (!empty($excluded_stall_files) && in_array($path, $excluded_stall_files)) {
                if ($verbose_logging) {
                    wpsec_debug_log('[INFO] WPFort: Skipping known problematic file: ' . $path, 'info');
                }
                continue;
            }
            
            // Handle special directories: never exclude wp-admin or wp-includes
            $is_core_directory = false;
            $core_dirs = [ABSPATH . 'wp-admin', ABSPATH . 'wp-includes'];
            foreach ($core_dirs as $core_dir) {
                if (strpos($path, $core_dir) === 0) {
                    $is_core_directory = true;
                    break;
                }
            }
            
            // Only apply exclusions if not in a core directory
            if (!$is_core_directory) {
                // Skip excluded directories, but only if the path is actually in a subdirectory
                foreach ($exclude_dirs as $exclude) {
                    // Skip if path is exactly the same as the excluded directory (would be caught by another scan)
                    if ($path === $exclude) {
                        $should_exclude = true;
                        break;
                    }
                    
                    // Skip if path is in a subdirectory of the excluded directory
                    if (strpos($path, $exclude . '/') === 0 || strpos($path, $exclude . '\\') === 0) {
                        $should_exclude = true;
                        break;
                    }
                }
            }
            
            // For security plugins, always scan files with potentially executable extensions
            $potentially_executable = ['php', 'js', 'html', 'htm', 'phtml', 'php4', 'php5', 'php7', 'phar', 'inc', 'pht', 'shtml', 'cgi', 'pl', 'py', 'sh', 'asp', 'aspx', 'jsp', 'jspx'];
            $file_extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
            $is_executable = in_array($file_extension, $potentially_executable);
            
            // SECURITY FIRST: Never exclude potentially executable files that could contain malware
            if ($is_executable) {
                if ($verbose_logging && $should_exclude) {
                    wpsec_debug_log(' WPFort: Including potentially executable file regardless of path exclusion: ' . $path, 'info');
                }
                $files[] = $path;
            }
            // Only apply exclusion for non-executable files
            else if ($should_exclude) {
                if ($verbose_logging) {
                    wpsec_debug_log('[INFO] WPFort: Excluding non-executable file from scan: ' . $path, 'info');
                }
                continue;
            }

            // Special handling for .htaccess files (no extension)
            $filename = $file->getFilename();
            if ($filename === '.htaccess') {
                $files[] = $path;
                if ($verbose_logging) {
                    wpsec_debug_log('[INFO] WPFort: Adding .htaccess file to scan queue: ' . $path, 'info');
                }
            } else {
                // Check extension for other files
                $ext = strtolower($file->getExtension());
                if (in_array($ext, $allowed_extensions)) {
                    $files[] = $path;
                    if ($verbose_logging) {
                        wpsec_debug_log('[INFO] WPFort: Adding file to scan queue: ' . $path, 'info');
                    }
                }
            }
        }
    } catch (Exception $e) {
        wpsec_debug_log('[ERROR]  scanning directory ' . $dir . ': ' . $e->getMessage(), 'error');
    }

    return $files;
}

function wpsec_scan_single_file($file_path, $signatures, $patterns, $priority) {
    // Check if this is a test file for targeted debugging
    $is_test_file = (strpos($file_path, 'test-') !== false || 
                    strpos($file_path, 'i-am-') !== false || 
                    strpos($file_path, 'eicar') !== false ||
                    strpos($file_path, 'malware') !== false);
    
    // Only log for test files or critical errors - remove excessive logging
    if ($is_test_file) {
        wpsec_debug_log(" TEST FILE SCAN: Starting scan of test file: " . basename($file_path), 'info');
    }
    
    // Get file extension and context
    $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
    $context = wpsec_get_file_context($file_path);
    $file_size = file_exists($file_path) ? filesize($file_path) : 0;
    
    // Only log context for test files
    if ($is_test_file) {
        wpsec_debug_log(" SCAN START: Processing file $file_path", 'info');
        wpsec_debug_log("   - Extension: $ext", 'info');
        wpsec_debug_log("   - Context: " . json_encode($context), 'info');
        wpsec_debug_log("   - Is test file: YES", 'info');
    }
    
    // Ignore directories, only scan individual files
    if (is_dir($file_path)) {
        if ($is_test_file) {
            wpsec_debug_log(' ERROR: Test file is a directory, not scanning: ' . $file_path, 'error');
        }
        return [];
    }
    $results = [];
    // Skip certain file types
    $skip_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'ico', 'mp4', 'webm', 'mp3', 'wav', 'pdf', 'doc', 'docx', 'ttf', 'woff', 'woff2', 'eot', 'zip', 'gz', 'tar', 'rar'];
    if (in_array($ext, $skip_extensions)) {
        return $results;
    }

    // Check if file is readable
    $is_readable = is_readable($file_path);
    
    // If not directly readable, try WP_Filesystem
    if (!$is_readable) {
        // Initialize WP_Filesystem if needed
        if (!function_exists('WP_Filesystem')) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }
        
        // Try to initialize with direct method first
        $wp_filesystem = null;
        if (WP_Filesystem(false, false, true)) {
            global $wp_filesystem;
            if ($wp_filesystem && $wp_filesystem->exists($file_path)) {
                $is_readable = true;
            }
        }
        
        // If still not readable, log and skip
        if (!$is_readable) {
            global $wpsec_verbose_logging;
            if ($wpsec_verbose_logging) {
                wpsec_debug_log(" File not readable: $file_path", 'info');
            }
            return $results;
        }
    }

    // Check file size - skip files over 10MB to prevent memory issues
    $file_size = @filesize($file_path);
    
    // If direct access fails, try WP_Filesystem
    if ($file_size === false) {
        // WP_Filesystem should already be initialized from the readability check
        global $wp_filesystem;
        if ($wp_filesystem && $wp_filesystem->exists($file_path)) {
            $file_size = $wp_filesystem->size($file_path);
        }
    }
    
    // Skip if still can't get size or file is too large
    if ($file_size === false || $file_size > 10 * 1024 * 1024) {
        global $wpsec_verbose_logging;
        if ($wpsec_verbose_logging) {
            wpsec_debug_log(" Skipping large or unreadable file ($file_size bytes): $file_path", 'info');
        }
        return $results;
    }

    try {
        // Get file context
        $context = wpsec_get_file_context($file_path);
        
        // Check if this is a deep scan for logging filtered files
        $is_deep_scan = get_option('wpsec_deep_scan_mode', false);
        
        // COMPREHENSIVE DEBUG: Log every file being scanned and which engines will run
        $is_test_file = (stripos($file_path, 'i-am-hacking') !== false || 
                        stripos($file_path, 'I-am-infecting') !== false || 
                        stripos($file_path, 'eicar') !== false);
        
        if ($is_test_file || $is_deep_scan) {
            wpsec_debug_log(" SCAN START: Processing file $file_path", 'info');
            wpsec_debug_log("   - Extension: $ext", 'info');
            wpsec_debug_log("   - Context: " . json_encode($context), 'info');
            wpsec_debug_log("   - Is test file: " . ($is_test_file ? 'YES' : 'NO'), 'info');
        }
        
        // Skip files that are known to be safe (only specific WordPress core files)
        if ($context['risk_level'] === 'very_low') {
            if ($is_deep_scan) {
                wpsec_debug_log(" DEEP SCAN FILTER: Skipping file with very low risk level: $file_path (context: " . $context['type'] . ")", 'info');
            }
            return $results;
        }
        
        // Skip files that are cached as safe (hash-based verification)
        if (!$is_deep_scan && function_exists('wpsec_is_file_cached_as_safe') && wpsec_is_file_cached_as_safe($file_path)) {
            if ($is_deep_scan) {
                wpsec_debug_log(" DEEP SCAN FILTER: Skipping cached safe file: $file_path", 'info');
            }
            wpsec_log("Skipping cached safe file: $file_path", 'debug');
            return $results;
        }
        
        // Run signature checks with error handling
        try {
            if ($is_test_file || $is_deep_scan) {
                wpsec_debug_log(" ENGINE: Running signature engine on $file_path", 'info');
            }
            $signature_results = wpsec_check_file_signatures($file_path, $signatures);
            if (!empty($signature_results)) {
                $results = array_merge($results, $signature_results);
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log(" SIGNATURE ENGINE: Found " . count($signature_results) . " detections in $file_path", 'info');
                    wpsec_debug_log("   - Signature results: " . json_encode($signature_results, JSON_UNESCAPED_SLASHES), 'info');
                }
            } else {
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log(" SIGNATURE ENGINE: No detections in $file_path", 'info');
                }
            }
        } catch (Exception $e) {
            wpsec_debug_log(" Error during signature check for $file_path: " . $e->getMessage(), 'error');
        }

        // Run pattern checks with error handling
        try {
            if ($is_test_file || $is_deep_scan) {
                wpsec_debug_log(" ENGINE: Running pattern engine on $file_path", 'info');
            }
            $pattern_results = wpsec_check_file_patterns($file_path, $patterns, $ext);
            if (!empty($pattern_results)) {
                $results = array_merge($results, $pattern_results);
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log(" PATTERN ENGINE: Found " . count($pattern_results) . " detections in $file_path", 'info');
                    wpsec_debug_log("   - Pattern results: " . json_encode($pattern_results, JSON_UNESCAPED_SLASHES), 'info');
                }
            } else {
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log(" PATTERN ENGINE: No detections in $file_path", 'info');
                }
            }
        } catch (Exception $e) {
            wpsec_debug_log(" Error during pattern check for $file_path: " . $e->getMessage(), 'error');
        }

        // Run heuristic analysis on PHP files
        if ($ext === 'php') {
            try {
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log(" ENGINE: Running heuristic engine on $file_path", 'info');
                }
                $heuristic_result = wpsec_check_file_heuristics($file_path, $ext);
                
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log("  DEBUG: Heuristic result for $file_path: " . print_r($heuristic_result, true), 'debug');
                    wpsec_debug_log("  DEBUG: Heuristic empty check: " . (empty($heuristic_result) ? 'TRUE' : 'FALSE'), 'debug');
                    wpsec_debug_log("  DEBUG: Heuristic is_array: " . (is_array($heuristic_result) ? 'TRUE' : 'FALSE'), 'debug');
                    if (is_array($heuristic_result) && !empty($heuristic_result)) {
                        wpsec_debug_log("  DEBUG: Heuristic array count: " . count($heuristic_result), 'debug');
                        wpsec_debug_log("  DEBUG: Heuristic first element: " . print_r($heuristic_result[0] ?? 'N/A', true), 'debug');
                        if (isset($heuristic_result[0])) {
                            wpsec_debug_log("  DEBUG: First element has 'type': " . (isset($heuristic_result[0]['type']) ? $heuristic_result[0]['type'] : 'NO'), 'debug');
                        }
                    }
                }
                
                if ($heuristic_result !== null && $heuristic_result !== false) {
                    if ($is_test_file || $is_deep_scan) {
                        wpsec_debug_log("  CRITICAL FIX: Heuristic normalization starting for $file_path", 'critical');
                    }
                    
                    // CRITICAL FIX: Heuristic engine returns array of detection objects
                    // Convert to standardized format before adding to results
                    if (is_array($heuristic_result) && !empty($heuristic_result)) {
                        if ($is_test_file || $is_deep_scan) {
                            wpsec_debug_log("  HEURISTIC FIX: Processing non-empty array result", 'info');
                        }
                        
                        // Check if this is an array of detection objects
                        if (isset($heuristic_result[0]) && is_array($heuristic_result[0]) && isset($heuristic_result[0]['type'])) {
                            // This is an array of detection objects - convert to file-level result
                            if ($is_test_file || $is_deep_scan) {
                                wpsec_debug_log("  HEURISTIC FIX: Converting array of detection objects", 'info');
                            }
                            $heuristic_file_result = [
                                'file_path' => $file_path,
                                'detections' => $heuristic_result,
                                'context' => $context,
                                'scan_time' => time(),
                                'file_size' => $file_size,
                                'extension' => $ext
                            ];
                            $results[] = $heuristic_file_result;
                            if ($is_test_file || $is_deep_scan) {
                                wpsec_debug_log("  HEURISTIC ENGINE: Found detection in $file_path", 'info');
                                wpsec_debug_log("   - Heuristic result: " . json_encode($heuristic_file_result, JSON_UNESCAPED_SLASHES), 'info');
                            }
                        } elseif (isset($heuristic_result['type'])) {
                            // This is a single detection object - wrap in array
                            if ($is_test_file || $is_deep_scan) {
                                wpsec_debug_log("  HEURISTIC FIX: Converting single detection object", 'info');
                            }
                            $heuristic_file_result = [
                                'file_path' => $file_path,
                                'detections' => [$heuristic_result],
                                'context' => $context,
                                'scan_time' => time(),
                                'file_size' => $file_size,
                                'extension' => $ext
                            ];
                            $results[] = $heuristic_file_result;
                            if ($is_test_file || $is_deep_scan) {
                                wpsec_debug_log("  HEURISTIC ENGINE: Found detection in $file_path", 'info');
                                wpsec_debug_log("   - Heuristic result: " . json_encode($heuristic_file_result, JSON_UNESCAPED_SLASHES), 'info');
                            }
                        } else {
                            // Fallback: add as-is if format is unexpected but not empty
                            if ($is_test_file || $is_deep_scan) {
                                wpsec_debug_log("  HEURISTIC FIX: Using fallback format", 'info');
                            }
                            $results[] = $heuristic_result;
                            if ($is_test_file || $is_deep_scan) {
                                wpsec_debug_log("  HEURISTIC ENGINE: Found detection in $file_path (fallback)", 'info');
                                wpsec_debug_log("   - Heuristic result: " . json_encode($heuristic_result, JSON_UNESCAPED_SLASHES), 'info');
                            }
                        }
                    } else {
                        if ($is_test_file || $is_deep_scan) {
                            wpsec_debug_log("  HEURISTIC ENGINE: No detections in $file_path (empty result)", 'info');
                        }
                    }
                } else {
                    if ($is_test_file || $is_deep_scan) {
                        wpsec_debug_log("  HEURISTIC ENGINE: No detections in $file_path (null/false result)", 'info');
                    }
                }
            } catch (Exception $e) {
                wpsec_debug_log(" Error during heuristic check for $file_path: " . $e->getMessage(), 'error');
            }
        }

        // Run anomaly checks
        try {
            if ($is_test_file || $is_deep_scan) {
                wpsec_debug_log(" ENGINE: Running anomaly engine on $file_path", 'info');
            }
            $anomaly_result = wpsec_check_file_anomalies($file_path, $ext);
            if ($is_test_file || $is_deep_scan) {
                wpsec_debug_log("  DEBUG: Anomaly result for $file_path: " . print_r($anomaly_result, true), 'debug');
                wpsec_debug_log("  DEBUG: Anomaly empty check: " . (empty($anomaly_result) ? 'TRUE' : 'FALSE'), 'debug');
                wpsec_debug_log("  DEBUG: Anomaly is_array: " . (is_array($anomaly_result) ? 'TRUE' : 'FALSE'), 'debug');
                if (is_array($anomaly_result) && !empty($anomaly_result)) {
                    wpsec_debug_log("  DEBUG: Anomaly array count: " . count($anomaly_result), 'debug');
                    wpsec_debug_log("  DEBUG: Anomaly first element: " . print_r($anomaly_result[0] ?? 'N/A', true), 'debug');
                    if (isset($anomaly_result[0])) {
                        wpsec_debug_log("  DEBUG: First element has 'type': " . (isset($anomaly_result[0]['type']) ? $anomaly_result[0]['type'] : 'NO'), 'debug');
                    }
                }
            }
            if ($anomaly_result !== null && $anomaly_result !== false) {
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log("  CRITICAL FIX: Anomaly normalization starting for $file_path", 'critical');
                }
                // CRITICAL FIX: Anomaly engine returns array of detection objects
                // Convert to standardized format before adding to results
                if (is_array($anomaly_result) && !empty($anomaly_result)) {
                    if ($is_test_file || $is_deep_scan) {
                        wpsec_debug_log("  ANOMALY FIX: Processing non-empty array result", 'info');
                    }
                    
                    // Check if this is an array of detection objects
                    if (isset($anomaly_result[0]) && is_array($anomaly_result[0]) && isset($anomaly_result[0]['type'])) {
                        // This is an array of detection objects - convert to file-level result
                        if ($is_test_file || $is_deep_scan) {
                            wpsec_debug_log("  ANOMALY FIX: Converting array of detection objects", 'info');
                        }
                        $anomaly_file_result = [
                            'file_path' => $file_path,
                            'detections' => $anomaly_result,
                            'context' => $context,
                            'scan_time' => time(),
                            'file_size' => $file_size,
                            'extension' => $ext
                        ];
                        $results[] = $anomaly_file_result;
                        if ($is_test_file || $is_deep_scan) {
                            wpsec_debug_log("  ANOMALY ENGINE: Found detection in $file_path", 'info');
                            wpsec_debug_log("   - Anomaly result: " . json_encode($anomaly_file_result, JSON_UNESCAPED_SLASHES), 'info');
                        }
                    } elseif (isset($anomaly_result['type'])) {
                        // This is a single detection object - wrap in array
                        if ($is_test_file || $is_deep_scan) {
                            wpsec_debug_log("  ANOMALY FIX: Converting single detection object", 'info');
                        }
                        $anomaly_file_result = [
                            'file_path' => $file_path,
                            'detections' => [$anomaly_result],
                            'context' => $context,
                            'scan_time' => time(),
                            'file_size' => $file_size,
                            'extension' => $ext
                        ];
                        $results[] = $anomaly_file_result;
                        if ($is_test_file || $is_deep_scan) {
                            wpsec_debug_log("  ANOMALY ENGINE: Found detection in $file_path", 'info');
                            wpsec_debug_log("   - Anomaly result: " . json_encode($anomaly_file_result, JSON_UNESCAPED_SLASHES), 'info');
                        }
                    } else {
                        // Fallback: add as-is if format is unexpected but not empty
                        if ($is_test_file || $is_deep_scan) {
                            wpsec_debug_log("  ANOMALY FIX: Using fallback format", 'info');
                        }
                        $results[] = $anomaly_result;
                        if ($is_test_file || $is_deep_scan) {
                            wpsec_debug_log("  ANOMALY ENGINE: Found detection in $file_path (fallback)", 'info');
                            wpsec_debug_log("   - Anomaly result: " . json_encode($anomaly_result, JSON_UNESCAPED_SLASHES), 'info');
                        }
                    }
                } else {
                    if ($is_test_file || $is_deep_scan) {
                        wpsec_debug_log("  ANOMALY ENGINE: No detections in $file_path (empty result)", 'info');
                    }
                }
            } else {
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log("  ANOMALY ENGINE: No detections in $file_path (null/false result)", 'info');
                }
            }
        } catch (Exception $e) {
            wpsec_debug_log(" Error during anomaly check for $file_path: " . $e->getMessage(), 'error');
        }

        // Run comprehensive advanced definitions check
        try {
            // Get advanced definitions globally
            global $wpsec_advanced_definitions;
            
            // Load advanced definitions if not already loaded
            if (empty($wpsec_advanced_definitions) && function_exists('wpsec_load_advanced_definitions')) {
                $wpsec_advanced_definitions = wpsec_load_advanced_definitions();
            }
            
            // Only check if we have definitions and the scan function
            if (!empty($wpsec_advanced_definitions) && function_exists('wpsec_scan_file_with_advanced_definitions')) {
                global $wpsec_verbose_logging;
                if (!empty($wpsec_verbose_logging)) {
                    wpsec_debug_log(" Running comprehensive advanced definitions scan for: $file_path", 'info');
                }
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log(" ENGINE: Running advanced engine on $file_path", 'info');
                }
                $advanced_result = wpsec_scan_file_with_advanced_definitions($file_path, $wpsec_advanced_definitions);
                if (!empty($advanced_result)) {
                    $results[] = $advanced_result;
                    if ($is_test_file || $is_deep_scan) {
                        wpsec_debug_log(" ADVANCED ENGINE: Found detection in $file_path", 'info');
                        wpsec_debug_log("   - Advanced result: " . json_encode($advanced_result, JSON_UNESCAPED_SLASHES), 'info');
                    }
                } else {
                    if ($is_test_file || $is_deep_scan) {
                        wpsec_debug_log(" ADVANCED ENGINE: No detections in $file_path", 'info');
                    }
                }
            }
        } catch (Exception $e) {
            wpsec_debug_log(" Critical error scanning file $file_path: " . $e->getMessage(), 'critical');
            wpsec_debug_log($e->getTraceAsString(), 'info');
        }
        
        // CRITICAL: Apply standardization to ensure consistent structure across all engines
        // Instead of creating temp_result with only pattern detections, 
        // we need to aggregate ALL results including heuristic and anomaly
        
        // Add comprehensive logging to trace engine types
        if ($is_test_file || $is_deep_scan) {
            wpsec_debug_log("🔄 AGGREGATION START: Processing " . count($results) . " raw results for $file_path", 'info');
            foreach ($results as $idx => $result) {
                $result_type = isset($result['type']) ? $result['type'] : 'NO_TYPE';
                $has_detections = isset($result['detections']) ? count($result['detections']) : 'NO_DETECTIONS';
                wpsec_debug_log("   Result $idx: type='$result_type', detections=$has_detections", 'info');
                if (isset($result['detections']) && is_array($result['detections'])) {
                    foreach ($result['detections'] as $det_idx => $detection) {
                        $det_type = isset($detection['type']) ? $detection['type'] : 'NO_TYPE';
                        wpsec_debug_log("     Detection $det_idx: type='$det_type'", 'info');
                    }
                }
            }
        }
        
        // First, add pattern detections to results if any exist
        if (!empty($results)) {
            // Filter results for this specific file only
            $file_specific_results = array_filter($results, function($result) use ($file_path) {
                return isset($result['file_path']) && $result['file_path'] === $file_path;
            });
            
            if (!empty($file_specific_results)) {
                // CRITICAL FIX: Don't use standardization function that only handles "potential" types
                // Instead, directly aggregate all engine results preserving their types
                
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log("🔧 AGGREGATION FIX: Processing " . count($file_specific_results) . " results for $file_path WITHOUT standardization", 'info');
                }
                
                // Merge all detections from all engines for this file
                $all_detections = [];
                $max_threat_score = 0;
                $max_confidence = 0;
                
                foreach ($file_specific_results as $result) {
                    if ($is_test_file || $is_deep_scan) {
                        $result_type = isset($result['type']) ? $result['type'] : 'NO_TYPE';
                        wpsec_debug_log("   Processing result with type: $result_type", 'info');
                    }
                    
                    if (isset($result['detections']) && is_array($result['detections'])) {
                        foreach ($result['detections'] as $detection) {
                            // CRITICAL FIX: Preserve engine type information in each detection
                            if (!isset($detection['engine_type']) && isset($result['type'])) {
                                $detection['engine_type'] = $result['type'];
                            }
                            if (!isset($detection['engine_type']) && isset($result['engine_type'])) {
                                $detection['engine_type'] = $result['engine_type'];
                            }
                            
                            $all_detections[] = $detection;
                            
                            // Track max scores
                            if (isset($detection['threat_score'])) {
                                $max_threat_score = max($max_threat_score, $detection['threat_score']);
                            }
                            if (isset($detection['confidence'])) {
                                $max_confidence = max($max_confidence, $detection['confidence']);
                            }
                        }
                    } elseif (isset($result['type'])) {
                        // Handle single detection objects
                        $detection = $result;
                        if (!isset($detection['engine_type'])) {
                            $detection['engine_type'] = $result['type'];
                        }
                        $all_detections[] = $detection;
                        
                        if (isset($detection['threat_score'])) {
                            $max_threat_score = max($max_threat_score, $detection['threat_score']);
                        }
                        if (isset($detection['confidence'])) {
                            $max_confidence = max($max_confidence, $detection['confidence']);
                        }
                    }
                }
                
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log("🎯 AGGREGATION RESULT: Merged " . count($all_detections) . " total detections", 'info');
                    foreach ($all_detections as $idx => $detection) {
                        $det_type = isset($detection['type']) ? $detection['type'] : 'NO_TYPE';
                        wpsec_debug_log("   Final detection $idx: type='$det_type'", 'info');
                    }
                }
                
                // Create final aggregated result with all detections
                
                // CRITICAL FIX: Calculate proper threat score using all detections
                $calculated_scores = wpsec_calculate_threat_score($all_detections, $file_path, $context);
                $calculated_threat_score = $calculated_scores['score'];
                $calculated_confidence = $calculated_scores['confidence'];
                
                // Use calculated scores, but still respect higher individual scores if present
                $final_threat_score = max($max_threat_score, $calculated_threat_score);
                $final_confidence = max($max_confidence, $calculated_confidence);
                
                $final_result = [
                    'file_path' => $file_path,
                    'detections' => $all_detections,
                    'context' => $context,
                    'scan_time' => time(),
                    'file_size' => $file_size,
                    'extension' => $ext,
                    'threat_score' => $final_threat_score,
                    'confidence' => $final_confidence
                ];
                
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log(" FINAL AGGREGATION: File $file_path has " . count($all_detections) . " total detections from all engines", 'info');
                    wpsec_debug_log(" FINAL AGGREGATION: Calculated threat_score=$calculated_threat_score, final=$final_threat_score, confidence=$final_confidence", 'info');
                }
                
                // Apply filtering logic based on threat scores and confidence levels
                $threat_score = $final_threat_score;
                $confidence = $final_confidence;
                
                // Apply filtering thresholds: (threat_score >= 2 && confidence >= 40) || (threat_score >= 4) || (confidence >= 80)
                $meets_threshold = ($threat_score >= 2 && $confidence >= 40) || 
                                   ($threat_score >= 4) || 
                                   ($confidence >= 80);
                
                if ($meets_threshold) {
                    $final_result['infected'] = true;
                    
                    if ($is_deep_scan) {
                        wpsec_debug_log(" DEEP SCAN: File meets threshold and marked as infected - $file_path", 'info');
                        wpsec_debug_log("   - Threshold check: threat=$threat_score, confidence=$confidence", 'info');
                    }
                    
                    // Update cache with infected file result
                    if (function_exists('wpsec_update_file_hash_cache')) {
                        $scan_result = [
                            'safe' => false,
                            'infected' => true,
                            'detections' => $all_detections,
                            'threat_score' => $threat_score,
                            'confidence' => $confidence
                        ];
                        wpsec_update_file_hash_cache($file_path, $scan_result);
                    }
                    
                    return $final_result;
                } else {
                    if ($is_deep_scan) {
                        wpsec_debug_log(" DEEP SCAN: File does not meet threshold - $file_path", 'info');
                        wpsec_debug_log("   - Threshold check: threat=$threat_score, confidence=$confidence", 'info');
                    }
                    
                    // Update cache with safe file result
                    if (function_exists('wpsec_update_file_hash_cache')) {
                        $scan_result = [
                            'safe' => true,
                            'infected' => false,
                            'detections' => [],
                            'threat_score' => $threat_score,
                            'confidence' => $confidence
                        ];
                        wpsec_update_file_hash_cache($file_path, $scan_result);
                    }
                    
                    return null; // File doesn't meet infection threshold
                }
            } else {
                if ($is_test_file || $is_deep_scan) {
                    wpsec_debug_log(" STANDARDIZATION: No file-specific results found for $file_path", 'info');
                }
            }
        } else {
            if ($is_test_file || $is_deep_scan) {
                wpsec_debug_log(" STANDARDIZATION: No results array to process for $file_path", 'info');
            }
        }
    } catch (Exception $e) {
        wpsec_debug_log(" Critical error scanning file $file_path: " . $e->getMessage(), 'critical');
        wpsec_debug_log($e->getTraceAsString(), 'info');
    }
    
    // If we reach here, file had no detections or was not processed - cache as safe
    if (empty($results) && function_exists('wpsec_update_file_hash_cache')) {
        $scan_result = [
            'safe' => true,
            'infected' => false,
            'detections' => [],
            'threat_score' => 0,
            'confidence' => 0,
            'filtered_reason' => 'no_detections'
        ];
        wpsec_update_file_hash_cache($file_path, $scan_result);
        
        $is_deep_scan = get_option('wpsec_deep_scan_mode', false);
        if ($is_deep_scan) {
            wpsec_debug_log(" DEEP SCAN: File cached as safe (no detections) - $file_path", 'info');
        }
    }
    
    return $results;
}

function wpsec_is_known_legitimate_plugin($file_path) {
    // Extract plugin directory name
    if (preg_match('!/wp-content/plugins/([^/]+)/!', $file_path, $matches)) {
        $plugin_name = $matches[1];
        
        // Check if we have a plugin.php file with a valid header
        $main_file = dirname(WP_CONTENT_DIR) . '/wp-content/plugins/' . $plugin_name . '/' . $plugin_name . '.php';
        if (!file_exists($main_file)) {
            $main_file = dirname(WP_CONTENT_DIR) . '/wp-content/plugins/' . $plugin_name . '/index.php';
        }
        
        if (file_exists($main_file)) {
            $content = file_get_contents($main_file, false, null, 0, 8192);
            
            // Look for plugin header and check for standard WordPress plugin repository references
            if (preg_match('!/\*\s*Plugin Name:.*?(wordpress\.org|wp\.org|WordPress Plugin Repository).*?\*/!s', $content)) {
                return true;
            }
            
            // Check for recognized plugin author names
            if (preg_match('!Author:\s*(Automattic|Yoast|WooCommerce|Elegant Themes|WPML|Gravity Forms)!i', $content)) {
                return true;
            }
        }
    }
    
    return false;
}

function wpsec_calculate_threat_score($detection_results, $file_path = '', $file_context = []) {
    $base_score = 0;
    $detection_count = count($detection_results);
    $engine_scores = [];
    
    if ($detection_count === 0) {
        return ['score' => 0, 'severity' => 'low', 'confidence' => 0];
    }
    
    // Enhanced engine-specific scoring with more aggressive base scores
    foreach ($detection_results as $result) {
        $engine_type = $result['engine_type'] ?? $result['type'] ?? 'unknown';
        $engine_score = 0;
        
        switch ($engine_type) {
            case 'heuristic':
                // Heuristic engine uses numeric scores (0-10)
                if (isset($result['score'])) {
                    $heuristic_score = floatval($result['score']);
                    // More aggressive scaling: heuristic score (0-10) to threat score (0-6)
                    $engine_score = min(6, $heuristic_score * 0.6);
                } elseif (isset($result['severity'])) {
                    $engine_score = wpsec_severity_to_score($result['severity']) + 1; // +1 bonus for heuristic
                } else {
                    $engine_score = 3; // Higher default for heuristic detections
                }
                break;
                
            case 'signatures':
            case 'signature':
                // Signature matches are high confidence - increased base score
                $engine_score = 5; // Increased from 4
                // Check for specific high-risk signatures
                if (isset($result['pattern_id'])) {
                    $pattern = strtolower($result['pattern_id']);
                    if (strpos($pattern, 'backdoor') !== false || 
                        strpos($pattern, 'webshell') !== false ||
                        strpos($pattern, 'cryptocurrency') !== false) {
                        $engine_score = 6; // Maximum for critical signatures
                    }
                }
                break;
                
            case 'anomaly':
                // Anomaly detections - increased base scores
                if (isset($result['description'])) {
                    $desc = strtolower($result['description']);
                    if (strpos($desc, 'mismatched') !== false) {
                        $engine_score = 2.5; // Increased from 1.5
                    } elseif (strpos($desc, 'suspicious') !== false) {
                        $engine_score = 3.5; // Increased from 2.5
                    } else {
                        $engine_score = 3; // Increased from 2
                    }
                } else {
                    $engine_score = 3; // Increased from 2
                }
                break;
                
            case 'potential':
            case 'pattern':
                // Pattern-based detections - more aggressive scoring
                if (isset($result['severity'])) {
                    $engine_score = wpsec_severity_to_score($result['severity']) + 0.5; // +0.5 bonus
                } else {
                    $engine_score = 2.5; // Increased from 1.5
                }
                
                // Add bonuses for specific high-risk patterns
                if (isset($result['pattern']) || isset($result['description'])) {
                    $pattern_text = strtolower($result['pattern'] ?? $result['description'] ?? '');
                    
                    // High-risk pattern bonuses
                    if (strpos($pattern_text, 'eval') !== false && 
                        (strpos($pattern_text, 'base64') !== false || strpos($pattern_text, 'decode') !== false)) {
                        $engine_score += 2; // Major bonus for eval + encoding
                    } elseif (strpos($pattern_text, 'system') !== false || 
                             strpos($pattern_text, 'exec') !== false || 
                             strpos($pattern_text, 'shell_exec') !== false) {
                        $engine_score += 1.5; // Bonus for command execution
                    } elseif (strpos($pattern_text, 'preg_replace') !== false && strpos($pattern_text, '/e') !== false) {
                        $engine_score += 1.5; // Bonus for preg_replace /e modifier
                    } elseif (strpos($pattern_text, 'create_function') !== false) {
                        $engine_score += 1; // Bonus for create_function
                    } elseif (strpos($pattern_text, 'eval') !== false) {
                        $engine_score += 1; // Bonus for any eval usage
                    }
                }
                break;
                
            case 'advanced':
                // Advanced engine detections - increased base score
                $engine_score = 4; // Increased from 3
                break;
                
            default:
                // Unknown engine type - use severity if available
                if (isset($result['severity'])) {
                    $engine_score = wpsec_severity_to_score($result['severity']) + 0.5; // +0.5 bonus
                } else {
                    $engine_score = 2; // Increased from 1
                }
        }
        
        // Apply confidence scaling if available (but less aggressive reduction)
        if (isset($result['confidence']) && $result['confidence'] > 0) {
            $confidence_factor = $result['confidence'] / 100;
            $engine_score *= (0.7 + 0.3 * $confidence_factor); // Scale between 70%-100% (less penalty)
        }
        
        $engine_scores[] = $engine_score;
        $base_score += $engine_score;
    }
    
    // Apply file context multipliers (but cap the reduction to prevent over-penalizing)
    $context_multiplier = wpsec_calculate_context_multiplier($file_path, $file_context);
    // Ensure context multiplier doesn't reduce score below 0.8 for legitimate detections
    if ($context_multiplier < 0.8 && $base_score >= 3) {
        $context_multiplier = max(0.8, $context_multiplier);
    }
    $base_score *= $context_multiplier;
    
    // Detection count bonus (multiple engines agreeing increases confidence)
    if ($detection_count > 1) {
        $detection_bonus = min(1.8, 1 + ($detection_count - 1) * 0.15); // Increased bonus
        $base_score *= $detection_bonus;
    }
    
    // Ensure minimum score for legitimate malware detections
    if ($base_score >= 2.5 && $base_score < 4.0) {
        $base_score = max(4.0, $base_score * 1.2); // Boost borderline scores
    }
    
    // Final score calculation with proper scaling
    $final_score = min(10, max(0, round($base_score, 1)));
    
    // Calculate aggregated confidence
    $total_confidence = 0;
    $confidence_count = 0;
    foreach ($detection_results as $result) {
        // CRITICAL FIX: Use fallback confidence if not provided or zero
        $result_confidence = isset($result['confidence']) ? $result['confidence'] : wpsec_get_default_confidence($result['engine_type'] ?? $result['type'] ?? 'unknown');
        if ($result_confidence <= 0) {
            $result_confidence = 70; // Fallback for engines that don't set confidence
        }
        $total_confidence += $result_confidence;
        $confidence_count++;
    }
    
    $confidence = $confidence_count > 0 ? round($total_confidence / $confidence_count) : 70;
    
    // Determine severity based on final score
    $severity = 'low';
    if ($final_score >= 7) {
        $severity = 'critical';
    } elseif ($final_score >= 5) {
        $severity = 'high';
    } elseif ($final_score >= 3) {
        $severity = 'medium';
    }
    
    return [
        'score' => $final_score,
        'severity' => $severity,
        'confidence' => $confidence
    ];
}

// Helper function to convert severity strings to numeric scores
function wpsec_severity_to_score($severity) {
    switch (strtolower($severity)) {
        case 'critical': return 4;
        case 'high': return 3;
        case 'medium': return 2;
        case 'low': return 1;
        default: return 1.5;
    }
}

// Helper function to calculate context-based multipliers
function wpsec_calculate_context_multiplier($file_path, $file_context) {
    $multiplier = 1.0;
    
    if (!empty($file_path)) {
        $path_lower = strtolower($file_path);
        
        // Location-based adjustments
        if (strpos($path_lower, '/uploads/') !== false) {
            $multiplier *= 1.3; // Higher risk in uploads directory
        } elseif (strpos($path_lower, '/wp-content/themes/') !== false) {
            $multiplier *= 1.1; // Slightly higher risk in themes
        } elseif (strpos($path_lower, '/wp-content/plugins/') !== false) {
            $multiplier *= 1.1; // Slightly higher risk in plugins
        } elseif (strpos($path_lower, '/wp-admin/') !== false || strpos($path_lower, '/wp-includes/') !== false) {
            $multiplier *= 0.8; // Lower risk in WordPress core (more false positives)
        }
        
        // File type adjustments
        $extension = pathinfo($file_path, PATHINFO_EXTENSION);
        switch (strtolower($extension)) {
            case 'php':
                $multiplier *= 1.2; // PHP files are higher risk
                break;
            case 'js':
                $multiplier *= 0.9; // JS files often have false positives
                break;
            case 'css':
                $multiplier *= 0.7; // CSS files rarely malicious
                break;
            case 'txt':
            case 'log':
                $multiplier *= 0.8; // Text files lower risk
                break;
        }
    }
    
    // Use provided context if available
    if (isset($file_context['location'])) {
        switch ($file_context['location']) {
            case 'uploads':
                $multiplier *= 1.3;
                break;
            case 'core':
                $multiplier *= 0.8;
                break;
            case 'plugin':
                $multiplier *= 1.1;
                break;
            case 'theme':
                $multiplier *= 1.1;
                break;
        }
    }
    
    return $multiplier;
}

// Helper function to get default confidence for engine types
function wpsec_get_default_confidence($engine_type) {
    switch ($engine_type) {
        case 'signatures':
        case 'signature':
            return 90; // High confidence for signature matches
        case 'heuristic':
            return 75; // Good confidence for heuristic analysis
        case 'advanced':
            return 80; // High confidence for advanced analysis
        case 'anomaly':
            return 60; // Medium confidence for anomaly detection
        case 'potential':
        case 'pattern':
            return 65; // Medium confidence for pattern matching
        default:
            return 70; // Default confidence
    }
}

/**
 * Standardize advanced detection results to ensure consistent structure
 * This ensures that detection results from advanced engines are properly structured
 * for inclusion in the final scan results
 *
 * @param array $results Results from advanced engines
 * @return array Standardized results with proper file_path and detections structure
 */
function wpsec_standardize_advanced_detection_results($results) {
    wpsec_debug_log(' STANDARDIZE FUNCTION START: Processing ' . count($results) . " items", 'info');
    
    // CRITICAL TRACE: Check for test files entering standardization
    foreach ($results as $key => $result) {
        if (isset($result['file_path']) && wpsec_is_test_malware_file($result['file_path'])) {
            wpsec_debug_log(' STANDARDIZE - LINE 1524: Found test file at input: ' . $result['file_path'], 'info');
            wpsec_debug_log('   - Threat score BEFORE standardization: ' . (isset($result['threat_score']) ? $result['threat_score'] : 'NOT SET'), 'info');
            wpsec_debug_log('   - Object structure: ' . json_encode($result, JSON_UNESCAPED_SLASHES), 'info');
        }
    }
    
    $standardized_results = [];
    $file_detections = [];
    
    // DIAGNOSTIC: Log the raw input to standardization
    $has_test_file = false;
    foreach ($results as $result) {
        if (isset($result['file_path']) && (stripos($result['file_path'], 'I-am-infecting') !== false || stripos($result['file_path'], 'i-am-hacking') !== false)) {
            $has_test_file = true;
            wpsec_debug_log(' DIAGNOSTIC: Found test malware file in raw results: ' . $result['file_path'], 'info');
            wpsec_debug_log(' DIAGNOSTIC: Raw detection data: ' . json_encode($result, JSON_PRETTY_PRINT), 'info');
        }
    }
    if (!$has_test_file) {
        wpsec_debug_log(' DIAGNOSTIC: No test malware files found in raw results array (' . count($results) . " total items)", 'info');
    }
    
    // Process results to identify any standalone detections
    foreach ($results as $result) {
        // Skip if result is already in expected format with file_path and detections[]
        // AND the detections array doesn't contain nested arrays or context objects
        if (isset($result['file_path']) && isset($result['detections']) && is_array($result['detections'])) {
            // Check for and fix nested arrays or context objects in detections
            $fixed_detections = [];
            $context_updated = false;
            
            foreach ($result['detections'] as $detection) {
                // If detection is an array (nested array), flatten it
                if (is_array($detection) && isset($detection[0]) && is_array($detection[0])) {
                    foreach ($detection as $nested_detection) {
                        // Only add if it's a properly structured detection
                        if (is_array($nested_detection) && isset($nested_detection['type'])) {
                            $fixed_detections[] = $nested_detection;
                        }
                    }
                }
                // If detection is actually a context object, update the file context
                else if (is_array($detection) && isset($detection['type']) && 
                         (isset($detection['is_core']) || isset($detection['is_plugin']) || 
                          isset($detection['is_theme']) || isset($detection['is_upload']) || 
                          isset($detection['risk_level']))) {
                    $result['context'] = $detection;
                    $context_updated = true;
                }
                // Otherwise, it's a normal detection
                else if (is_array($detection) && isset($detection['type'])) {
                    $fixed_detections[] = $detection;
                }
            }
            
            // Replace detections with fixed array if we made changes
            if (!empty($fixed_detections) || $context_updated) {
                $result['detections'] = $fixed_detections;
            }
            
            $standardized_results[] = $result;
            continue;
        }
        
        // Process standalone detection entries (type 'potential' without detections[] array)
        if (isset($result['type']) && isset($result['file_path'])) {
            $file_path = $result['file_path'];
            
            // Create a detection entry from this result
            $detection = [
                'type' => $result['type'],
                'name' => $result['name'] ?? '',
                'severity' => $result['severity'] ?? 'medium',
                'confidence' => $result['confidence'] ?? 70,
                'description' => $result['description'] ?? ''
            ];
            
            // Add pattern-specific fields if available
            if (isset($result['pattern_id'])) {
                $detection['pattern_id'] = $result['pattern_id'];
            }
            if (isset($result['pattern_match'])) {
                $detection['pattern_match'] = $result['pattern_match'];
            }
            if (isset($result['file_hash'])) {
                $detection['file_hash'] = $result['file_hash'];
            }
            
            // Group detections by file path
            if (!isset($file_detections[$file_path])) {
                $file_detections[$file_path] = [];
            }
            $file_detections[$file_path][] = $detection;
        }
        // Handle results without file_path (keep as is)
        else if (!isset($result['file_path'])) {
            $standardized_results[] = $result;
        }
    }
    
    // Convert grouped detections to standardized format
    foreach ($file_detections as $file_path => $detections) {
        $standardized_results[] = [
            'file_path' => $file_path,
            'detections' => $detections,
            'context' => [
                'type' => 'unknown',
                'is_core' => false,
                'is_plugin' => false,
                'is_theme' => false,
                'is_upload' => false,
                'risk_level' => 'medium'
            ],
            'scan_time' => time(),
            'file_size' => file_exists($file_path) ? filesize($file_path) : 0,
            'extension' => pathinfo($file_path, PATHINFO_EXTENSION)
        ];
    }
    
    // DIAGNOSTIC: Check if test files made it through standardization
    $found_test_file = false;
    foreach ($standardized_results as $result) {
        if (isset($result['file_path']) && (stripos($result['file_path'], 'I-am-infecting') !== false || stripos($result['file_path'], 'i-am-hacking') !== false)) {
            $found_test_file = true;
            wpsec_debug_log(' DIAGNOSTIC STANDARDIZED: Test file in standardized results: ' . $result['file_path'], 'info');
            wpsec_debug_log(' DIAGNOSTIC STANDARDIZED: Detection data: ' . json_encode($result, JSON_PRETTY_PRINT), 'info');
        }
    }
    if (!$found_test_file) {
        wpsec_debug_log(' DIAGNOSTIC STANDARDIZED: No test files in standardized results array of ' . count($standardized_results) . " items", 'info');
    }
    
    return $standardized_results;
}

// Add action for cron job
add_action('wpsec_scan_cron', 'wpsec_run_scan');