<?php
if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
}

// Register AJAX handlers
add_action('wp_ajax_moesec_scan_progress', 'moesec_scan_progress_handler');
add_action('wp_ajax_moesec_ajax_scan_progress', 'moesec_scan_progress_handler'); // Handle both action names
add_action('wp_ajax_moesec_refresh_scan_results', 'moesec_refresh_scan_results_handler');
add_action('wp_ajax_moesec_start_file_scan', 'moesec_start_file_scan_handler');
add_action('wp_ajax_moesec_start_db_scan', 'moesec_start_db_scan_handler');
add_action('wp_ajax_moesec_restore_quarantined_file', 'moesec_restore_quarantined_file_handler');
add_action('wp_ajax_moesec_delete_quarantined_file', 'moesec_delete_quarantined_file_handler');

require_once(plugin_dir_path(__FILE__) . 'signature-update.php');

// Function to add CORS headers to AJAX responses
function moesec_add_cors_headers() {
    // Get the origin
    $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
    
    // Allow any origin for AJAX requests
    if (!empty($origin)) {
        header("Access-Control-Allow-Origin: $origin");
    } else {
        header("Access-Control-Allow-Origin: *");
    }
    
    header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
    header('Access-Control-Allow-Credentials: true');
    header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
    
    // Handle preflight OPTIONS requests
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        status_header(200);
        exit();
    }
}

// AJAX handler to restore quarantined file
function moesec_restore_quarantined_file_handler() {
    // Add CORS headers
    moesec_add_cors_headers();
    
    // Check nonce
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'moesec_ajax_nonce')) {
        wp_send_json_error(array(
            'message' => esc_html__('Security check failed.', 'moesec'),
            'error' => 'nonce_verification_failed'
        ));
        exit;
    }

    if (!current_user_can('manage_options')) {
        wp_send_json_error(array(
            'message' => esc_html__('You do not have permission to perform this action.', 'moesec'),
            'error' => 'insufficient_permissions'
        ));
        exit;
    }

    $quarantine_file = isset($_POST['file']) ? sanitize_text_field($_POST['file']) : '';
    $original_path = isset($_POST['original_path']) ? sanitize_text_field($_POST['original_path']) : '';
    
    if (empty($quarantine_file)) {
        wp_send_json_error(array(
            'message' => esc_html__('Missing file information.', 'moesec'),
            'error' => 'missing_file_info'
        ));
        exit;
    }
    
    $quarantine_dir = WP_CONTENT_DIR . '/moesec-quarantine';
    $quarantine_file_path = $quarantine_dir . '/' . $quarantine_file;
    
    // Try to get original path from metadata if not provided
    if (empty($original_path)) {
        $metadata_file = $quarantine_file_path . '.meta';
        if (file_exists($metadata_file)) {
            $metadata = json_decode(file_get_contents($metadata_file), true);
            if ($metadata && isset($metadata['original_path'])) {
                $original_path = $metadata['original_path'];
            }
        }
        
        // If still no original path, try to extract from filename
        if (empty($original_path)) {
            // Extract original filename and try to guess path
            $file_parts = explode('.moesec-quarantine-', $quarantine_file);
            if (count($file_parts) >= 2) {
                $original_filename = $file_parts[0];
                // Default to wp-content/uploads if we can't determine the path
                $original_path = 'wp-content/uploads/' . $original_filename;
            }
        }
    }
    
    if (empty($original_path)) {
        wp_send_json_error(array(
            'message' => esc_html__('Cannot determine original file path.', 'moesec'),
            'error' => 'missing_original_path'
        ));
        exit;
    }
    
    $restore_path = ABSPATH . ltrim($original_path, '/');
    
    // Verify the original path is within WordPress installation
    $real_restore_path = realpath(dirname($restore_path));
    $real_abspath = realpath(ABSPATH);
    
    if ($real_restore_path === false || $real_abspath === false || strpos($real_restore_path, $real_abspath) !== 0) {
        wp_send_json_error(array(
            'message' => esc_html__('Invalid restore path.', 'moesec'),
            'error' => 'invalid_path'
        ));
        exit;
    }
    
    // Create directory if it doesn't exist
    $restore_dir = dirname($restore_path);
    if (!file_exists($restore_dir)) {
        if (!wp_mkdir_p($restore_dir)) {
            wp_send_json_error(array(
                'message' => esc_html__('Failed to create directory for restoration.', 'moesec'),
                'error' => 'directory_creation_failed'
            ));
            exit;
        }
    }
    
    if (file_exists($quarantine_file_path)) {
        // Check if target file exists and make backup if needed
        if (file_exists($restore_path)) {
            $backup_path = $restore_path . '.moesec-backup-' . time();
            if (!copy($restore_path, $backup_path)) {
                wp_send_json_error(array(
                    'message' => esc_html__('Failed to create backup of existing file.', 'moesec'),
                    'error' => 'backup_failed'
                ));
                exit;
            }
        }
        
        if (copy($quarantine_file_path, $restore_path)) {
            // Set proper permissions (644 for files)
            chmod($restore_path, 0644);
            
            // Restore original modification time if available in metadata
            $metadata_file = $quarantine_file_path . '.meta';
            if (file_exists($metadata_file)) {
                $metadata = json_decode(file_get_contents($metadata_file), true);
                if ($metadata && isset($metadata['original_mtime'])) {
                    touch($restore_path, $metadata['original_mtime']);
                }
            }
            
            // Delete the quarantined file and metadata after successful restore
            $deleted_quarantine = unlink($quarantine_file_path);
            $deleted_metadata = true;
            if (file_exists($metadata_file)) {
                $deleted_metadata = unlink($metadata_file);
            }
            
            if ($deleted_quarantine && $deleted_metadata) {
                moesec_log('File restored from quarantine: ' . $original_path);
                wp_send_json_success(array(
                    'message' => esc_html__('File restored successfully.', 'moesec')
                ));
            } else {
                // If we can't delete the quarantined file, log it but still return success
                moesec_log('File restored but could not delete quarantined file: ' . $quarantine_file_path);
                wp_send_json_success(array(
                    'message' => esc_html__('File restored but could not delete quarantined file.', 'moesec')
                ));
            }
        } else {
            wp_send_json_error(array(
                'message' => esc_html__('Failed to restore file. Check permissions.', 'moesec'),
                'error' => 'restore_failed'
            ));
        }
    } else {
        wp_send_json_error(array(
            'message' => esc_html__('Quarantined file not found.', 'moesec'),
            'error' => 'file_not_found'
        ));
    }
}

// AJAX handler to delete quarantined file
function moesec_delete_quarantined_file_handler() {
    // Add CORS headers
    moesec_add_cors_headers();
    
    // Check nonce
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'moesec_ajax_nonce')) {
        wp_send_json_error(array(
            'message' => esc_html__('Security check failed.', 'moesec'),
            'error' => 'nonce_verification_failed'
        ));
        exit;
    }

    if (!current_user_can('manage_options')) {
        wp_send_json_error(array(
            'message' => esc_html__('You do not have permission to perform this action.', 'moesec'),
            'error' => 'insufficient_permissions'
        ));
        exit;
    }

    $quarantine_file = isset($_POST['file']) ? sanitize_text_field($_POST['file']) : '';
    
    if (empty($quarantine_file)) {
        wp_send_json_error(array(
            'message' => esc_html__('Missing file information.', 'moesec'),
            'error' => 'missing_file_info'
        ));
        exit;
    }
    
    $quarantine_dir = WP_CONTENT_DIR . '/moesec-quarantine';
    $quarantine_file_path = $quarantine_dir . '/' . $quarantine_file;
    
    // Validate path to prevent directory traversal
    $real_path = realpath($quarantine_file_path);
    $real_dir = realpath($quarantine_dir);
    
    if ($real_path === false || $real_dir === false || strpos($real_path, $real_dir) !== 0) {
        wp_send_json_error(array(
            'message' => esc_html__('Invalid file path.', 'moesec'),
            'error' => 'invalid_path'
        ));
        exit;
    }
    
    if (file_exists($quarantine_file_path) && unlink($quarantine_file_path)) {
        // Also delete metadata file if it exists
        $metadata_file = $quarantine_file_path . '.meta';
        if (file_exists($metadata_file)) {
            unlink($metadata_file);
        }
        
        moesec_log('Quarantined file deleted: ' . $quarantine_file);
        wp_send_json_success(array(
            'message' => esc_html__('File deleted successfully.', 'moesec')
        ));
    } else {
        wp_send_json_error(array(
            'message' => esc_html__('Failed to delete file. File may not exist or permissions issue.', 'moesec'),
            'error' => 'delete_failed'
        ));
    }
}

// AJAX handler to start file scan
function moesec_start_file_scan_handler() {
    // Add CORS headers
    moesec_add_cors_headers();
    
    // Check nonce
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'moesec_ajax_nonce')) {
        wp_send_json_error(array(
            'message' => esc_html__('Security check failed.', 'moesec'),
            'error' => 'nonce_verification_failed'
        ));
        exit;
    }

    if (!current_user_can('manage_options')) {
        wp_send_json_error(array(
            'message' => esc_html__('You do not have permission to perform this action.', 'moesec'),
            'error' => 'insufficient_permissions'
        ));
        exit;
    }

    // Get scan mode if provided
    $scan_mode = isset($_POST['scan_mode']) ? sanitize_text_field($_POST['scan_mode']) : 'full';
    $custom_path = isset($_POST['custom_path']) ? sanitize_text_field($_POST['custom_path']) : '';
    
    // Store scan mode in a transient for use during scanning
    set_transient('moesec_scan_mode', $scan_mode, 3600);
    set_transient('moesec_scan_custom_path', $custom_path, 3600);

    // Delete any existing progress transient
    delete_transient('moesec_file_scan_progress');
    
    // Set initial progress
    set_transient('moesec_file_scan_progress', 0, 3600);
    
    // Start the scan using WordPress background processing
    wp_schedule_single_event(time(), 'moesec_run_file_scan');
    
    // Log the start of the scan
    moesec_log(sprintf(
        esc_html__('File scan started with mode: %s', 'moesec'),
        $scan_mode
    ));
    
    wp_send_json_success(array(
        'message' => esc_html__('File scan started.', 'moesec')
    ));
}

// AJAX handler to start database scan
function moesec_start_db_scan_handler() {
    // Add CORS headers
    moesec_add_cors_headers();
    
    // Check nonce
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'moesec_ajax_nonce')) {
        wp_send_json_error(array(
            'message' => esc_html__('Security check failed.', 'moesec'),
            'error' => 'nonce_verification_failed'
        ));
        exit;
    }

    if (!current_user_can('manage_options')) {
        wp_send_json_error(array(
            'message' => esc_html__('You do not have permission to perform this action.', 'moesec'),
            'error' => 'insufficient_permissions'
        ));
        exit;
    }

    // Delete any existing progress transient
    delete_transient('moesec_db_scan_progress');
    
    // Set initial progress
    set_transient('moesec_db_scan_progress', 0, 3600);
    
    // Start the scan using WordPress background processing
    wp_schedule_single_event(time(), 'moesec_run_db_scan');
    
    // Log the start of the scan
    moesec_log(esc_html__('Database scan started.', 'moesec'));
    
    wp_send_json_success(array(
        'message' => esc_html__('Database scan started.', 'moesec')
    ));
}

// New AJAX handler to refresh scan results
function moesec_refresh_scan_results_handler() {
    // Add CORS headers
    moesec_add_cors_headers();
    
    // Check nonce
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'moesec_ajax_nonce')) {
        wp_send_json_error(array(
            'message' => esc_html__('Security check failed.', 'moesec'),
            'error' => 'nonce_verification_failed'
        ));
        exit;
    }

    if (!current_user_can('manage_options')) {
        wp_send_json_error(array(
            'message' => esc_html__('You do not have permission to perform this action.', 'moesec'),
            'error' => 'insufficient_permissions'
        ));
        exit;
    }

    $scan_type = isset($_POST['scan_type']) ? sanitize_text_field($_POST['scan_type']) : '';
    
    ob_start();
    if ($scan_type === 'file') {
        $suspicious_files = get_option('moesec_suspicious_files', array());
        moesec_display_suspicious_files($suspicious_files);
    } else if ($scan_type === 'db') {
        $suspicious_db_entries = get_option('moesec_suspicious_db_entries', array());
        moesec_display_suspicious_db_entries($suspicious_db_entries);
    } else if ($scan_type === 'quarantine') {
        moesec_display_quarantined_files();
    }
    $html = ob_get_clean();

    wp_send_json_success(array(
        'html' => $html
    ));
}

function moesec_file_db_scan_tab() {
    if (!current_user_can('manage_options')) {
        wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'moesec'));
    }

    // Handle file actions - only call once
    moesec_handle_file_actions();
    moesec_handle_db_actions();

    // Get default scan settings
    $scan_settings = get_option('moesec_scan_settings', array(
        'file_batch_size' => 1000,
        'max_file_size' => 5, // MB
        'excluded_dirs' => array('wp-content/uploads', 'wp-content/cache'),
        'excluded_extensions' => array('jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'mp3', 'mp4', 'webm', 'pdf', 'sql', 'tar', 'zip', 'gz', 'rar', 'po', 'pot', 'mo', 'css', 'tiff', 'xml', 'json', 'woff', 'woff2', 'ttf', 'eot', 'yaml', 'txt'),
        'db_batch_size' => 100,
        'memory_limit' => 256, // MB
        'execution_time' => 30, // seconds
        'max_files_per_scan' => 500000, // Maximum files to scan in one run
        'scan_mode' => 'full' // Default scan mode
    ));
    
    // Add scan settings form
    if (isset($_POST['moesec_save_scan_settings']) && check_admin_referer('moesec_scan_settings', 'moesec_scan_settings_nonce')) {
        $scan_settings['file_batch_size'] = intval($_POST['file_batch_size']);
        $scan_settings['max_file_size'] = floatval($_POST['max_file_size']);
        $scan_settings['excluded_dirs'] = array_map('trim', explode(',', sanitize_text_field($_POST['excluded_dirs'])));
        $scan_settings['excluded_extensions'] = array_map('trim', explode(',', sanitize_text_field($_POST['excluded_extensions'])));
        $scan_settings['db_batch_size'] = intval($_POST['db_batch_size']);
        $scan_settings['memory_limit'] = intval($_POST['memory_limit']);
        $scan_settings['execution_time'] = intval($_POST['execution_time']);
        $scan_settings['max_files_per_scan'] = intval($_POST['max_files_per_scan']);
        
        update_option('moesec_scan_settings', $scan_settings);
        echo '<div class="updated"><p>' . esc_html__('Scan settings saved successfully.', 'moesec') . '</p></div>';
    }

    $suspicious_files = get_option('moesec_suspicious_files', array());
    $suspicious_db_entries = get_option('moesec_suspicious_db_entries', array());

    ?>
    <div class="wrap">
        <!-- Review Request Section for Scanner -->
        <div class="moesec-scanner-review-request" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px; padding: 20px; margin: 20px 0; text-align: center; box-shadow: 0 4px 15px rgba(0,0,0,0.1);">
            <h4 style="color: white; margin-top: 0; font-size: 18px;">
                <span class="dashicons dashicons-shield-alt" style="color: #ffd700; font-size: 24px; vertical-align: middle;"></span>
                <?php esc_html_e('Found malware or cleaned your site?', 'moesec'); ?>
                <span class="dashicons dashicons-shield-alt" style="color: #ffd700; font-size: 24px; vertical-align: middle;"></span>
            </h4>
            <p style="margin: 15px 0; font-size: 16px; line-height: 1.5;">
                <?php esc_html_e('If our malware scanner helped you detect threats or clean your website, please share your experience with others!', 'moesec'); ?>
            </p>
            <a href="https://wordpress.org/support/plugin/moesec/reviews/#new-post" 
               class="button" 
               target="_blank" 
               style="background: #ffd700; color: #333; border: none; padding: 12px 25px; font-size: 16px; font-weight: bold; border-radius: 25px; text-decoration: none; display: inline-block; transition: all 0.3s ease;">
                <span class="dashicons dashicons-star-filled" style="vertical-align: middle; margin-right: 8px;"></span>
                <?php esc_html_e('Leave a 5-Star Review', 'moesec'); ?>
            </a>
            <p style="font-size: 13px; margin: 15px 0 0 0; opacity: 0.9;">
                <?php esc_html_e('Help other website owners discover MoeSec\'s powerful security features!', 'moesec'); ?>
            </p>
        </div>
        
        <h3><?php esc_html_e('Scan Settings', 'moesec'); ?></h3>
        <form method="post" action="">
            <?php wp_nonce_field('moesec_scan_settings', 'moesec_scan_settings_nonce'); ?>
            <table class="form-table">
                <tr>
                    <th><label for="file_batch_size"><?php esc_html_e('File Batch Size', 'moesec'); ?></label></th>
                    <td>
                        <input type="number" id="file_batch_size" name="file_batch_size" value="<?php echo esc_attr($scan_settings['file_batch_size']); ?>" min="1000" max="5000">
                        <p class="description"><?php esc_html_e('Number of files to process in each batch. Lower values use less resources but take longer.', 'moesec'); ?></p>
                    </td>
                </tr>
                <tr>
                    <th><label for="max_file_size"><?php esc_html_e('Max File Size (MB)', 'moesec'); ?></label></th>
                    <td>
                        <input type="number" id="max_file_size" name="max_file_size" value="<?php echo esc_attr($scan_settings['max_file_size']); ?>" min="1" max="20" step="0.5">
                        <p class="description"><?php esc_html_e('Skip files larger than this size to conserve memory.', 'moesec'); ?></p>
                    </td>
                </tr>
                <tr>
                    <th><label for="excluded_dirs"><?php esc_html_e('Excluded Directories', 'moesec'); ?></label></th>
                    <td>
                        <input type="text" id="excluded_dirs" name="excluded_dirs" value="<?php echo esc_attr(implode(', ', $scan_settings['excluded_dirs'])); ?>" class="large-text">
                        <p class="description"><?php esc_html_e('Comma-separated list of directories to exclude from scanning (relative to WordPress root).', 'moesec'); ?></p>
                    </td>
                </tr>
                <tr>
                    <th><label for="excluded_extensions"><?php esc_html_e('Excluded File Extensions', 'moesec'); ?></label></th>
                    <td>
                        <input type="text" id="excluded_extensions" name="excluded_extensions" value="<?php echo esc_attr(implode(', ', $scan_settings['excluded_extensions'])); ?>" placeholder="<?php esc_attr_e('e.g., jpg, png, pdf, zip, txt, etc', 'moesec'); ?>" class="large-text">
                        <p class="description"><?php esc_html_e('Comma-separated list of file extensions to exclude from scanning (e.g., jpg, png, pdf).', 'moesec'); ?></p>
                    </td>
                </tr>
                <tr>
                    <th><label for="db_batch_size"><?php esc_html_e('Database Batch Size', 'moesec'); ?></label></th>
                    <td>
                        <input type="number" id="db_batch_size" name="db_batch_size" value="<?php echo esc_attr($scan_settings['db_batch_size']); ?>" min="10" max="2000">
                        <p class="description"><?php esc_html_e('Number of database rows to process in each batch.', 'moesec'); ?></p>
                    </td>
                </tr>
                <tr>
                    <th><label for="memory_limit"><?php esc_html_e('Memory Limit (MB)', 'moesec'); ?></label></th>
                    <td>
                        <input type="number" id="memory_limit" name="memory_limit" value="<?php echo esc_attr($scan_settings['memory_limit']); ?>" min="64" max="2048">
                        <p class="description"><?php esc_html_e('Maximum memory to use during scanning. Lower values are better for shared hosting.', 'moesec'); ?></p>
                    </td>
                </tr>
                <tr>
                    <th><label for="execution_time"><?php esc_html_e('Execution Time (seconds)', 'moesec'); ?></label></th>
                    <td>
                        <input type="number" id="execution_time" name="execution_time" value="<?php echo esc_attr($scan_settings['execution_time']); ?>" min="30" max="3600">
                        <p class="description"><?php esc_html_e('Maximum execution time for each batch. Lower values are better for shared hosting.', 'moesec'); ?></p>
                    </td>
                </tr>
                <tr>
                    <th><label for="max_files_per_scan"><?php esc_html_e('Max Files Per Scan', 'moesec'); ?></label></th>
                    <td>
                        <input type="number" id="max_files_per_scan" name="max_files_per_scan" value="<?php echo esc_attr($scan_settings['max_files_per_scan']); ?>" min="100000" max="500000">
                        <p class="description"><?php esc_html_e('Maximum number of files to scan in one run. Lower values are better for shared hosting.', 'moesec'); ?></p>
                    </td>
                </tr>
            </table>
            <p class="submit">
                <input type="submit" name="moesec_save_scan_settings" class="button button-primary" value="<?php esc_attr_e('Save Settings', 'moesec'); ?>">
            </p>
        </form>

        <h3><?php esc_html_e('File Scanner', 'moesec'); ?></h3>
        <div class="scan-options">
            <select id="moesec-scan-mode-select">
                <option value="full"><?php esc_html_e('Full Scan (All Files)', 'moesec'); ?></option>
                <option value="wp-content"><?php esc_html_e('WP-Content Only', 'moesec'); ?></option>
                <option value="plugins"><?php esc_html_e('Plugins Only', 'moesec'); ?></option>
                <option value="themes"><?php esc_html_e('Themes Only', 'moesec'); ?></option>
                <option value="uploads"><?php esc_html_e('Uploads Only', 'moesec'); ?></option>
                <option value="custom"><?php esc_html_e('Custom Path', 'moesec'); ?></option>
            </select>
            <div id="moesec-custom-path-input" style="display: none; margin: 10px 0;">
                <input type="text" id="moesec-custom-path" placeholder="<?php esc_attr_e('Example: /folder or /wp-content/folder', 'moesec'); ?>" class="regular-text">
                <p class="description"><?php esc_html_e('Enter the path relative to WordPress root (without trailing slash)', 'moesec'); ?></p>
            </div>
        </div>
        <button id="moesec-file-scan-button" class="button button-primary"><?php esc_attr_e('Run File Scan', 'moesec'); ?></button>
        <div id="file-scan-progress" class="moesec-progress-bar" style="display: none; margin-top: 10px;">
            <div class="moesec-progress" style="width: 0%;"></div>
        </div>
        <div id="file-scan-status" style="margin-top: 5px;"></div>
        <h4><?php esc_html_e('Suspicious Files', 'moesec'); ?></h4>
        <div id="file-scan-results">
            <?php moesec_display_suspicious_files($suspicious_files); ?>
        </div>

        <h3><?php esc_html_e('Database Scanner', 'moesec'); ?></h3>
        <button id="moesec-db-scan-button" class="button button-primary"><?php esc_attr_e('Run Database Scan', 'moesec'); ?></button>
        <div id="db-scan-progress" class="moesec-progress-bar" style="display: none; margin-top: 10px;">
            <div class="moesec-progress" style="width: 0%;"></div>
        </div>
        <div id="db-scan-status" style="margin-top: 5px;"></div>
        <h4><?php esc_html_e('Suspicious Database Entries', 'moesec'); ?></h4>
        <div id="db-scan-results">
            <?php moesec_display_suspicious_db_entries($suspicious_db_entries); ?>
        </div>

        <h3><?php esc_html_e('Quarantined Files', 'moesec'); ?></h3>
        <button id="moesec-refresh-quarantine" class="button"><?php esc_attr_e('Refresh Quarantine List', 'moesec'); ?></button>
        <div id="quarantine-results">
            <?php moesec_display_quarantined_files(); ?>
        </div>
        
        <?php
        // Display whitelisted files
        $whitelisted_files = get_option('moesec_whitelisted_files', array());
        if (!empty($whitelisted_files)) {
            echo '<h3>' . esc_html__('Whitelisted Files', 'moesec') . '</h3>';
            echo '<table class="widefat">';
            echo '<thead><tr><th>' . esc_html__('File', 'moesec') . '</th><th>' . esc_html__('Action', 'moesec') . '</th></tr></thead>';
            echo '<tbody>';
            foreach ($whitelisted_files as $file) {
                echo '<tr>';
                echo '<td>' . esc_html($file) . '</td>';
                echo '<td><a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=remove_whitelist&file=' . urlencode($file) . '#file-db-scan'), 'moesec_remove_whitelist')) . '" class="button">' . esc_html__('Remove from Whitelist', 'moesec') . '</a></td>';
                echo '</tr>';
            }
            echo '</tbody></table>';
        }
        
        // Display whitelisted database entries
        $whitelisted_db_entries = get_option('moesec_whitelisted_db_entries', array());
        if (!empty($whitelisted_db_entries)) {
            echo '<h3>' . esc_html__('Whitelisted Database Entries', 'moesec') . '</h3>';
            echo '<table class="widefat">';
            echo '<thead><tr><th>' . esc_html__('Table', 'moesec') . '</th><th>' . esc_html__('Column', 'moesec') . '</th><th>' . esc_html__('ID', 'moesec') . '</th><th>' . esc_html__('Action', 'moesec') . '</th></tr></thead>';
            echo '<tbody>';
            foreach ($whitelisted_db_entries as $entry) {
                echo '<tr>';
                echo '<td>' . esc_html($entry['table']) . '</td>';
                echo '<td>' . esc_html($entry['column']) . '</td>';
                echo '<td>' . esc_html($entry['id']) . '</td>';
                echo '<td><a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=remove_db_whitelist&table=' . urlencode($entry['table']) . '&id=' . urlencode($entry['id']) . '&column=' . urlencode($entry['column']) . '#file-db-scan'), 'moesec_remove_db_whitelist')) . '" class="button">' . esc_html__('Remove from Whitelist', 'moesec') . '</a></td>';
                echo '</tr>';
            }
            echo '</tbody></table>';
        }
        ?>
    </div>
    <?php
}

// Schedule the file scan
add_action('moesec_run_file_scan', 'moesec_run_file_scan');
function moesec_run_file_scan() {
    // Get scan mode from transient
    $scan_mode = get_transient('moesec_scan_mode');
    $custom_path = get_transient('moesec_scan_custom_path');
    
    // Log the start of the scan with mode
    moesec_log(sprintf(
        esc_html__('File scan started with mode: %s', 'moesec'),
        $scan_mode ? $scan_mode : 'full'
    ));
    
    $suspicious_files = moesec_scan_files($scan_mode, $custom_path);
    
    update_option('moesec_suspicious_files', $suspicious_files);
    update_option('moesec_last_file_scan_time', current_time('mysql'));
    
    // Set final progress
    set_transient('moesec_file_scan_progress', 100, 3600);
    
    moesec_log(sprintf(
        esc_html__('File scan completed. %d suspicious files detected.', 'moesec'),
        count($suspicious_files)
    ));
    
    // Clean up transients
    delete_transient('moesec_scan_mode');
    delete_transient('moesec_scan_custom_path');
}

// Schedule the database scan
add_action('moesec_run_db_scan', 'moesec_run_db_scan');
function moesec_run_db_scan() {
    
    // Log the start of the scan
    moesec_log(esc_html__('Database scan started.', 'moesec'));
    
    $suspicious_db_entries = moesec_scan_database();
    
    update_option('moesec_suspicious_db_entries', $suspicious_db_entries);
    update_option('moesec_last_db_scan_time', current_time('mysql'));
    
    // Set final progress
    set_transient('moesec_db_scan_progress', 100, 3600);
    
    moesec_log(sprintf(
        esc_html__('Database scan completed. %d suspicious entries detected.', 'moesec'),
        count($suspicious_db_entries)
    ));
}

function moesec_scan_files($scan_mode = 'full', $custom_path = '') {
    // Set initial progress
    set_transient('moesec_file_scan_progress', 0, 3600);
    
    // Make sure to update progress throughout the scan
    $suspicious_files = array();
    $patterns_file = plugin_dir_path(__FILE__) . '../assets/patterns-files.txt';
    
    // Create patterns file if it doesn't exist
    if (!file_exists($patterns_file)) {
        file_put_contents($patterns_file, '');
    }
    
    $patterns = file($patterns_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    $patterns = array_map('base64_decode', $patterns);

    $wp_root = ABSPATH;
    $whitelisted_files = get_option('moesec_whitelisted_files', array());
    
    // Add plugin pattern files to whitelist
    $plugin_pattern_files = array(
        'wp-content/plugins/moesec/assets/patterns-files.txt',
        'wp-content/plugins/moesec/assets/patterns-dbs.txt'
    );
    
    // Get the plugin directory path relative to ABSPATH
    $plugin_dir = str_replace($wp_root, '', realpath(plugin_dir_path(__FILE__) . '..'));
    $plugin_pattern_files_absolute = array(
        $plugin_dir . '/assets/patterns-files.txt',
        $plugin_dir . '/assets/patterns-dbs.txt'
    );

    // Get scan settings
    $scan_settings = get_option('moesec_scan_settings', array(
        'excluded_extensions' => array('jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'mp3', 'mp4', 'webm', 'pdf', 'sql', 'tar', 'zip', 'gz', 'rar', 'po', 'pot', 'mo', 'css', 'tiff', 'xml', 'json', 'woff', 'woff2', 'ttf', 'eot', 'yaml', 'txt')
    ));
    
    // Determine scan path based on mode
    $scan_path = $wp_root;
    switch ($scan_mode) {
        case 'plugins':
            $scan_path = WP_CONTENT_DIR . '/plugins';
            break;
        case 'wp-content':
            $scan_path = WP_CONTENT_DIR;
            break;
        case 'themes':
            $scan_path = WP_CONTENT_DIR . '/themes';
            break;
        case 'uploads':
            $scan_path = WP_CONTENT_DIR . '/uploads';
            break;
        case 'custom':
            if (!empty($custom_path)) {
                $scan_path = $wp_root . ltrim($custom_path, '/');
            }
            break;
        default:
            $scan_path = $wp_root;
    }
    
    // Get all files to scan using a safer method
    $files_to_scan = moesec_get_files_to_scan($scan_path);
    
    // Get excluded extensions from settings
    $skip_extensions = isset($scan_settings['excluded_extensions']) ? $scan_settings['excluded_extensions'] : array('jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'mp3', 'mp4', 'webm', 'pdf', 'sql', 'tar', 'zip', 'gz', 'rar', 'po', 'pot', 'mo', 'css', 'tiff', 'xml', 'json', 'woff', 'woff2', 'ttf', 'eot', 'yaml', 'txt');
    
    // Filter files to scan
    $filtered_files = array();
    foreach ($files_to_scan as $file) {
        $relative_path = str_replace($wp_root, '', $file);
        
        // Skip whitelisted files
        if (in_array($relative_path, $whitelisted_files)) {
            continue;
        }
        
        // Skip plugin pattern files
        if (in_array($relative_path, $plugin_pattern_files) ||
            in_array($relative_path, $plugin_pattern_files_absolute)) {
            continue;
        }

        // Skip files with excluded extensions
        $extension = strtolower(pathinfo($relative_path, PATHINFO_EXTENSION));
        if (in_array($extension, $skip_extensions)) {
            continue;
        }
        
        // Skip files larger than max_file_size to avoid memory issues
        $max_file_size = isset($scan_settings['max_file_size']) ? (int)$scan_settings['max_file_size'] * 1024 * 1024 : 5 * 1024 * 1024;
        if (file_exists($file) && filesize($file) > $max_file_size) {
            continue;
        }
        
        $filtered_files[] = $file;
    }
    
    $total_files = count($filtered_files);
    $files_processed = 0;
    
    foreach ($filtered_files as $file) {
        $files_processed++;
        
        // Update progress every 50 files or so
        if ($files_processed % 50 === 0 || $files_processed === $total_files) {
            $progress = min(99, round(($files_processed / max(1, $total_files)) * 100));
            set_transient('moesec_file_scan_progress', $progress, 3600);
        }
        
        $relative_path = str_replace($wp_root, '', $file);
        
        // Skip if file doesn't exist or isn't readable
        if (!file_exists($file) || !is_readable($file)) {
            continue;
        }
        
        // Use file streaming instead of loading entire file
        $matched_patterns = array();
        $handle = @fopen($file, 'r');
        
        if ($handle) {
            $content = '';
            while (!feof($handle)) {
                $chunk = @fread($handle, 8192); // Read in 8KB chunks
                if ($chunk === false) {
                    // If reading fails, break the loop
                    break;
                }
                $content .= $chunk;
                
                // Check for patterns in the current chunk
                foreach ($patterns as $pattern) {
                    if (empty($pattern)) continue;
                    
                    if (strpos($pattern, '/') === 0) {
                        // It's a regex pattern
                        if (@preg_match($pattern, $content)) {
                            $matched_patterns[] = $pattern;
                        }
                    } else {
                        // It's a keyword
                        if (stripos($content, $pattern) !== false) {
                            $matched_patterns[] = $pattern;
                        }
                    }
                }
                
                // If we found matches, no need to read more
                if (!empty($matched_patterns)) {
                    break;
                }
                
                // Keep only the last 8KB to check for patterns that might span chunks
                if (strlen($content) > 8192) {
                    $content = substr($content, -8192);
                }
            }
            fclose($handle);
            
            if (!empty($matched_patterns)) {
                $suspicious_files[$relative_path] = $matched_patterns;
            }
        }
    }
    
    // Set final progress
    set_transient('moesec_file_scan_progress', 100, 3600);

    return $suspicious_files;
}

function moesec_scan_database() {
    // Set initial progress
    set_transient('moesec_db_scan_progress', 0, 3600);
    
    global $wpdb;
    $suspicious_entries = array();
    $patterns_file = plugin_dir_path(__FILE__) . '../assets/patterns-dbs.txt';
    
    // Create patterns file if it doesn't exist
    if (!file_exists($patterns_file)) {
        file_put_contents($patterns_file, '');
    }
    
    $patterns = file($patterns_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    $patterns = array_map('base64_decode', $patterns);

    // Get whitelisted database entries
    $whitelisted_db_entries = get_option('moesec_whitelisted_db_entries', array());

    // Get list of tables to exclude from scanning
    $excluded_tables = array(
        $wpdb->prefix . 'posts_meta', // Often contains large serialized data
        $wpdb->prefix . 'woocommerce_sessions', // WooCommerce sessions can be large
        $wpdb->prefix . 'actionscheduler_logs', // Action Scheduler logs
        $wpdb->prefix . 'revslider_slides', // Revolution Slider slides
    );
    
    // List of option names to exclude from scanning
    $excluded_options = array(
        'moesec_suspicious_files',
        'moesec_suspicious_db_entries',
        'moesec_whitelisted_files',
        'moesec_whitelisted_db_entries',
        'moesec_last_file_scan_time',
        'moesec_last_db_scan_time',
        'moesec_last_signature_update',
        'moesec_scan_in_progress',
    );
    
    $tables = $wpdb->get_col("SHOW TABLES");
    $total_tables = count($tables);
    $tables_processed = 0;
    
    foreach ($tables as $table) {
        $tables_processed++;
        
        // Update progress for each table
        $progress = min(99, round(($tables_processed / $total_tables) * 100));
        set_transient('moesec_db_scan_progress', $progress, 3600);
        
        // Sanitize table name to prevent SQL injection
        $table = esc_sql($table);
        
        // Skip excluded tables
        if (in_array($table, $excluded_tables)) {
            continue;
        }
        
        // Special handling for options table to exclude our own options
        if ($table == $wpdb->options) {
            // Create placeholders for the SQL query
            $placeholders = implode(',', array_fill(0, count($excluded_options), '%s'));
            
            // Get all options except our own
            $query = $wpdb->prepare(
                "SELECT * FROM {$wpdb->options} WHERE option_name NOT IN ($placeholders)",
                $excluded_options
            );
            
            $results = $wpdb->get_results($query);
            
            foreach ($results as $row) {
                // Check if this entry is whitelisted
                $is_whitelisted = false;
                foreach ($whitelisted_db_entries as $whitelisted_entry) {
                    if ($whitelisted_entry['table'] == $table && 
                        $whitelisted_entry['column'] == 'option_value' && 
                        $whitelisted_entry['id'] == $row->option_id) {
                        $is_whitelisted = true;
                        break;
                    }
                }
                
                if ($is_whitelisted) {
                    continue;
                }
                
                $matched_patterns = array();
                foreach ($patterns as $pattern) {
                    if (empty($pattern)) continue;
                    
                    if (strpos($pattern, '/') === 0) {
                        // It's a regex pattern
                        if (@preg_match($pattern, $row->option_value)) {
                            $matched_patterns[] = $pattern;
                        }
                    } else {
                        // It's a keyword
                        if (stripos($row->option_value, $pattern) !== false) {
                            $matched_patterns[] = $pattern;
                        }
                    }
                }
                if (!empty($matched_patterns)) {
                    $suspicious_entries[] = array(
                        'table' => $table,
                        'column' => 'option_value',
                        'id' => $row->option_id,
                        'patterns' => $matched_patterns
                    );
                }
            }
            
            continue; // Skip the regular processing for options table
        }
        
        // Find primary key column
        $primary_key = 'ID';
        $table_structure = $wpdb->get_results("DESCRIBE {$table}");
        foreach ($table_structure as $column) {
            if ($column->Key == 'PRI') {
                $primary_key = $column->Field;
                break;
            }
        }
        
        // Get columns
        $columns = $wpdb->get_col("DESCRIBE {$table}");
        
        // Get total rows
        $total_rows = $wpdb->get_var("SELECT COUNT(*) FROM {$table}");
        
        // Process in batches to avoid memory issues
        $batch_size = 50;
        $offset = 0;
        
        while ($offset < $total_rows) {
            $results = $wpdb->get_results("SELECT * FROM {$table} LIMIT {$batch_size} OFFSET {$offset}");
            
            foreach ($results as $row) {
                foreach ($columns as $column) {
                    if (!isset($row->$column) || empty($row->$column)) {
                        continue;
                    }
                    
                    // Skip binary data or very large fields
                    if (is_resource($row->$column) || strlen($row->$column) > 1000000) {
                        continue;
                    }
                    
                    // Check if this entry is whitelisted
                    $is_whitelisted = false;
                    foreach ($whitelisted_db_entries as $whitelisted_entry) {
                        if ($whitelisted_entry['table'] == $table && 
                            $whitelisted_entry['column'] == $column && 
                            $whitelisted_entry['id'] == (isset($row->$primary_key) ? $row->$primary_key : '')) {
                            $is_whitelisted = true;
                            break;
                        }
                    }
                    
                    if ($is_whitelisted) {
                        continue;
                    }
                    
                    $matched_patterns = array();
                    foreach ($patterns as $pattern) {
                        if (empty($pattern)) continue;
                        
                        if (strpos($pattern, '/') === 0) {
                            // It's a regex pattern
                            if (@preg_match($pattern, $row->$column)) {
                                $matched_patterns[] = $pattern;
                            }
                        } else {
                            // It's a keyword
                            if (stripos($row->$column, $pattern) !== false) {
                                $matched_patterns[] = $pattern;
                            }
                        }
                    }
                    
                    if (!empty($matched_patterns)) {
                        $suspicious_entries[] = array(
                            'table' => $table,
                            'column' => $column,
                            'id' => isset($row->$primary_key) ? $row->$primary_key : '',
                            'patterns' => $matched_patterns
                        );
                    }
                }
            }
            
            $offset += $batch_size;
            
            // Update progress within batch processing for more granular updates
            $batch_progress = min(99, round(($tables_processed - 1 + ($offset / $total_rows)) / $total_tables * 100));
            set_transient('moesec_db_scan_progress', $batch_progress, 3600);
        }
    }
    
    // Set final progress
    set_transient('moesec_db_scan_progress', 100, 3600);

    return $suspicious_entries;
}

function moesec_get_files_to_scan($root_dir) {
    $files = array();
    $dirs_to_scan = array($root_dir);
    $open_basedir = ini_get('open_basedir');
    $open_basedir_active = !empty($open_basedir);
    
    // Get scan settings
    $scan_settings = get_option('moesec_scan_settings', array(
        'excluded_dirs' => array('wp-content/uploads', 'wp-content/cache', 'wp-content/upgrade', 'wp-content/backup-db', 'wp-content/backups', 'wp-content/ai1wm-backups', 'wp-content/updraft')
    ));
    
    // Default excluded directories
    $excluded_dirs = array();
    
    // Convert relative paths to absolute paths
    foreach ($scan_settings['excluded_dirs'] as $dir) {
        $excluded_dirs[] = ABSPATH . ltrim($dir, '/');
    }
    
    // Always exclude the quarantine directory from scanning
    $quarantine_dir = WP_CONTENT_DIR . '/moesec-quarantine';
    $excluded_dirs[] = $quarantine_dir;
    
    while (!empty($dirs_to_scan)) {
        $current_dir = array_shift($dirs_to_scan);
        
        // Skip if directory doesn't exist
        if (!is_dir($current_dir)) {
            continue;
        }
        
        // Skip if directory is in excluded list
        $skip = false;
        foreach ($excluded_dirs as $excluded_dir) {
            if (strpos($current_dir, $excluded_dir) === 0) {
                $skip = true;
                break;
            }
        }
        if ($skip) {
            continue;
        }
        
        // Try to read the directory safely
        $dir_contents = @scandir($current_dir);
        if ($dir_contents === false) {
            // If we can't read the directory, log it and continue
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('MoeSec: Could not read directory: ' . $current_dir);
            }
            continue;
        }
        
        foreach ($dir_contents as $item) {
            // Skip . and ..
            if ($item === '.' || $item === '..') {
                continue;
            }
            
            $path = $current_dir . '/' . $item;
            $path = str_replace('//', '/', $path); // Normalize path
            
            // Skip if path doesn't exist
            if (!file_exists($path)) {
                continue;
            }
            
            // Handle open_basedir restrictions
            if ($open_basedir_active) {
                // Check if path is within open_basedir restrictions
                $allowed = false;
                $basedirs = explode(PATH_SEPARATOR, $open_basedir);
                foreach ($basedirs as $basedir) {
                    if (strpos($path, $basedir) === 0) {
                        $allowed = true;
                        break;
                    }
                }
                if (!$allowed) {
                    continue; // Skip this path
                }
            }
            
            try {
                if (is_dir($path)) {
                    // Skip if directory is in excluded list
                    $skip = false;
                    foreach ($excluded_dirs as $excluded_dir) {
                        if (strpos($path, $excluded_dir) === 0) {
                            $skip = true;
                            break;
                        }
                    }
                    if (!$skip) {
                        // Add directory to the list to scan
                        $dirs_to_scan[] = $path;
                    }
                } else if (is_file($path) && is_readable($path)) {
                    // Add file to the list of files to scan
                    $files[] = $path;
                }
            } catch (Exception $e) {
                // Skip files/directories that cause exceptions
                if (defined('WP_DEBUG') && WP_DEBUG) {
                    error_log('MoeSec: Exception while scanning: ' . $e->getMessage());
                }
                continue;
            }
        }
    }
    
    return $files;
}

function moesec_prepare_patterns($patterns) {
    return array_map(function($pattern) {
        $pattern = trim($pattern);
        if (strpos($pattern, '/') === 0) {
            // It's already a regex pattern, just return it
            return $pattern;
        } else {
            // It's a keyword, escape it for use in regex
            return '/' . preg_quote($pattern, '/') . '/i';
        }
    }, $patterns);
}

function moesec_display_suspicious_files($suspicious_files) {
    if (!empty($suspicious_files)) {
        echo '<table class="widefat">';
        echo '<thead><tr><th>' . esc_html__('File', 'moesec') . '</th><th>' . esc_html__('Actions', 'moesec') . '</th></tr></thead>';
        echo '<tbody>';
        foreach ($suspicious_files as $file => $patterns) {
            echo '<tr>';
            echo '<td>' . esc_html($file) . '</td>';
            echo '<td>';
            echo '<a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=edit_file&file=' . urlencode($file) . '#file-db-scan'), 'moesec_edit_file')) . '" class="button">' . esc_html__('Edit', 'moesec') . '</a> ';
            echo '<a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=quarantine_file&file=' . urlencode($file) . '#file-db-scan'), 'moesec_quarantine_file')) . '" class="button">' . esc_html__('Quarantine', 'moesec') . '</a> ';
            echo '<a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=delete_file&file=' . urlencode($file) . '#file-db-scan'), 'moesec_delete_file')) . '" class="button" onclick="return confirm(\'' . esc_js(__('Are you sure you want to delete this file?', 'moesec')) . '\');">' . esc_html__('Delete', 'moesec') . '</a> ';
            echo '<a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=whitelist_file&file=' . urlencode($file) . '#file-db-scan'), 'moesec_whitelist_file')) . '" class="button">' . esc_html__('Whitelist', 'moesec') . '</a> ';
            echo '<a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=report_file&file=' . urlencode($file) . '#file-db-scan'), 'moesec_report_file')) . '" class="button">' . esc_html__('Report', 'moesec') . '</a>';
            echo '</td>';
            echo '</tr>';
        }
        echo '</tbody></table>';
    } else {
        echo '<p>' . esc_html__('No suspicious files found.', 'moesec') . '</p>';
    }
}

function moesec_display_suspicious_db_entries($suspicious_db_entries) {
    if (!empty($suspicious_db_entries)) {
        echo '<table class="widefat">';
        echo '<thead><tr><th>' . esc_html__('Table', 'moesec') . '</th><th>' . esc_html__('Column', 'moesec') . '</th><th>' . esc_html__('ID', 'moesec') . '</th><th>' . esc_html__('Actions', 'moesec') . '</th></tr></thead>';
        echo '<tbody>';
        foreach ($suspicious_db_entries as $entry) {
            echo '<tr>';
            echo '<td>' . esc_html($entry['table']) . '</td>';
            echo '<td>' . esc_html($entry['column']) . '</td>';
            echo '<td>' . esc_html($entry['id']) . '</td>';
            echo '<td>';
            echo '<a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=edit_db_entry&table=' . urlencode($entry['table']) . '&id=' . urlencode($entry['id']) . '#file-db-scan'), 'moesec_edit_db_entry')) . '" class="button">' . esc_html__('Edit', 'moesec') . '</a> ';
            echo '<a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=delete_db_entry&table=' . urlencode($entry['table']) . '&id=' . urlencode($entry['id']) . '#file-db-scan'), 'moesec_delete_db_entry')) . '" class="button" onclick="return confirm(\'' . esc_js(__('Are you sure you want to delete this database entry?', 'moesec')) . '\');">' . esc_html__('Delete', 'moesec') . '</a> ';
            echo '<a href="' . esc_url(wp_nonce_url(admin_url('admin.php?page=moesec&tab=file-db-scan&action=whitelist_db_entry&table=' . urlencode($entry['table']) . '&id=' . urlencode($entry['id']) . '&column=' . urlencode($entry['column']) . '#file-db-scan'), 'moesec_whitelist_db_entry')) . '" class="button">' . esc_html__('Whitelist', 'moesec') . '</a>';
            echo '</td>';
            echo '</tr>';
        }
        echo '</tbody></table>';
    } else {
        echo '<p>' . esc_html__('No suspicious database entries found.', 'moesec') . '</p>';
    }
}

// Function to display quarantined files with enhanced metadata
function moesec_display_quarantined_files() {
    $quarantine_dir = WP_CONTENT_DIR . '/moesec-quarantine';
    
    if (!file_exists($quarantine_dir)) {
        echo '<p>' . esc_html__('No quarantined files found.', 'moesec') . '</p>';
        return;
    }
    
    $quarantined_files = scandir($quarantine_dir);
    $quarantined_files = array_diff($quarantined_files, array('.', '..', 'index.php'));
    
    // Filter out metadata files from display
    $quarantined_files = array_filter($quarantined_files, function($file) {
        return !preg_match('/\.meta$/', $file);
    });
    
    if (empty($quarantined_files)) {
        echo '<p>' . esc_html__('No quarantined files found.', 'moesec') . '</p>';
        return;
    }
    
    echo '<table class="widefat">';
    echo '<thead><tr>';
    echo '<th>' . esc_html__('Original File', 'moesec') . '</th>';
    echo '<th>' . esc_html__('Original Path', 'moesec') . '</th>';
    echo '<th>' . esc_html__('File Created', 'moesec') . '</th>';
    echo '<th>' . esc_html__('Quarantined On', 'moesec') . '</th>';
    echo '<th>' . esc_html__('Size', 'moesec') . '</th>';
    echo '<th>' . esc_html__('Actions', 'moesec') . '</th>';
    echo '</tr></thead>';
    echo '<tbody>';
    
    foreach ($quarantined_files as $file) {
        $file_path = $quarantine_dir . '/' . $file;
        $metadata_file = $file_path . '.meta';
        
        // Initialize default values
        $original_filename = '';
        $original_path = '';
        $original_mtime = '';
        $quarantine_time = '';
        $file_size = '';
        
        // Try to get metadata
        if (file_exists($metadata_file)) {
            $metadata = json_decode(file_get_contents($metadata_file), true);
            if ($metadata) {
                $original_filename = basename($metadata['original_path']);
                $original_path = $metadata['original_path'];
                $original_mtime = isset($metadata['original_mtime']) ? date('Y-m-d H:i:s', $metadata['original_mtime']) : '';
                $quarantine_time = isset($metadata['quarantine_time']) ? date('Y-m-d H:i:s', $metadata['quarantine_time']) : '';
                $file_size = isset($metadata['file_size']) ? size_format($metadata['file_size']) : '';
            }
        }
        
        // Fallback for files without metadata (legacy quarantined files)
        if (empty($original_filename)) {
            // Extract original filename and timestamp from filename
            if (preg_match('/^(.+)\.moesec-quarantine-(\d+)$/', $file, $matches)) {
                $original_filename = $matches[1];
                $quarantine_time = date('Y-m-d H:i:s', (int)$matches[2]);
                
                // Try to determine the original path (this is an approximation)
                if (preg_match('/^(wp-content|wp-includes|wp-admin)/', $original_filename)) {
                    $original_path = $original_filename;
                } else {
                    // Default to wp-content/uploads if we can't determine the path
                    $original_path = 'wp-content/uploads/' . $original_filename;
                }
            } else if (preg_match('/^(.+)\.(\d+)$/', $file, $matches)) {
                // Handle old quarantine format (filename.timestamp)
                $original_filename = $matches[1];
                $quarantine_time = date('Y-m-d H:i:s', (int)$matches[2]);
                $original_path = 'wp-content/uploads/' . $original_filename;
            } else {
                $original_filename = $file;
                $original_path = 'Unknown';
                $quarantine_time = date('Y-m-d H:i:s', filemtime($file_path));
            }
            
            // Get file size if not available
            if (empty($file_size)) {
                $file_size = size_format(filesize($file_path));
            }
        }
        
        echo '<tr>';
        echo '<td>' . esc_html($original_filename) . '</td>';
        echo '<td>' . esc_html($original_path) . '</td>';
        echo '<td>' . esc_html($original_mtime ? $original_mtime : 'Unknown') . '</td>';
        echo '<td>' . esc_html($quarantine_time) . '</td>';
        echo '<td>' . esc_html($file_size) . '</td>';
        echo '<td>';
        echo '<button class="button moesec-restore-file" data-file="' . esc_attr($file) . '" data-original-path="' . esc_attr($original_path) . '">' . esc_html__('Restore', 'moesec') . '</button> ';
        echo '<button class="button moesec-delete-quarantined-file" data-file="' . esc_attr($file) . '">' . esc_html__('Delete', 'moesec') . '</button>';
        echo '</td>';
        echo '</tr>';
    }
    
    echo '</tbody></table>';
}

function moesec_handle_file_actions() {
    if (!current_user_can('manage_options')) {
        return;
    }

    if (isset($_GET['action']) && isset($_GET['file']) && isset($_GET['_wpnonce'])) {
        $action = sanitize_text_field($_GET['action']);
        $file = sanitize_text_field(urldecode($_GET['file']));
        $nonce = sanitize_text_field($_GET['_wpnonce']);

        $full_path = ABSPATH . $file;

        switch ($action) {
            case 'edit_file':
                if (wp_verify_nonce($nonce, 'moesec_edit_file')) {
                    moesec_edit_file($full_path, $file);
                }
                break;
            case 'quarantine_file':
                if (wp_verify_nonce($nonce, 'moesec_quarantine_file')) {
                    moesec_quarantine_file($full_path, $file);
                }
                break;
            case 'delete_file':
                if (wp_verify_nonce($nonce, 'moesec_delete_file')) {
                    moesec_delete_file($full_path, $file);
                }
                break;
            case 'whitelist_file':
                if (wp_verify_nonce($nonce, 'moesec_whitelist_file')) {
                    moesec_whitelist_file($file);
                }
                break;
            case 'report_file':
                if (wp_verify_nonce($nonce, 'moesec_report_file')) {
                    if (moesec_report_suspicious_file($full_path, $file)) {
                        echo '<center><div class="updated"><p>' . esc_html__('File reported successfully. You can email security@MoeSec.com', 'moesec') . '</p></div></center>';
                    } else {
                        echo '<center><div class="error"><p>' . esc_html__('Failed to report file. You can email security@MoeSec.com', 'moesec') . '</p></div></center>';
                    }
                }
                break;
            case 'remove_whitelist':
                if (wp_verify_nonce($nonce, 'moesec_remove_whitelist')) {
                    moesec_remove_whitelisted_file($file);
                }
                break;
        }
    }
}

function moesec_handle_db_actions() {
    if (!current_user_can('manage_options')) {
        return;
    }

    if (isset($_GET['action']) && isset($_GET['table']) && isset($_GET['id']) && isset($_GET['_wpnonce'])) {
        $action = sanitize_text_field($_GET['action']);
        $table = sanitize_text_field($_GET['table']);
        $id = intval($_GET['id']);
        $nonce = sanitize_text_field($_GET['_wpnonce']);

        switch ($action) {
            case 'edit_db_entry':
                if (wp_verify_nonce($nonce, 'moesec_edit_db_entry')) {
                    moesec_edit_db_entry($table, $id);
                }
                break;
            case 'delete_db_entry':
                if (wp_verify_nonce($nonce, 'moesec_delete_db_entry')) {
                    moesec_delete_db_entry($table, $id);
                }
                break;
            case 'whitelist_db_entry':
                if (wp_verify_nonce($nonce, 'moesec_whitelist_db_entry')) {
                    $column = isset($_GET['column']) ? sanitize_text_field($_GET['column']) : '';
                    moesec_whitelist_db_entry($table, $id, $column);
                }
                break;
            case 'remove_db_whitelist':
                if (wp_verify_nonce($nonce, 'moesec_remove_db_whitelist')) {
                    $column = isset($_GET['column']) ? sanitize_text_field($_GET['column']) : '';
                    moesec_remove_whitelisted_db_entry($table, $id, $column);
                }
                break;
        }
    }
}

function moesec_edit_file($file, $relative_path) {
if (!current_user_can('edit_themes')) {
        wp_die(esc_html__('You do not have sufficient permissions to edit files.', 'moesec'));
}
    if (isset($_POST['moesec_save_file']) && check_admin_referer('moesec_edit_file', 'moesec_edit_file_nonce')) {
        $content = wp_unslash($_POST['file_content']);
        if (file_put_contents($file, $content) !== false) {
            echo '<center><div class="updated"><p>' . esc_html__('File updated successfully.', 'moesec') . '</p></div></center>';
            moesec_log('File edited: ' . $file);
            
            // Update suspicious files list
            $suspicious_files = get_option('moesec_suspicious_files', array());
            unset($suspicious_files[$relative_path]);
            update_option('moesec_suspicious_files', $suspicious_files);
        } else {
            echo '<center><div class="error"><p>' . esc_html__('Failed to update file. Check file permission or contact support.', 'moesec') . '</p></div></center>';
        }
    }

    $content = file_get_contents($file);
    ?> 
<center>
    <div class="wrap">
        <h3><?php echo esc_html(sprintf(__('Edit File: %s', 'moesec'), $relative_path)); ?></h3>
        <form method="post" action="">
            <?php wp_nonce_field('moesec_edit_file', 'moesec_edit_file_nonce'); ?>
            <textarea name="file_content" rows="10" style="width: 40%; font-family: monospace;"><?php echo esc_textarea($content); ?></textarea>
            <p>
                <input type="submit" name="moesec_save_file" class="button button-primary" value="<?php esc_attr_e('Save Changes', 'moesec'); ?>">
                <a href="<?php echo esc_url(admin_url('admin.php?page=moesec&tab=file-db-scan#file-db-scan')); ?>" class="button"><?php esc_html_e('Cancel', 'moesec'); ?></a>
            </p>
        </form>
    </div>
</center>
    <?php
}

function moesec_quarantine_file($file, $relative_path) {
    if (!current_user_can('edit_themes')) {
        wp_die(esc_html__('You do not have sufficient permissions to quarantine files.', 'moesec'));
    }

    $quarantine_dir = WP_CONTENT_DIR . '/moesec-quarantine';
    if (!file_exists($quarantine_dir)) {
        wp_mkdir_p($quarantine_dir);
        // Add security file
        file_put_contents($quarantine_dir . '/index.php', '<?php // Silence is golden');
    }

    $quarantine_file = $quarantine_dir . '/' . basename($file) . '.moesec-quarantine-' . time();
    
    // Store metadata about the quarantined file
    $metadata = array(
        'original_path' => $relative_path,
        'original_full_path' => $file,
        'original_mtime' => filemtime($file),
        'quarantine_time' => time(),
        'file_size' => filesize($file)
    );
    
    if (@copy($file, $quarantine_file) && unlink($file)) {
        // Save metadata
        file_put_contents($quarantine_file . '.meta', json_encode($metadata));
        
        // Update suspicious files list
        $suspicious_files = get_option('moesec_suspicious_files', array());
        unset($suspicious_files[$relative_path]);
        update_option('moesec_suspicious_files', $suspicious_files);
        
        moesec_log('File quarantined: ' . $file);
        echo '<center><div class="updated"><p>' . esc_html__('File quarantined successfully.', 'moesec') . '</p></div></center>';
    } else {
        echo '<center><div class="error"><p>' . esc_html__('Failed to quarantine file. Check file permissions or contact support.', 'moesec') . '</p></div></center>';
    }
}

function moesec_delete_file($file, $relative_path) {
    if (!current_user_can('delete_themes')) {
        wp_die(esc_html__('You do not have sufficient permissions to delete files.', 'moesec'));
    }

    if (unlink($file)) {
        // Update suspicious files list
        $suspicious_files = get_option('moesec_suspicious_files', array());
        unset($suspicious_files[$relative_path]);
        update_option('moesec_suspicious_files', $suspicious_files);
        
        moesec_log('File deleted: ' . $file);
        echo '<center><div class="updated"><p>' . esc_html__('File deleted successfully.', 'moesec') . '</p></div></center>';
    } else {
        echo '<center><div class="error"><p>' . esc_html__('Failed to delete file. Check file permissions or contact support.', 'moesec') . '</p></div></center>';
    }
}

function moesec_edit_db_entry($table, $id) {
    global $wpdb;

    if (!current_user_can('edit_posts')) {
        wp_die(esc_html__('You do not have sufficient permissions to edit database entries.', 'moesec'));
    }

    $table = esc_sql($table);
    
    // First, try to determine the primary key column
    $primary_key = 'ID'; // Default assumption
    
    // Get table structure to find the primary key
    $table_structure = $wpdb->get_results("DESCRIBE $table");
    foreach ($table_structure as $column) {
        if ($column->Key == 'PRI') {
            $primary_key = $column->Field;
            break;
        }
    }
    
    // If we couldn't find a primary key, try common column names
    if (empty($primary_key)) {
        $common_ids = ['id', 'ID', 'option_id', 'comment_id', 'meta_id', 'post_id', 'user_id', 'term_id'];
        foreach ($common_ids as $possible_id) {
            $column_exists = $wpdb->get_var("SHOW COLUMNS FROM $table LIKE '$possible_id'");
            if ($column_exists) {
                $primary_key = $possible_id;
                break;
            }
        }
    }
    
    // Get the row using the identified primary key
    $query = $wpdb->prepare("SELECT * FROM $table WHERE $primary_key = %s", $id);
    $row = $wpdb->get_row($query);

    if (!$row) {
        // If still not found, try a more flexible approach for the options table
        if ($table == $wpdb->options && is_numeric($id)) {
            $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table WHERE option_id = %d", $id));
        }
        
        // If still not found, display an error
        if (!$row) {
            echo '<center><div class="error"><p>' . esc_html__('Database entry not found. Table: ', 'moesec') . esc_html($table) . ', ID: ' . esc_html($id) . '</p></div></center>';
            echo '<p><a href="' . esc_url(admin_url('admin.php?page=moesec&tab=file-db-scan#file-db-scan')) . '" class="button">' . esc_html__('Back to Scanner', 'moesec') . '</a></p>';
            return;
        }
    }

    if (isset($_POST['moesec_save_db_entry']) && check_admin_referer('moesec_edit_db_entry', 'moesec_edit_db_entry_nonce')) {
        $data = array();
        foreach ($_POST['data'] as $column => $value) {
            // Skip the primary key to avoid updating it
            if ($column != $primary_key) {
                $data[$column] = $value;
            }
        }
        
        $where = array($primary_key => $id);
        $format = array_fill(0, count($data), '%s');
        $where_format = array('%s');

        if ($wpdb->update($table, $data, $where, $format, $where_format) !== false) {
            // Update suspicious entries list
            $suspicious_entries = get_option('moesec_suspicious_db_entries', array());
            foreach ($suspicious_entries as $key => $entry) {
                if ($entry['table'] == $table && $entry['id'] == $id) {
                    unset($suspicious_entries[$key]);
                }
            }
            update_option('moesec_suspicious_db_entries', $suspicious_entries);
            
            moesec_log('Database entry edited: ' . $table . ' (' . $primary_key . ': ' . $id . ')');
            echo '<center><div class="updated"><p>' . esc_html__('Database entry updated successfully.', 'moesec') . '</p></div></center>';
        } else {
            echo '<center><div class="error"><p>' . esc_html__('Failed to update database entry. Check permissions or contact support.', 'moesec') . '</p></div></center>';
        }
    }

    ?>
<center>
    <div class="wrap">
        <h3><?php esc_html_e('Edit Database Entry', 'moesec'); ?></h3>
        <p><?php echo esc_html(sprintf(__('Table: %s, %s: %s', 'moesec'), $table, $primary_key, $id)); ?></p>
        <form method="post" action="">
            <?php wp_nonce_field('moesec_edit_db_entry', 'moesec_edit_db_entry_nonce'); ?>
            <table class="form-table">
                <?php foreach ($row as $column => $value): ?>
                    <tr>
                        <th><label for="<?php echo esc_attr($column); ?>"><?php echo esc_html($column); ?></label></th>
                        <td>
                            <?php if ($column === $primary_key): ?>
                                <?php echo esc_html($value); ?>
                                <input type="hidden" name="data[<?php echo esc_attr($column); ?>]" value="<?php echo esc_attr($value); ?>">
                            <?php else: ?>
                                <textarea name="data[<?php echo esc_attr($column); ?>]" id="<?php echo esc_attr($column); ?>" rows="5" style="width: 40%;"><?php echo esc_textarea($value); ?></textarea>
                            <?php endif; ?>
                        </td>
                    </tr>
                <?php endforeach; ?>
            </table>
            <p>
                <input type="submit" name="moesec_save_db_entry" class="button button-primary" value="<?php esc_attr_e('Save Changes', 'moesec'); ?>">
                <a href="<?php echo esc_url(admin_url('admin.php?page=moesec&tab=file-db-scan#file-db-scan')); ?>" class="button"><?php esc_html_e('Cancel', 'moesec'); ?></a>
            </p>
        </form>
    </div>
</center>
    <?php
}

function moesec_delete_db_entry($table, $id) {
    global $wpdb;

    if (!current_user_can('delete_posts')) {
        wp_die(esc_html__('You do not have sufficient permissions to delete database entries.', 'moesec'));
    }

    $table = esc_sql($table);
    
    // First, try to determine the primary key column
    $primary_key = 'ID'; // Default assumption
    
    // Get table structure to find the primary key
    $table_structure = $wpdb->get_results("DESCRIBE $table");
    foreach ($table_structure as $column) {
        if ($column->Key == 'PRI') {
            $primary_key = $column->Field;
            break;
        }
    }
    
    // If we couldn't find a primary key, try common column names
    if (empty($primary_key)) {
        $common_ids = ['id', 'ID', 'option_id', 'comment_id', 'meta_id', 'post_id', 'user_id', 'term_id'];
        foreach ($common_ids as $possible_id) {
            $column_exists = $wpdb->get_var("SHOW COLUMNS FROM $table LIKE '$possible_id'");
            if ($column_exists) {
                $primary_key = $possible_id;
                break;
            }
        }
    }
    
    // Delete the row using the identified primary key
    if ($wpdb->delete($table, array($primary_key => $id), array('%s')) !== false) {
        // Update suspicious entries list
        $suspicious_entries = get_option('moesec_suspicious_db_entries', array());
        foreach ($suspicious_entries as $key => $entry) {
            if ($entry['table'] == $table && $entry['id'] == $id) {
                unset($suspicious_entries[$key]);
            }
        }
        update_option('moesec_suspicious_db_entries', $suspicious_entries);
        
        moesec_log('Database entry deleted: ' . $table . ' (' . $primary_key . ': ' . $id . ')');
        echo '<center><div class="updated"><p>' . esc_html__('Database entry deleted successfully.', 'moesec') . '</p></div></center>';
    } else {
        echo '<center><div class="error"><p>' . esc_html__('Failed to delete database entry. Check permissions or contact support.', 'moesec') . '</p></div></center>';
    }
}

function moesec_whitelist_file($file) {
    if (!current_user_can('manage_options')) {
        wp_die(esc_html__('You do not have sufficient permissions to whitelist files.', 'moesec'));
    }

    $whitelisted_files = get_option('moesec_whitelisted_files', array());
    if (!in_array($file, $whitelisted_files)) {
        $whitelisted_files[] = $file;
        update_option('moesec_whitelisted_files', $whitelisted_files);

        $suspicious_files = get_option('moesec_suspicious_files', array());
        unset($suspicious_files[$file]);
        update_option('moesec_suspicious_files', $suspicious_files);

        echo '<center><div class="updated"><p>' . esc_html__('File whitelisted successfully.', 'moesec') . '</p></div></center>';
        moesec_log('File whitelisted: ' . $file);
    } else {
        echo '<center><div class="updated"><p>' . esc_html__('File is already whitelisted.', 'moesec') . '</p></div></center>';
    }
}

function moesec_whitelist_db_entry($table, $id, $column) {
    if (!current_user_can('manage_options')) {
        wp_die(esc_html__('You do not have sufficient permissions to whitelist database entries.', 'moesec'));
    }

    $whitelisted_db_entries = get_option('moesec_whitelisted_db_entries', array());
    
    $entry_key = array(
        'table' => $table,
        'id' => $id,
        'column' => $column
    );
    
    // Check if entry is already whitelisted
    $already_whitelisted = false;
    foreach ($whitelisted_db_entries as $whitelisted_entry) {
        if ($whitelisted_entry['table'] == $table && 
            $whitelisted_entry['id'] == $id && 
            $whitelisted_entry['column'] == $column) {
            $already_whitelisted = true;
            break;
        }
    }
    
    if (!$already_whitelisted) {
        $whitelisted_db_entries[] = $entry_key;
        update_option('moesec_whitelisted_db_entries', $whitelisted_db_entries);

        // Remove from suspicious entries list
        $suspicious_entries = get_option('moesec_suspicious_db_entries', array());
        foreach ($suspicious_entries as $key => $entry) {
            if ($entry['table'] == $table && $entry['id'] == $id && $entry['column'] == $column) {
                unset($suspicious_entries[$key]);
            }
        }
        update_option('moesec_suspicious_db_entries', $suspicious_entries);

        echo '<center><div class="updated"><p>' . esc_html__('Database entry whitelisted successfully.', 'moesec') . '</p></div></center>';
        moesec_log('Database entry whitelisted: ' . $table . ' (' . $column . ': ' . $id . ')');
    } else {
        echo '<center><div class="updated"><p>' . esc_html__('Database entry is already whitelisted.', 'moesec') . '</p></div></center>';
    }
}

function moesec_remove_whitelisted_file($file) {
    if (!current_user_can('manage_options')) {
        wp_die(esc_html__('You do not have sufficient permissions to remove whitelisted files.', 'moesec'));
    }

    $whitelisted_files = get_option('moesec_whitelisted_files', array());
    $index = array_search($file, $whitelisted_files);
    if ($index !== false) {
        unset($whitelisted_files[$index]);
        update_option('moesec_whitelisted_files', array_values($whitelisted_files));
        echo '<center><div class="updated"><p>' . esc_html__('File removed from whitelist successfully.', 'moesec') . '</p></div></center>';
        moesec_log('File removed from whitelist: ' . $file);
    } else {
        echo '<center><div class="error"><p>' . esc_html__('File is not in the whitelist.', 'moesec') . '</p></div></center>';
    }
}

function moesec_remove_whitelisted_db_entry($table, $id, $column) {
    if (!current_user_can('manage_options')) {
        wp_die(esc_html__('You do not have sufficient permissions to remove whitelisted database entries.', 'moesec'));
    }

    $whitelisted_db_entries = get_option('moesec_whitelisted_db_entries', array());
    
    foreach ($whitelisted_db_entries as $key => $entry) {
        if ($entry['table'] == $table && $entry['id'] == $id && $entry['column'] == $column) {
            unset($whitelisted_db_entries[$key]);
            update_option('moesec_whitelisted_db_entries', array_values($whitelisted_db_entries));
            echo '<center><div class="updated"><p>' . esc_html__('Database entry removed from whitelist successfully.', 'moesec') . '</p></div></center>';
            moesec_log('Database entry removed from whitelist: ' . $table . ' (' . $column . ': ' . $id . ')');
            return;
        }
    }
    
    echo '<center><div class="error"><p>' . esc_html__('Database entry is not in the whitelist.', 'moesec') . '</p></div></center>';
}

function moesec_report_suspicious_file($file_path) {
    if (!current_user_can('manage_options')) {
        return false;
    }

    $site_url = get_site_url();
    $domain = parse_url($site_url, PHP_URL_HOST);
    $file_name = basename($file_path);
    $file_extension = pathinfo($file_path, PATHINFO_EXTENSION);
    $last_modified = date("Y-m-d H:i:s", @filemtime($file_path));

    // Compress the file
    $zip_file = wp_tempnam('moesec_suspicious_file_') . '.zip';
    if (class_exists('ZipArchive')) {
        $zip = new ZipArchive();
        if ($zip->open($zip_file, ZipArchive::CREATE) === TRUE) {
            $zip->addFile($file_path, $file_name);
            $zip->setEncryptionName($file_name, ZipArchive::EM_AES_256, 'moesec');
            $zip->close();
        } else {
            return false;
        }
    } else {
        return false;
    }

    // Prepare email content
    $to = 'security@moesec.com';
    $subject = sprintf('[MoeSec Plugin Report] Suspicious File from %s', $domain);
    $message = sprintf(
        "A suspicious file has been reported from the MoeSec plugin on %s.\n\n" .
        "File Path: %s\n" .
        "File Name: %s\n" .
        "File Extension: %s\n" .
        "Last Modified: %s\n\n" .
        "The suspicious file is attached to this email for further investigation.",
        esc_html($domain),
        esc_html($file_path),
        esc_html($file_name),
        esc_html($file_extension),
        esc_html($last_modified)
    );

    // Send email with attachment
    $headers = array('Content-Type: text/plain; charset=UTF-8');
    $attachments = array($zip_file);

    $result = wp_mail($to, $subject, $message, $headers, $attachments);

    // Clean up the temporary zip file
    if (file_exists($zip_file)) {
        unlink($zip_file);
    }

    return $result;
}

// AJAX handler for scan progress
function moesec_scan_progress_handler() {
    // Add CORS headers
    moesec_add_cors_headers();
    
    // Check if nonce exists before verifying it
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'moesec_ajax_nonce')) {
        wp_send_json_error(array(
            'message' => esc_html__('Security check failed.', 'moesec'),
            'error' => 'nonce_verification_failed'
        ));
        exit;
    }

    if (!current_user_can('manage_options')) {
        wp_send_json_error(array(
            'message' => esc_html__('You do not have permission to perform this action.', 'moesec'),
            'error' => 'insufficient_permissions'
        ));
        exit;
    }

    $scan_type = isset($_POST['scan_type']) ? sanitize_text_field($_POST['scan_type']) : '';
    
    if ($scan_type === 'file') {
        $progress = get_transient('moesec_file_scan_progress');
        if ($progress === false) {
            $progress = 0;
        }
    } else if ($scan_type === 'db') {
        $progress = get_transient('moesec_db_scan_progress');
        if ($progress === false) {
            $progress = 0;
        }
    } else {
        $progress = 0;
    }

    wp_send_json_success(array(
        'progress' => (int)$progress,
        'message' => $progress < 100 ? esc_html__('Scanning...', 'moesec') : esc_html__('Scan completed', 'moesec')
    ));
}