<?php
/**
 * VMPFence Server State Scanner
 *
 * @package VMPFence
 * @since 1.0.0
 * @since 2.2.4 SQL Query fix
 * @since 2.2.6 Skipped path description updated for server
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

class VMPFence_Server_State_Scanner {
    
    private $scan_results = [];
    private $issues = [];
    private $debug_log = [];
    private $scan_options = [];
    private $ipv4_interceptor = null;
    
    /**
     * Set IPv4 interceptor for HTTP requests
     */
    public function set_ipv4_interceptor($interceptor) {
        $this->ipv4_interceptor = $interceptor;
    }
    
    /**
     * Run server state scan with optional scan options
     */
    public function run_scan($scan_options = null) {
        // Initialize performance controls if available
        $use_performance_controls = false;
        if (class_exists('VMPFence_Performance_Manager')) {
            VMPFence_Performance_Manager::init();
            $use_performance_controls = true;
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Server State Scanner: Performance controls initialized';
        }
        
        // IMPLEMENTATION: Load scan options if provided
        $this->scan_options = $scan_options ? $scan_options : [];
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Starting Server State Scan';
        
        // Clear previous server state scan data FIRST
        $this->clear_previous_scan_data();
        
        $this->scan_results = [
            'scan_type' => 'server_state',
            'scan_time' => current_time('mysql'),
            'issues_found' => 0,
            'checks_performed' => 0
        ];
        
        // Track which checks are executed
        $checks_to_run = [
            'check_php_version' => 'PHP Version and Configuration',
            'check_wordpress_version' => 'WordPress Version',
            'check_file_permissions' => 'File Permissions',
            'check_database_security' => 'Database Security',
            'check_ssl_https' => 'SSL/HTTPS Configuration',
            'check_server_limits' => 'Server Resource Limits',
            'check_server_software' => 'Server Software',
            'check_ip_detection_method' => 'IP Detection Method',
            'check_waf_status' => 'Web Application Firewall',
            'check_disk_space' => 'Disk Space',
            'check_skipped_paths' => 'Skipped Paths',
            'check_public_file_exposure' => 'Public File Exposure'
        ];
        
        $checks_executed = [];
        $checks_failed = [];
        
        // Perform all server state checks with error handling and option filtering
        $processed_checks = 0;
        foreach ($checks_to_run as $method => $description) {
            // Performance throttling for check processing
            if (class_exists('VMPFence_Performance_Manager')) {
                VMPFence_Performance_Manager::throttle_processing($processed_checks);
            }
            $processed_checks++;
            
            // IMPLEMENTATION: Check scan options before executing specific methods
            $should_execute = false; // Default to FALSE - only run if explicitly enabled
            
            switch($method) {
                case 'check_ip_detection_method':
                    $should_execute = !empty($this->scan_options['scansEnabled_checkHowGetIPs']);
                    break;
                case 'check_waf_status':
                    $should_execute = !empty($this->scan_options['scansEnabled_wafStatus']);
                    break;
                case 'check_disk_space':
                    $should_execute = !empty($this->scan_options['scansEnabled_diskSpace']);
                    break;
                case 'check_public_file_exposure':
                    $should_execute = !empty($this->scan_options['scansEnabled_checkReadableConfig']);
                    break;
                case 'check_wordpress_version':
                    $should_execute = !empty($this->scan_options['scansEnabled_oldVersions']);
                    break;
                case 'check_php_version':
                    $should_execute = !empty($this->scan_options['scansEnabled_oldVersions']);
                    break;
                case 'check_file_permissions':
                    $should_execute = !empty($this->scan_options['scansEnabled_checkReadableConfig']);
                    break;
                case 'check_database_security':
                    $should_execute = !empty($this->scan_options['scansEnabled_checkReadableConfig']);
                    break;
                case 'check_ssl_https':
                    $should_execute = !empty($this->scan_options['scansEnabled_checkReadableConfig']);
                    break;
                case 'check_server_limits':
                    $should_execute = !empty($this->scan_options['scansEnabled_checkReadableConfig']);
                    break;
                case 'check_server_software':
                    $should_execute = !empty($this->scan_options['scansEnabled_checkReadableConfig']);
                    break;
                case 'check_skipped_paths':
                    $should_execute = true; // Always run
                    break;
                // All other methods are disabled by default unless their option is added above
            }
            
            // DEBUG: Log the decision for each method
            // error_log('[Server State Scanner] Method: ' . $method . ' -> should_execute: ' . ($should_execute ? 'TRUE' : 'FALSE'));
            
            if (!$should_execute) {
                $this->debug_log[] = '[Scan Controller] SKIPPED: ' . $description . ' (disabled in scan options)';
                continue;
            }
            
            try {
                $this->debug_log[] = '[Scan Controller] Executing: ' . $description;
                $issues_before = count($this->issues);
                
                $this->$method();
                
                $issues_after = count($this->issues);
                $new_issues = $issues_after - $issues_before;
                
                $checks_executed[] = $method;
                $this->debug_log[] = '[Scan Controller] ✓ Completed: ' . $description . ' (found ' . $new_issues . ' issues)';
                
            } catch (Exception $e) {
                $checks_failed[] = $method;
                $this->debug_log[] = '[Scan Controller] ✗ FAILED: ' . $description . ' - Error: ' . $e->getMessage();
                
                // Add an issue for the failed check
                $this->add_issue('high', 'Scanner Check Failed',
                    "The {$description} check failed to execute properly.",
                    'Contact system administrator to review scanner configuration.',
                    'scanner_error'
                );
            } catch (Error $e) {
                $checks_failed[] = $method;
                $this->debug_log[] = '[Scan Controller] ✗ FATAL ERROR: ' . $description . ' - Error: ' . $e->getMessage();
                
                $this->add_issue('critical', 'Scanner Check Fatal Error',
                    "The {$description} check encountered a fatal error.",
                    'Contact system administrator immediately to review scanner configuration.',
                    'scanner_error'
                );
            }
        }
        
        // Calculate totals
        $this->scan_results['issues_found'] = count($this->issues);
        $this->scan_results['checks_performed'] = count($checks_executed);
        $this->scan_results['checks_failed'] = count($checks_failed);
        
        // Log execution summary
        $total_checks = count($checks_to_run);
        $successful_checks = count($checks_executed);
        $failed_checks = count($checks_failed);
        
        $this->debug_log[] = '[Scan Controller] === EXECUTION SUMMARY ===';
        $this->debug_log[] = '[Scan Controller] Total checks planned: ' . $total_checks;
        $this->debug_log[] = '[Scan Controller] Successful checks: ' . $successful_checks;
        $this->debug_log[] = '[Scan Controller] Failed checks: ' . $failed_checks;
        
        if (!empty($checks_failed)) {
            $this->debug_log[] = '[Scan Controller] Failed check methods: ' . implode(', ', $checks_failed);
        }
        
        // Save results to database
        $this->save_scan_results();
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Server State Scan Complete - Found ' . count($this->issues) . ' issues';
        
        // Apply performance controls to limit issues if enabled
        if (class_exists('VMPFence_Performance_Manager')) {
            $this->issues = VMPFence_Performance_Manager::limit_issues($this->issues);
            $this->debug_log[] = '[' . current_time('H:i:s') . '] Performance Manager: Limited issues to ' . count($this->issues);
        }
        
        return [
            'results' => $this->scan_results,
            'issues' => $this->issues,
            'debug_log' => $this->debug_log,
            'checks_executed' => $checks_executed,
            'checks_failed' => $checks_failed
        ];
    }
    
    /**
     * Check PHP version and configuration
     */
    private function check_php_version() {
        $this->debug_log[] = '[PHP Check] Starting PHP version and configuration check';
        
        $php_version = PHP_VERSION;
        $this->debug_log[] = '[PHP Check] Current PHP version: ' . $php_version;
        
        $supported_versions = ['8.1', '8.2', '8.3'];
        $is_supported = false;
        
        foreach ($supported_versions as $version) {
            if (version_compare($php_version, $version, '>=')) {
                $is_supported = true;
                $this->debug_log[] = '[PHP Check] PHP version is supported (>= ' . $version . ')';
                break;
            }
        }
        
        if (!$is_supported || version_compare($php_version, '7.4', '<')) {
            $this->add_issue('critical', 'Outdated PHP Version', 
                "PHP version {$php_version} is outdated and may have security vulnerabilities. Update to PHP 8.1 or higher.",
                'Update PHP through your hosting provider or server administrator.',
                'php_version'
            );
            $this->debug_log[] = '[PHP Check] ISSUE: PHP version is outdated';
        } else {
            $this->debug_log[] = '[PHP Check] PHP version is acceptable';
        }
        
        // Check dangerous PHP functions
        $dangerous_functions = ['exec', 'shell_exec', 'system', 'passthru'];
        $enabled_dangerous = [];
        
        foreach ($dangerous_functions as $func) {
            if (function_exists($func)) {
                $enabled_dangerous[] = $func;
                $this->debug_log[] = '[PHP Check] Dangerous function enabled: ' . $func;
            }
        }
        
        if (!empty($enabled_dangerous)) {
            // Log as debug information instead of creating issues
            $this->debug_log[] = '[PHP Check] INFO: ' . count($enabled_dangerous) . ' dangerous functions enabled: ' . implode(', ', $enabled_dangerous);
            $this->debug_log[] = '[PHP Check] RECOMMENDATION: Consider disabling these functions in php.ini if not needed';
            foreach ($enabled_dangerous as $func) {
                $this->debug_log[] = '[PHP Check] - ' . $func . ': Can be exploited by attackers if not properly secured';
            }
        } else {
            $this->debug_log[] = '[PHP Check] No dangerous functions enabled';
        }
        
        $this->debug_log[] = '[PHP Check] PHP check completed';
    }
    
    /**
     * Check WordPress version
     */
    private function check_wordpress_version() {
        global $wp_version;
        
        $this->debug_log[] = '[WP Check] Starting WordPress version check';
        $this->debug_log[] = '[WP Check] Current WordPress version: ' . $wp_version;
        
        // Get latest WordPress version (simplified check)
        $latest_version = get_transient('vmpfence_latest_wp_version');
        if (!$latest_version) {
            $this->debug_log[] = '[WP Check] Fetching latest WordPress version from API';
            
            // Use IPv4 interceptor if available
            if ($this->ipv4_interceptor) {
                // error_log('VMPFence IPv4: Using IPv4 interceptor for WordPress API call');
                $response = $this->ipv4_interceptor->intercept(function() {
                    return wp_remote_get('https://api.wordpress.org/core/version-check/1.7/');
                });
            } else {
                // error_log('VMPFence IPv4: Using standard HTTP request (no IPv4 interceptor)');
                $response = wp_remote_get('https://api.wordpress.org/core/version-check/1.7/');
            }
            
            if (!is_wp_error($response)) {
                $body = wp_remote_retrieve_body($response);
                $data = json_decode($body, true);
                if (isset($data['offers'][0]['version'])) {
                    $latest_version = $data['offers'][0]['version'];
                    set_transient('vmpfence_latest_wp_version', $latest_version, 12 * HOUR_IN_SECONDS);
                    $this->debug_log[] = '[WP Check] Latest WordPress version from API: ' . $latest_version;
                } else {
                    $this->debug_log[] = '[WP Check] Failed to parse API response';
                }
            } else {
                $this->debug_log[] = '[WP Check] API request failed: ' . $response->get_error_message();
            }
        } else {
            $this->debug_log[] = '[WP Check] Using cached latest version: ' . $latest_version;
        }
        
        if ($latest_version && version_compare($wp_version, $latest_version, '<')) {
            $this->add_issue('high', 'Outdated WordPress Version',
                "WordPress {$wp_version} is outdated. Latest version is {$latest_version}.",
                'Update WordPress through Dashboard > Updates or wp-admin/update-core.php',
                'wordpress_core'
            );
            $this->debug_log[] = '[WP Check] ISSUE: WordPress version is outdated';
        } else {
            $this->debug_log[] = '[WP Check] WordPress version is up to date';
        }
        
        $this->debug_log[] = '[WP Check] WordPress version check completed';
    }
    
    /**
     * Check file permissions
     */
    private function check_file_permissions() {
        $this->debug_log[] = '[File Permissions] Starting file permissions check';
        
        $checks = [
            [
                'path' => ABSPATH . 'wp-config.php',
                'name' => 'wp-config.php',
                'recommended' => '600',
                'max_safe' => '644'
            ],
            [
                'path' => ABSPATH,
                'name' => 'WordPress root directory',
                'recommended' => '755',
                'max_safe' => '755'
            ],
            [
                'path' => WP_CONTENT_DIR,
                'name' => 'wp-content directory',
                'recommended' => '755',
                'max_safe' => '755'
            ]
        ];
        
        $issues_found = 0;
        
        foreach ($checks as $check) {
            if (file_exists($check['path'])) {
                $perms = substr(sprintf('%o', fileperms($check['path'])), -3);
                $perms_decimal = octdec($perms);
                $max_safe_decimal = octdec($check['max_safe']);
                
                $this->debug_log[] = '[File Permissions] ' . $check['name'] . ' permissions: ' . $perms . ' (recommended: ' . $check['recommended'] . ')';
                
                if ($perms_decimal > $max_safe_decimal) {
                    // Log as debug information instead of creating issues
                    $this->debug_log[] = '[File Permissions] INFO: ' . $check['name'] . ' has permissions ' . $perms . ', recommended ' . $check['recommended'];
                    $this->debug_log[] = '[File Permissions] RECOMMENDATION: Change permissions to ' . $check['recommended'] . ' using chmod or hosting control panel';
                    $issues_found++;
                } else {
                    $this->debug_log[] = '[File Permissions] ' . $check['name'] . ' permissions are secure';
                }
            } else {
                $this->debug_log[] = '[File Permissions] WARNING: ' . $check['name'] . ' not found at ' . $check['path'];
            }
        }
        
        if ($issues_found === 0) {
            $this->debug_log[] = '[File Permissions] All checked file permissions are secure';
        }
        
        $this->debug_log[] = '[File Permissions] File permissions check completed';
    }
    
    /**
     * Check database security
     */
    private function check_database_security() {
        global $wpdb;
        
        $this->debug_log[] = '[Database Check] Starting database security check';
        
        // Check table prefix
        $this->debug_log[] = '[Database Check] Current table prefix: ' . $wpdb->prefix;
        
        if ($wpdb->prefix === 'wp_') {
            // Log as debug information instead of creating issues
            $this->debug_log[] = '[Database Check] INFO: Using default "wp_" table prefix';
            $this->debug_log[] = '[Database Check] RECOMMENDATION: Consider changing table prefix during WordPress installation or migration for better security';
        } else {
            $this->debug_log[] = '[Database Check] Custom table prefix is being used';
        }
        
        // Check database version
        $db_version = $wpdb->get_var('SELECT VERSION()');
        if ($db_version) {
            $this->debug_log[] = '[Database Check] Database version: ' . $db_version;
            
            // Check for very old MySQL versions
            if (version_compare($db_version, '5.7', '<')) {
                $this->add_issue('medium', 'Old Database Version',
                    "MySQL version {$db_version} is outdated and may lack security features.",
                    'Update MySQL/MariaDB through your hosting provider.',
                    'database_version'
                );
                $this->debug_log[] = '[Database Check] ISSUE: Database version is outdated';
            } else {
                $this->debug_log[] = '[Database Check] Database version is acceptable';
            }
        } else {
            $this->debug_log[] = '[Database Check] Unable to retrieve database version';
        }
        
        $this->debug_log[] = '[Database Check] Database security check completed';
    }
    
    /**
     * Check SSL/HTTPS status
     */
    private function check_ssl_https() {
        $this->debug_log[] = '[SSL Check] Starting SSL/HTTPS configuration check';
        
        $is_ssl = is_ssl();
        $this->debug_log[] = '[SSL Check] Current request is SSL: ' . ($is_ssl ? 'Yes' : 'No');
        
        if (!$is_ssl) {
            // Log as debug information instead of creating issues
            $this->debug_log[] = '[SSL Check] INFO: Site not using HTTPS - data transmission is not encrypted';
            $this->debug_log[] = '[SSL Check] RECOMMENDATION: Enable SSL certificate and force HTTPS redirects';
        } else {
            $this->debug_log[] = '[SSL Check] Site is using HTTPS';
        }
        
        // Check if WordPress is configured for HTTPS
        $home_url = get_option('home');
        $site_url = get_option('siteurl');
        
        $this->debug_log[] = '[SSL Check] Home URL: ' . $home_url;
        $this->debug_log[] = '[SSL Check] Site URL: ' . $site_url;
        
        if (strpos($home_url, 'https://') !== 0 || strpos($site_url, 'https://') !== 0) {
            // Log as debug information instead of creating issues
            $this->debug_log[] = '[SSL Check] INFO: WordPress URLs not configured for HTTPS';
            $this->debug_log[] = '[SSL Check] RECOMMENDATION: Update WordPress Address and Site Address in Settings > General to use HTTPS';
        } else {
            $this->debug_log[] = '[SSL Check] WordPress URLs properly configured for HTTPS';
        }
        
        $this->debug_log[] = '[SSL Check] SSL/HTTPS check completed';
    }
    
    /**
     * Check server resource limits
     */
    private function check_server_limits() {
        $this->debug_log[] = '[Limits Check] Starting server resource limits check';
        
        // Check memory limit
        $memory_limit = wp_convert_hr_to_bytes(ini_get('memory_limit'));
        $memory_limit_hr = ini_get('memory_limit');
        $recommended_memory = 256 * 1024 * 1024; // 256MB
        
        $this->debug_log[] = '[Limits Check] Current memory limit: ' . $memory_limit_hr . ' (' . size_format($memory_limit) . ')';
        $this->debug_log[] = '[Limits Check] Recommended memory limit: ' . size_format($recommended_memory);
        
        if ($memory_limit < $recommended_memory) {
            $this->add_issue('medium', 'Low Memory Limit',
                'PHP memory limit is ' . size_format($memory_limit) . ', recommended minimum is 256MB.',
                'Increase memory_limit in php.ini or contact your hosting provider.',
                'memory_limit'
            );
            $this->debug_log[] = '[Limits Check] ISSUE: Memory limit below recommended';
        } else {
            $this->debug_log[] = '[Limits Check] Memory limit is adequate';
        }
        
        // Check execution time limit
        $max_execution_time = ini_get('max_execution_time');
        $this->debug_log[] = '[Limits Check] Max execution time: ' . $max_execution_time . ' seconds';
        
        if ($max_execution_time > 0 && $max_execution_time < 60) {
            // Check if this is a VMPFence Performance Manager override
            if (function_exists('ini_get_all')) {
                $all_settings = ini_get_all();
                if (isset($all_settings['max_execution_time'])) {
                    $global_val = $all_settings['max_execution_time']['global_value'];
                    $local_val = $all_settings['max_execution_time']['local_value'];
                    
                    if ($global_val != $local_val) {
                        if (class_exists('VMPFence_Performance_Manager')) {
                            $this->debug_log[] = '[Limits Check] INFO: VMPFence Performance Manager has set execution time to ' . $local_val . ' seconds';
                            $this->debug_log[] = '[Limits Check] NOTE: This is VMPFence\'s performance management (caps at 90s, then uses half: ' . $global_val . ' → 90 → ' . $local_val . ')';
                            $this->debug_log[] = '[Limits Check] ANALYSIS: php.ini has ' . $global_val . ' seconds, VMPFence overrode to ' . $local_val . ' seconds for web-based scans';
                            $this->debug_log[] = '[Limits Check] PURPOSE: Prevents timeouts and ensures responsive web interface during scans';
                        } else {
                            $this->debug_log[] = '[Limits Check] INFO: PHP execution time overridden from ' . $global_val . ' to ' . $local_val . ' seconds';
                            $this->debug_log[] = '[Limits Check] NOTE: This may be WordPress core or another plugin managing execution time';
                        }
                    } else {
                        $this->debug_log[] = '[Limits Check] INFO: PHP max execution time is ' . $max_execution_time . ' seconds (no override detected)';
                        $this->debug_log[] = '[Limits Check] RECOMMENDATION: Consider increasing max_execution_time in php.ini for better scan performance';
                    }
                }
            } else {
                $this->debug_log[] = '[Limits Check] INFO: PHP max execution time is ' . $max_execution_time . ' seconds';
                $this->debug_log[] = '[Limits Check] NOTE: Unable to determine if this is an override (ini_get_all not available)';
            }
        } else {
            $this->debug_log[] = '[Limits Check] Execution time limit is adequate (' . $max_execution_time . ' seconds)';
        }
        
        // Check upload limit
        $upload_max = wp_convert_hr_to_bytes(ini_get('upload_max_filesize'));
        $upload_max_hr = ini_get('upload_max_filesize');
        $this->debug_log[] = '[Limits Check] Upload file size limit: ' . $upload_max_hr . ' (' . size_format($upload_max) . ')';
        
        if ($upload_max < 32 * 1024 * 1024) { // 32MB
            $this->add_issue('low', 'Low Upload File Size Limit',
                'Upload file size limit is ' . size_format($upload_max) . ', recommended minimum is 32MB.',
                'Increase upload_max_filesize in php.ini.',
                'upload_limit'
            );
            $this->debug_log[] = '[Limits Check] ISSUE: Upload limit below recommended';
        } else {
            $this->debug_log[] = '[Limits Check] Upload limit is adequate';
        }
        
        $this->debug_log[] = '[Limits Check] Server limits check completed';
    }
    
    /**
     * Check server software information
     */
    private function check_server_software() {
        $this->debug_log[] = '[Server Software] Starting server software check';
        
        $server_software = sanitize_text_field(wp_unslash($_SERVER['SERVER_SOFTWARE'] ?? 'Unknown'));
        $this->debug_log[] = '[Server Software] Server software: ' . $server_software;
        
        $issues_found = 0;
        
        // Check if server info is exposed (security consideration)
        if (strpos($server_software, 'Apache') !== false) {
            $this->debug_log[] = '[Server Software] Apache server detected';
            
            // Check for version exposure
            if (preg_match('/Apache\/([0-9\.]+)/', $server_software, $matches)) {
                // Log as debug information instead of creating issues
                $this->debug_log[] = '[Server Software] INFO: Apache version exposed in headers - ' . $matches[1];
                $this->debug_log[] = '[Server Software] RECOMMENDATION: Configure Apache to hide version information using ServerTokens directive';
                $issues_found++;
            } else {
                $this->debug_log[] = '[Server Software] Apache version is hidden';
            }
        } else {
            $this->debug_log[] = '[Server Software] Non-Apache server or server info hidden';
        }
        
        // Check for debug mode
        if (defined('WP_DEBUG') && WP_DEBUG) {
            $this->add_issue('medium', 'Debug Mode Enabled',
                'WordPress debug mode is enabled, which may expose sensitive information.',
                'Disable WP_DEBUG in wp-config.php for production sites.',
                'debug_mode'
            );
            $this->debug_log[] = '[Server Software] ISSUE: WordPress debug mode is enabled';
            $issues_found++;
        } else {
            $this->debug_log[] = '[Server Software] WordPress debug mode is disabled';
        }
        
        // Additional checks for other server software
        if (strpos($server_software, 'nginx') !== false) {
            $this->debug_log[] = '[Server Software] Nginx server detected';
            if (preg_match('/nginx\/([0-9\.]+)/', $server_software, $matches)) {
                // Log as debug information instead of creating issues
                $this->debug_log[] = '[Server Software] INFO: Nginx version exposed in headers - ' . $matches[1];
                $this->debug_log[] = '[Server Software] RECOMMENDATION: Configure Nginx to hide version information using server_tokens directive';
                $issues_found++;
            }
        }
        
        if ($issues_found === 0) {
            $this->debug_log[] = '[Server Software] No server software issues detected';
        }
        
        $this->debug_log[] = '[Server Software] Server software check completed';
    }
    
    /**
     * Clear previous server state scan data
     */
    private function clear_previous_scan_data() {
        global $wpdb;
        
        $this->debug_log[] = '[' . current_time('H:i:s') . '] Clearing previous server state scan data';
        
        // Table names
        $scan_issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        $scan_results_table = $wpdb->prefix . 'vmpfence_scan_results';
        
        // Check if tables exist
        $scan_issues_exists = $wpdb->get_var("SHOW TABLES LIKE '$scan_issues_table'");   // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $scan_results_exists = $wpdb->get_var("SHOW TABLES LIKE '$scan_results_table'");  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        
        if (!$scan_issues_exists || !$scan_results_exists) {
            $this->debug_log[] = "WARNING: Required database tables are missing, skipping cleanup";
            return;
        }
        
        // Clear previous server state scan issues (non-ignored only)
        $deleted = $wpdb->query($wpdb->prepare(
            "DELETE FROM {$scan_issues_table} WHERE issue_type = %s AND status != 'ignored'", 'server_state'  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        ));
        $this->debug_log[] = "Deleted $deleted previous server state issues from database";
        
        // Clear previous server state scan results
        $deleted_results = $wpdb->query($wpdb->prepare(
            "DELETE FROM {$scan_results_table} WHERE scan_type = %s", 'server_state'  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        ));
        $this->debug_log[] = "Deleted $deleted_results previous server state scan results from database";
    }
    
    /**
     * Add an issue to the results
     */
    private function add_issue($severity, $title, $description, $solution, $type = '', $file_path = '') {
        // For scan_exclusions, store JSON data in description field
        if ($type === 'scan_exclusions') {
            $this->issues[] = [
                'severity' => $severity,
                'title' => $title,
                'description' => $solution, // JSON data goes in description for scan_exclusions
                'solution' => $description, // Clean description goes in solution field
                'scan_type' => 'server_state', // This is the overall scan category
                'type' => $type, // This is the specific test type
                'file_path' => $file_path // File path if applicable
            ];
        } else {
            $this->issues[] = [
                'severity' => $severity,
                'title' => $title,
                'description' => $description,
                'solution' => $solution,
                'scan_type' => 'server_state', // This is the overall scan category
                'type' => $type, // This is the specific test type
                'file_path' => $file_path // File path if applicable
            ];
        }
    }
    
    /**
     * Save scan results to database
     */
    private function save_scan_results() {
        global $wpdb;
        
        // Always save scan summary to track which scanners ran, regardless of issues found
        $this->debug_log[] = "About to save server state scan summary (" . count($this->issues) . " issues found)";
        
        $scan_issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        $scan_results_table = $wpdb->prefix . 'vmpfence_scan_results';
        
        // Check if tables exist
        $scan_issues_exists = $wpdb->get_var("SHOW TABLES LIKE '$scan_issues_table'");  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $scan_results_exists = $wpdb->get_var("SHOW TABLES LIKE '$scan_results_table'");  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        
        
        if (!$scan_issues_exists || !$scan_results_exists) {
            $this->debug_log[] = "ERROR: Required database tables are missing";
            return;
        }

        
        // Always insert scan summary to vmpfence_scan_results (even with 0 issues)
        $insert_data = [
            'scan_type' => 'server_state',
            'scan_time' => current_time('mysql'),
            'issues_found' => count($this->issues),
            'scan_data' => wp_json_encode($this->scan_results)
        ];
        
        $insert_result = $wpdb->insert($scan_results_table, $insert_data);
        
        if ($insert_result === false) {
            $this->debug_log[] = "ERROR: Failed to insert scan summary: " . $wpdb->last_error;
            return;
        } else {
            $this->debug_log[] = "Successfully inserted scan summary with ID: " . $wpdb->insert_id;
        }
        
        $scan_id = $wpdb->insert_id;
        
        // Only process issues if there are any to save
        if (empty($this->issues)) {
            $this->debug_log[] = "Scan summary saved successfully - no issues to process";
            return;
        }
        
        // Insert each issue
        $successful_inserts = 0;
        foreach ($this->issues as $index => $issue) {
            $file_path = $issue['file_path'] ?? '';
            $type = $issue['type'] ?? '';
            
            // Add detailed logging for scan_exclusions
            if ($type === 'scan_exclusions') {
                $description = $issue['title'] . ': ' . $issue['description'];
                $details = $issue['solution']; // JSON data for JavaScript
            } else {
                $description = $issue['title'] . ': ' . $issue['description'] . ' Solution: ' . $issue['solution'];
                $details = '';
            }
            
            // First check if this issue should be recreated as ignored
            if ($this->handle_ignored_issue($file_path, 'server_state', $description, $scan_id, $type)) {
                continue; // Issue was handled as ignored, skip normal processing
            }
            
            // Check if this issue is currently ignored (skip normal creation)
            // Exception: scan_exclusions (skipped paths) should always be shown
            if ($type !== 'scan_exclusions' && $this->is_issue_ignored($file_path, 'server_state', $description, $type)) {
                $this->debug_log[] = "SKIP: Server state issue already ignored - " . $issue['title'];
                continue;
            } elseif ($type === 'scan_exclusions') {
                $this->debug_log[] = '[DB Save] scan_exclusions - Will NOT be skipped (always show)';
            }

            $issue_data = [
                'scan_id' => $scan_id,
                'file_path' => $file_path,
                'issue_type' => 'server_state', // This is the scan category
                'type' => $type, // This is the specific test type
                'severity' => $this->map_issue_type_to_severity('server_state'),
                'description' => $description,
                'detected_time' => current_time('mysql'),
                'status' => 'new'
            ];
            
            $insert_result = $wpdb->insert($scan_issues_table, $issue_data);
            
            if ($insert_result === false) {
                $this->debug_log[] = "ERROR: Failed to insert issue $index: " . $wpdb->last_error;
            } else {
                $successful_inserts++;
                $this->debug_log[] = "Successfully inserted issue $index with ID: " . $wpdb->insert_id;
            }
        }
        
        $this->debug_log[] = "Saved $successful_inserts out of " . count($this->issues) . " server state issues to database";
    }
    
    /**
     * Check if an issue is already ignored
     */
    private function is_issue_ignored($file_path, $issue_type, $description, $type = '') {
        global $wpdb;
        $scan_issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        
        $count = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM $scan_issues_table WHERE file_path = %s AND issue_type = %s AND description = %s AND type = %s AND status = 'ignored'",  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $file_path,
            $issue_type,
            $description,
            $type
        ));
        
        return $count > 0;
    }
    
    /**
     * Handle previously ignored issues - recreate them in current scan as ignored
     *
     * @param string $file_path File path
     * @param string $issue_type Issue type
     * @param string $description Issue description
     * @param int $scan_id Current scan ID
     * @param string $type Specific test type
     * @return bool Whether issue was handled
     */
    private function handle_ignored_issue($file_path, $issue_type, $description, $scan_id, $type = '') {
        global $wpdb;
        
        $issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        
        // Check if this exact issue was previously ignored
        $ignored_issue = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$issues_table} WHERE file_path = %s AND issue_type = %s AND description = %s AND type = %s AND status = 'ignored' ORDER BY detected_time DESC LIMIT 1",  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $file_path,
            $issue_type,
            $description,
            $type
        ));
        
        if ($ignored_issue) {
            // Recreate the ignored issue in current scan
            $insert_result = $wpdb->insert(
                $issues_table,
                [
                    'scan_id' => $scan_id,
                    'file_path' => $file_path,
                    'issue_type' => $issue_type,
                    'type' => $type,
                    'severity' => $this->map_issue_type_to_severity($issue_type),
                    'description' => $description,
                    'status' => 'ignored',
                    'detected_time' => current_time('mysql'),
                    'resolved_time' => current_time('mysql')
                ],
                ['%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s']
            );
            
            if ($insert_result) {
                // Clean up old ignored entries for this same issue (keep only the latest)
                $wpdb->query($wpdb->prepare(
                    "DELETE FROM {$issues_table} WHERE file_path = %s AND issue_type = %s AND description = %s AND status = 'ignored' AND id != %d",  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
                    $file_path,
                    $issue_type,
                    $description,
                    $wpdb->insert_id
                ));
                
                $this->debug_log[] = '[' . current_time('H:i:s') . '] PRESERVED: Recreated ignored server_state - ' . $description;
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Check IP detection method validation
     */
    private function check_ip_detection_method() {
        $this->debug_log[] = '[IP Detection] Starting IP detection method validation';
        
        // Get current IP detection setting
        $current_method = VMPFence_Config::get('ip_detection_method', 'REMOTE_ADDR');
        $this->debug_log[] = '[IP Detection] Current method: ' . $current_method;
        
        // Test different IP detection methods
        $test_methods = [
            'REMOTE_ADDR' => sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'] ?? '')),
            'HTTP_X_FORWARDED_FOR' => sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR'] ?? '')),
            'HTTP_X_REAL_IP' => sanitize_text_field(wp_unslash($_SERVER['HTTP_X_REAL_IP'] ?? '')),
            'HTTP_CF_CONNECTING_IP' => sanitize_text_field(wp_unslash($_SERVER['HTTP_CF_CONNECTING_IP'] ?? ''))
        ];
        
        $valid_ips = [];
        $local_ips = [];
        
        foreach ($test_methods as $method => $ip) {
            if (!empty($ip) && filter_var($ip, FILTER_VALIDATE_IP)) {
                // Check if it's a public IP
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                    $valid_ips[$method] = $ip;
                    $this->debug_log[] = '[IP Detection] Valid public IP found via ' . $method . ': ' . $ip;
                } else {
                    $local_ips[$method] = $ip;
                    $this->debug_log[] = '[IP Detection] Local/private IP found via ' . $method . ': ' . $ip;
                }
            }
        }
        
        // Check if we're in a development environment
        $is_local_env = (
            strpos(get_site_url(), 'localhost') !== false ||
            strpos(get_site_url(), '127.0.0.1') !== false ||
            strpos(get_site_url(), '192.168.') !== false ||
            strpos(get_site_url(), '10.') !== false ||
            strpos(sanitize_text_field(wp_unslash($_SERVER['SERVER_NAME'] ?? '')), 'localhost') !== false
        );
        
        if (empty($valid_ips) && empty($local_ips)) {
            $this->add_issue('high', 'IP Detection Method Issue',
                'Unable to detect any IP address through any method.',
                'Check server configuration and network settings.',
                'ip_detection'
            );
            $this->debug_log[] = '[IP Detection] ISSUE: No IP detected at all';
        } else if (empty($valid_ips) && !$is_local_env) {
            $this->add_issue('medium', 'No Public IP Detected',
                'Unable to detect valid public IP address. Only private/local IPs found.',
                'Check server configuration and proxy settings for public IP detection.',
                'ip_detection'
            );
            $this->debug_log[] = '[IP Detection] ISSUE: No valid public IP detected (production environment)';
        } else if (empty($valid_ips) && $is_local_env) {
            // For local development, this is expected
            $local_methods = implode(', ', array_keys($local_ips));
            $this->debug_log[] = '[IP Detection] Local development environment detected - using local IPs: ' . $local_methods;
        } else if (count($valid_ips) > 1) {
            $methods = implode(', ', array_keys($valid_ips));
            $this->add_issue('medium', 'Multiple IP Detection Methods',
                "Multiple IP detection methods available: {$methods}. Verify correct method is configured.",
                'Review proxy configuration and select the most reliable IP detection method.',
                'ip_detection'
            );
            $this->debug_log[] = '[IP Detection] WARNING: Multiple methods available';
        } else {
            $this->debug_log[] = '[IP Detection] IP detection method validation passed';
        }
        
        $this->debug_log[] = '[IP Detection] IP detection check completed';
    }
    
    /**
     * Check Web Application Firewall status
     * @since 2.1.0 -- New code to check WAF status
     */
    private function check_waf_status() {
        $this->debug_log[] = '[WAF] Starting Web Application Firewall status check';
        
        // First check if VMPFence's own WAF is enabled
        $vmpfence_waf_enabled = false;
        if (class_exists('VMPFence_Config')) {
            $vmpfence_waf_enabled = VMPFence_Config::get('waf_enabled', 0);
            if ($vmpfence_waf_enabled) {
                $this->debug_log[] = '[WAF] VMPFence WAF is enabled';
                return; // WAF is active, no issue to report
            }
        }
        
        // Check if popular WAF plugins are installed
        $waf_plugins = [
            'wordfence/wordfence.php' => 'Wordfence',
            'sucuri-scanner/sucuri.php' => 'Sucuri',
            'bulletproof-security/bulletproof-security.php' => 'BulletProof Security',
            'all-in-one-wp-security-and-firewall/wp-security.php' => 'All In One WP Security',
            'wp-security-audit-log/wp-security-audit-log.php' => 'WP Security Audit Log'
        ];
        
        $active_waf = null;
        foreach ($waf_plugins as $plugin_path => $plugin_name) {
            if (is_plugin_active($plugin_path)) {
                $active_waf = $plugin_name;
                $this->debug_log[] = '[WAF] Active WAF found: ' . $plugin_name;
                break;
            }
        }
        
        if (!$active_waf) {
            $this->add_issue('high', 'No Web Application Firewall',
                'No active Web Application Firewall detected.',
                'Enable VMPFence WAF in the Firewall settings, or install and configure a WAF plugin.',
                'waf_status'
            );
            $this->debug_log[] = '[WAF] ISSUE: No WAF detected (VMPFence WAF disabled, no other WAF plugins active)';
        }
        
        $this->debug_log[] = '[WAF] WAF status check completed';
    }
    
    /**
     * Check disk space availability
     */
    private function check_disk_space() {
        $this->debug_log[] = '[Disk Space] Starting disk space check';
        
        $total_space = disk_total_space('.');
        $free_space = disk_free_space('.');
        
        if (!$total_space || !$free_space) {
            $this->debug_log[] = '[Disk Space] Unable to access disk space information';
            $this->add_issue('medium', 'Disk Space Information Unavailable',
                'Unable to access disk space information.',
                'Check server permissions and disk access.',
                'disk_space'
            );
            return;
        }
        
        $free_mb = round($free_space / 1024 / 1024, 2);
        $total_mb = round($total_space / 1024 / 1024, 2);
        $free_percentage = round(($free_space / $total_space) * 100, 2);
        
        $this->debug_log[] = '[Disk Space] Total: ' . $total_mb . 'MB, Free: ' . $free_mb . 'MB (' . $free_percentage . '%)';
        
        if ($free_mb < 5) {
            $this->add_issue('critical', 'Critically Low Disk Space',
                "Only {$free_mb}MB disk space remaining.",
                'Free up disk space immediately to prevent website downtime.',
                'disk_space'
            );
            $this->debug_log[] = '[Disk Space] CRITICAL: Less than 5MB free';
        } else if ($free_mb < 20) {
            $this->add_issue('high', 'Low Disk Space',
                "Only {$free_mb}MB disk space remaining.",
                'Free up disk space to prevent potential issues.',
                'disk_space'
            );
            $this->debug_log[] = '[Disk Space] HIGH: Less than 20MB free';
        } else if ($free_percentage < 5) {
            $this->add_issue('medium', 'Low Disk Space Percentage',
                "Only {$free_percentage}% disk space remaining.",
                'Monitor disk usage and clean up unnecessary files.',
                'disk_space'
            );
            $this->debug_log[] = '[Disk Space] MEDIUM: Less than 5% free';
        } else {
            $this->debug_log[] = '[Disk Space] Disk space is adequate';
        }
        
        $this->debug_log[] = '[Disk Space] Disk space check completed';
    }
    
    /**
     * Check for paths skipped in scanning
     */
    private function check_skipped_paths() {
        $this->debug_log[] = '[Skipped Paths] Starting skipped paths check';
        
        // Get VMPFence scan exclusion settings
        $excluded_directories = get_option('vmpfence_excluded_directories', []);
        $excluded_file_types = get_option('vmpfence_excluded_file_types', []);
        
        // Fix: Get the correct scan outside setting from VMPFence config
        $scan_options = VMPFence_Scan_Config::getScanOptions();
        $scan_outside_wp = isset($scan_options['other_scanOutside']) ? $scan_options['other_scanOutside'] : 0;

        $this->debug_log[] = '[Skipped Paths] Scan outside WordPress setting: ' . ($scan_outside_wp ? 'ENABLED' : 'DISABLED');
        
        $skipped_items = [];
        
        // Check if scanning outside WordPress is disabled and find actual paths that would be skipped
        if (!$scan_outside_wp) {
            $wp_root = rtrim(ABSPATH, '/\\');
            $actual_skipped_paths = [];
            
            // First, scan within WordPress root for non-WordPress directories
            $this->debug_log[] = '[Skipped Paths] Scanning WordPress root for non-WP directories: ' . $wp_root;
            
            if (is_dir($wp_root) && is_readable($wp_root)) {
                $wp_entries = scandir($wp_root);
                
                foreach ($wp_entries as $entry) {
                    if ($entry === '.' || $entry === '..') continue;
                    
                    $full_path = $wp_root . DIRECTORY_SEPARATOR . $entry;
                    
                    if (is_dir($full_path)) {
                        // Skip standard WordPress directories
                        if (in_array($entry, ['wp-admin', 'wp-content', 'wp-includes'])) {
                            continue;
                        }
                        
                        // Common non-WordPress folders that should be skipped
                        if (in_array($entry, ['.git', '.svn', '.hg', 'node_modules', 'vendor', 'Research Files', 'documentation', 'backup', 'logs', 'test', 'tests'])) {
                            $actual_skipped_paths[] = $full_path;
                        } elseif (preg_match('/^[A-Z]/', $entry)) {
                            // Capitalized folders (like "Research Files") are often non-WordPress
                            $actual_skipped_paths[] = $full_path;
                        }
                    }
                }
            }
            
            // Then scan parent directory for paths outside WordPress
            $parent_dir = dirname($wp_root);
            if (is_dir($parent_dir) && is_readable($parent_dir)) {
                $this->debug_log[] = '[Skipped Paths] Scanning parent directory: ' . $parent_dir;
                
                $entries = scandir($parent_dir);
                
                foreach ($entries as $entry) {
                    if ($entry === '.' || $entry === '..') continue;
                    
                    $full_path = $parent_dir . DIRECTORY_SEPARATOR . $entry;
                    
                    // Skip if this is the WordPress directory itself
                    if (realpath($full_path) === realpath($wp_root)) {
                        continue;
                    }
                    
                    // This path would be skipped if scan_outside_wp is false
                    if (is_dir($full_path)) {
                        // Common folders that are typically skipped
                        if (in_array($entry, ['.git', '.svn', '.hg', 'node_modules', 'vendor'])) {
                            $actual_skipped_paths[] = $full_path;
                        } elseif (preg_match('/^[A-Z]/', $entry)) {
                            // Capitalized folders (like "Research Files") are often outside WP
                            $actual_skipped_paths[] = $full_path;
                        }
                    }
                }
            }
            
            if (!empty($actual_skipped_paths)) {
                foreach ($actual_skipped_paths as $path) {
                    // Convert to relative path for display
                    if (strpos($path, $wp_root) === 0) {
                        // Path is within WordPress root
                        $display_path = str_replace($wp_root . DIRECTORY_SEPARATOR, '', $path);
                    } else {
                        // Path is outside WordPress root
                        $display_path = str_replace(dirname($wp_root) . DIRECTORY_SEPARATOR, '', $path);
                    }
                    $skipped_items[] = $display_path;
                }
                $this->debug_log[] = '[Skipped Paths] Found actual skipped paths: ' . implode(', ', $actual_skipped_paths);
            } else {
                // Fallback to generic message if no specific paths found
                $skipped_items[] = 'Files outside WordPress installation';
                $this->debug_log[] = '[Skipped Paths] No specific paths found, using generic message';
            }
        }
        
        // Add excluded directories from settings
        if (!empty($excluded_directories)) {
            foreach ($excluded_directories as $dir) {
                $skipped_items[] = $dir;
            }
            $this->debug_log[] = '[Skipped Paths] Excluded directories: ' . implode(', ', $excluded_directories);
        }
        
        // Add excluded file types
        if (!empty($excluded_file_types)) {
            $file_types = implode(', ', $excluded_file_types);
            $skipped_items[] = "File types: {$file_types}";
            $this->debug_log[] = '[Skipped Paths] Excluded file types: ' . $file_types;
        }
        
        if (!empty($skipped_items)) {
            $count = count($skipped_items);
            
            // Create a consolidated issue
            $title = $count === 1 
                ? '1 path was skipped for the malware scan due to scan settings'
                : "{$count} paths were skipped for the malware scan due to scan settings";
            
            // Create detailed description with path list
            $pathText = $count === 1 ? 'path' : 'paths';
            $explanation = $count === 1
                ? 'The option "Scan files outside your WordPress installation" is disabled, so 1 path is not scanned. Ignore this issue to keep skipping it, or enable the option to include it in future scans.'
                : "The option \"Scan files outside your WordPress installation\" is disabled, so {$count} paths are not scanned. Ignore this issue to keep skipping them, or enable the option to include them in future scans.";
            
            // Format path list
            if ($count === 1) {
                $pathList = $skipped_items[0];
            } elseif ($count === 2) {
                $pathList = implode(' and ', $skipped_items);
            } else {
                $lastItem = array_pop($skipped_items);
                $pathList = implode(', ', $skipped_items) . ', and ' . $lastItem;
            }
            
            $description = "{$explanation}\n\nThe {$pathText} skipped " . ($count === 1 ? 'is' : 'are') . ": {$pathList}";
            
            // Store structured data for JavaScript processing
            $structured_data = json_encode([
                'skipped_paths' => $skipped_items,
                'count' => $count,
                'explanation' => $explanation
            ]);
            
            // Add comprehensive logging for debugging
            $this->debug_log[] = '[Skipped Paths] Issue title: ' . $title;
            
            $this->add_issue('low', $title, $description, $structured_data, 'scan_exclusions');
            $this->debug_log[] = '[Skipped Paths] ISSUE: ' . $count . ' items skipped (created consolidated issue)';
        } else {
            $this->debug_log[] = '[Skipped Paths] No paths are being skipped';
        }
        
        $this->debug_log[] = '[Skipped Paths] Skipped paths check completed';
    }
    
    /**
     * Check for public file exposure vulnerabilities
     */
    private function check_public_file_exposure() {
        $this->debug_log[] = '[Public Files] Starting public file exposure check';
        
        // Check for sensitive files that should not be publicly accessible
        $sensitive_files = [
            'wp-config.php' => 'WordPress configuration file',
            '.htaccess' => 'Apache configuration file',
            'readme.html' => 'WordPress readme file',
            'license.txt' => 'WordPress license file',
            'wp-config-sample.php' => 'WordPress config sample',
            'debug.log' => 'WordPress debug log',
            'error_log' => 'Server error log',
            '.env' => 'Environment configuration file'
        ];
        
        $site_url = get_site_url();
        $exposed_files = [];
        
        foreach ($sensitive_files as $file => $description) {
            $file_url = $site_url . '/' . $file;
            
            // Test if file is accessible
            if ($this->ipv4_interceptor) {
                $response = $this->ipv4_interceptor->intercept(function() use ($file_url) {
                    return wp_remote_get($file_url, [
                        'timeout' => 10,
                        'sslverify' => false,
                        'user-agent' => 'VMPFence-Security-Scanner'
                    ]);
                });
            } else {
                $response = wp_remote_get($file_url, [
                    'timeout' => 10,
                    'sslverify' => false,
                    'user-agent' => 'VMPFence-Security-Scanner'
                ]);
            }
            
            if (!is_wp_error($response)) {
                $response_code = wp_remote_retrieve_response_code($response);
                $response_body = wp_remote_retrieve_body($response);
                
                // Check if file is accessible (not 403/404) and contains expected content
                if ($response_code === 200 && !empty($response_body)) {
                    // Additional checks for specific files
                    $is_exposed = false;
                    
                    if ($file === 'wp-config.php' && (strpos($response_body, 'DB_NAME') !== false || strpos($response_body, 'DB_PASSWORD') !== false)) {
                        $is_exposed = true;
                    } elseif ($file === '.htaccess' && strpos($response_body, 'RewriteEngine') !== false) {
                        $is_exposed = true;
                    } elseif (in_array($file, ['readme.html', 'license.txt']) && strlen($response_body) > 100) {
                        $is_exposed = true;
                    } elseif (strpos($file, 'log') !== false && strlen($response_body) > 10) {
                        $is_exposed = true;
                    } elseif ($file === '.env' && (strpos($response_body, '=') !== false)) {
                        $is_exposed = true;
                    }
                    
                    if ($is_exposed) {
                        $exposed_files[] = $file . ' (' . $description . ')';
                        $this->debug_log[] = '[Public Files] EXPOSED: ' . $file;
                    }
                }
            }
        }
        
        // Check for directory listing
        $uploads_dir = wp_upload_dir();
        if (isset($uploads_dir['baseurl'])) {
            if ($this->ipv4_interceptor) {
                $response = $this->ipv4_interceptor->intercept(function() use ($uploads_dir) {
                    return wp_remote_get($uploads_dir['baseurl'], [
                        'timeout' => 10,
                        'sslverify' => false
                    ]);
                });
            } else {
                $response = wp_remote_get($uploads_dir['baseurl'], [
                    'timeout' => 10,
                    'sslverify' => false
                ]);
            }
            
            if (!is_wp_error($response)) {
                $response_body = wp_remote_retrieve_body($response);
                if (stripos($response_body, 'Index of') !== false || stripos($response_body, 'Directory Listing') !== false) {
                    $exposed_files[] = 'uploads directory (directory listing enabled)';
                    $this->debug_log[] = '[Public Files] EXPOSED: Directory listing in uploads';
                }
            }
        }
        
        if (!empty($exposed_files)) {
            $count = count($exposed_files);
            
            // Create individual issues for each exposed file
            foreach ($exposed_files as $exposed_file) {
                $this->add_issue('high', 'Publicly Accessible Sensitive File',
                    "Sensitive file is publicly accessible: {$exposed_file}",
                    'Configure web server to block access to sensitive files and disable directory listing.',
                    'public_files'
                );
            }
            
            $this->debug_log[] = '[Public Files] ISSUE: ' . $count . ' files exposed';
        } else {
            $this->debug_log[] = '[Public Files] No sensitive files are publicly exposed';
        }
        
        $this->debug_log[] = '[Public Files] Public file exposure check completed';
    }
    
    /**
     * Map issue type to severity level
     *
     * @param string $issue_type Issue type
     * @return string Severity level
     */
    private function map_issue_type_to_severity($issue_type) {
        switch ($issue_type) {
            case 'server_state':
                return 'medium';
            default:
                return 'medium';
        }
    }
}
