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

/**
 * WordPress Core Reinstall Functions
 *
 * Provides functionality to safely reinstall WordPress core files
 * without affecting content or settings.
 */

// Define constant for status option prefix
define('WPSEC_CORE_REINSTALL_STATUS_PREFIX', 'wpsec_core_reinstall_status_');

/**
 * Reinstall WordPress core files from official repository
 *
 * @param string $version Version to reinstall, or 'current' for the site's current version
 * @param array $options Array of options:
 *                     - verify_checksums: Whether to verify checksums after reinstall (default: true)
 *                     - backup_first: Whether to backup existing files before replace (default: true)
 *                     - backup_core_only: Whether to only backup core files, not content (default: true)
 *                     - skip_files: Array of files to skip (default: ['wp-config.php'])
 *                     - skip_dirs: Array of directories to skip (default: ['wp-content'])
 *                     - operation_id: Optional operation ID for status tracking
 * @return array|WP_Error Result of the reinstall operation or error
 */
function wpsec_reinstall_wordpress_core($version = 'current', $options = []) {
    global $wp_version, $wpdb;
    
    // Default options
    $default_options = [
        'verify_checksums' => true,
        'backup_first' => true,
        'backup_core_only' => true,
        'skip_files' => ['wp-config.php'],
        'skip_dirs' => ['wp-content'],
        'operation_id' => null,
        'bypass_webhooks' => false,
        'restore_index_files' => false,
    ];
    
    $options = array_merge($default_options, $options);
    
    // Use the provided operation ID or generate a new one
    $operation_id = !empty($options['operation_id']) ? $options['operation_id'] : uniqid('wpsec_core_reinstall_', true);
    
    // Store bypass_webhooks setting
    $bypass_webhooks = !empty($options['bypass_webhooks']);
    update_option('wpsec_core_reinstall_bypass_webhooks_' . $operation_id, $bypass_webhooks);
    
    // Check if metadata already exists (might have been created by the endpoint)
    $existing_metadata = get_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id);
    
    if (!$existing_metadata) {
        // Set up reinstall metadata
        $metadata = [
            'id' => $operation_id,
            'started_at' => current_time('mysql'),
            'status' => 'preparing',
            'version' => $version === 'current' ? $wp_version : $version,
            'current_version' => $wp_version,
            'options' => $options,
            'progress' => 0,
            'log' => []
        ];
        
        // Store metadata
        update_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id, $metadata);
    }
    
    // Log the start of the operation
    wpsec_core_reinstall_log($operation_id, 'Core reinstall operation started');
    wpsec_core_reinstall_log($operation_id, 'Current WordPress version: ' . $wp_version);
    
    // Send initial progress webhook
    if (function_exists('wpsec_send_core_reinstall_progress_webhook')) {
        wpsec_send_core_reinstall_progress_webhook($operation_id, 'in_progress', 'Core reinstall operation started');
    }
    
    // Get temporary directory for downloads
    $temp_dir = get_temp_dir() . 'wpsec_core_reinstall_' . $operation_id;
    if (!wp_mkdir_p($temp_dir)) {
        wpsec_core_reinstall_log($operation_id, 'Failed to create temporary directory', 'error');
        wpsec_core_reinstall_update_status($operation_id, 'failed', 'Failed to create temporary directory');
        return new WP_Error('temp_dir_creation_failed', 'Failed to create temporary directory');
    }
    
    wpsec_core_reinstall_log($operation_id, 'Temporary directory created: ' . $temp_dir);
    
    // Update status
    wpsec_core_reinstall_update_status($operation_id, 'downloading', 'Downloading WordPress core files');
    
    // Send progress webhook for downloading phase
    if (function_exists('wpsec_send_core_reinstall_progress_webhook')) {
        wpsec_send_core_reinstall_progress_webhook($operation_id, 'in_progress', 'Downloading WordPress core files');
    }
    
    // Determine version to download
    $version_to_download = $version === 'current' ? $wp_version : $version;
    
    // Download WordPress package
    $download_url = 'https://wordpress.org/wordpress-' . $version_to_download . '.zip';
    $download_path = $temp_dir . '/wordpress.zip';
    
    wpsec_core_reinstall_log($operation_id, 'Downloading WordPress ' . $version_to_download . ' from: ' . $download_url);
    
    $download_result = wpsec_download_file($download_url, $download_path);
    if (is_wp_error($download_result)) {
        $error_message = 'Download failed: ' . $download_result->get_error_message();
        wpsec_core_reinstall_log($operation_id, $error_message, 'error');
        wpsec_core_reinstall_update_status($operation_id, 'failed', 'Failed to download WordPress package');
        
        // Send failed webhook
        if (function_exists('wpsec_send_core_reinstall_failed_webhook')) {
            wpsec_send_core_reinstall_failed_webhook($operation_id, 'Failed to download WordPress package: ' . $download_result->get_error_message());
        }
        
        // Clean up
        wpsec_core_reinstall_cleanup($temp_dir);
        return $download_result;
    }
    
    wpsec_core_reinstall_log($operation_id, 'WordPress package downloaded successfully');
    wpsec_core_reinstall_update_status($operation_id, 'extracting', 'Extracting WordPress package', 20);
    
    // Send progress webhook for extracting phase
    if (function_exists('wpsec_send_core_reinstall_progress_webhook')) {
        wpsec_send_core_reinstall_progress_webhook($operation_id, 'in_progress', 'Extracting WordPress package');
    }
    
    // Extract package
    $unzip_result = wpsec_unzip_file($download_path, $temp_dir);
    if (is_wp_error($unzip_result)) {
        $error_message = 'Extraction failed: ' . $unzip_result->get_error_message();
        wpsec_core_reinstall_log($operation_id, $error_message, 'error');
        wpsec_core_reinstall_update_status($operation_id, 'failed', 'Failed to extract WordPress package');
        
        // Send failed webhook
        if (function_exists('wpsec_send_core_reinstall_failed_webhook')) {
            wpsec_send_core_reinstall_failed_webhook($operation_id, 'Failed to extract WordPress package: ' . $unzip_result->get_error_message());
        }
        
        // Clean up
        wpsec_core_reinstall_cleanup($temp_dir);
        return $unzip_result;
    }
    
    wpsec_core_reinstall_log($operation_id, 'WordPress package extracted successfully');
    
    // Create backup if requested
    if ($options['backup_first']) {
        wpsec_core_reinstall_update_status($operation_id, 'backing_up', 'Creating backup of current WordPress files', 30);
        
        // Send progress webhook for backup phase
        if (function_exists('wpsec_send_core_reinstall_progress_webhook')) {
            wpsec_send_core_reinstall_progress_webhook($operation_id, 'in_progress', 'Creating backup of current WordPress files');
        }
        
        // Use the standardized backup directory path
        $backup_dir = WP_CONTENT_DIR . '/wpsec-backups/core';
        $backup_path = $backup_dir . '/backup-' . gmdate('Ymd-His') . '.zip';
        
        if (!file_exists($backup_dir)) {
            wp_mkdir_p($backup_dir);
        }
        
        $backup_result = wpsec_core_reinstall_create_backup($operation_id, $backup_path, $options['backup_core_only']);
        if (is_wp_error($backup_result)) {
            $error_message = 'Backup failed: ' . $backup_result->get_error_message();
            wpsec_core_reinstall_log($operation_id, $error_message, 'error');
            wpsec_core_reinstall_update_status($operation_id, 'failed', 'Failed to create backup');
            
            // Send failed webhook
            if (function_exists('wpsec_send_core_reinstall_failed_webhook')) {
                wpsec_send_core_reinstall_failed_webhook($operation_id, 'Failed to create backup: ' . $backup_result->get_error_message());
            }
            
            // Clean up
            wpsec_core_reinstall_cleanup($temp_dir);
            return $backup_result;
        }
        
        wpsec_core_reinstall_log($operation_id, 'Backup created successfully: ' . $backup_path);
        wpsec_core_reinstall_update_metadata($operation_id, 'backup_path', $backup_path);
    }
    
    // Verify checksums if requested
    if ($options['verify_checksums']) {
        wpsec_core_reinstall_update_status($operation_id, 'verifying', 'Verifying file integrity', 50);
        
        // Send progress webhook for verification phase
        if (function_exists('wpsec_send_core_reinstall_progress_webhook')) {
            wpsec_send_core_reinstall_progress_webhook($operation_id, 'in_progress', 'Verifying file integrity');
        }
        
        $verify_result = wpsec_core_reinstall_verify_checksums($operation_id, $temp_dir . '/wordpress', $version_to_download);
        if (is_wp_error($verify_result)) {
            $error_message = 'Checksum verification failed: ' . $verify_result->get_error_message();
            wpsec_core_reinstall_log($operation_id, $error_message, 'error');
            wpsec_core_reinstall_update_status($operation_id, 'failed', 'File integrity verification failed');
            
            // Send failed webhook
            if (function_exists('wpsec_send_core_reinstall_failed_webhook')) {
                wpsec_send_core_reinstall_failed_webhook($operation_id, 'File integrity verification failed: ' . $verify_result->get_error_message());
            }
            
            // Clean up
            wpsec_core_reinstall_cleanup($temp_dir);
            return $verify_result;
        }
        
        wpsec_core_reinstall_log($operation_id, 'File integrity verified successfully');
    }
    
    // Replace core files
    wpsec_core_reinstall_update_status($operation_id, 'replacing', 'Replacing WordPress core files', 60);
    
    // Send progress webhook for replacing phase
    if (function_exists('wpsec_send_core_reinstall_progress_webhook')) {
        wpsec_send_core_reinstall_progress_webhook($operation_id, 'in_progress', 'Replacing WordPress core files');
    }
    
    $replace_result = wpsec_core_reinstall_replace_files($operation_id, $temp_dir . '/wordpress', ABSPATH, $options);
    if (is_wp_error($replace_result)) {
        $error_message = 'File replacement failed: ' . $replace_result->get_error_message();
        wpsec_core_reinstall_log($operation_id, $error_message, 'error');
        wpsec_core_reinstall_update_status($operation_id, 'failed', 'Failed to replace WordPress core files');
        
        // Send failed webhook
        if (function_exists('wpsec_send_core_reinstall_failed_webhook')) {
            wpsec_send_core_reinstall_failed_webhook($operation_id, 'Failed to replace WordPress core files: ' . $replace_result->get_error_message());
        }
        
        // Clean up
        wpsec_core_reinstall_cleanup($temp_dir);
        return $replace_result;
    }
    
    // Restore index.php files in wp-content directories if requested
    if (!empty($options['restore_index_files'])) {
        wpsec_core_reinstall_update_status($operation_id, 'restoring_indexes', 'Restoring index.php files in content directories', 90);
        wpsec_core_reinstall_log($operation_id, 'Restoring index.php files in content directories');
        
        $index_result = wpsec_core_reinstall_restore_index_files($operation_id);
        if (is_wp_error($index_result)) {
            wpsec_core_reinstall_log($operation_id, 'Warning: ' . $index_result->get_error_message(), 'warning');
        } else {
            wpsec_core_reinstall_log($operation_id, 'Successfully restored ' . $index_result . ' index.php files');
        }
    }
    
    wpsec_core_reinstall_log($operation_id, 'Core files replaced successfully');
    
    // Update version in database if necessary
    if ($version !== 'current' && $version !== $wp_version) {
        $wpdb->update($wpdb->options, ['option_value' => $version], ['option_name' => 'db_version']);
        $wpdb->update($wpdb->options, ['option_value' => $version], ['option_name' => 'db_version_raw']);
    }
    
    // Clean up
    wpsec_core_reinstall_update_status($operation_id, 'cleaning_up', 'Cleaning up temporary files', 90);
    
    // Send progress webhook for cleanup phase
    if (function_exists('wpsec_send_core_reinstall_progress_webhook')) {
        wpsec_send_core_reinstall_progress_webhook($operation_id, 'in_progress', 'Cleaning up temporary files');
    }
    
    wpsec_core_reinstall_cleanup($temp_dir);
    
    // Finalize
    $end_time = current_time('mysql');
    wpsec_core_reinstall_log($operation_id, 'Core reinstall operation completed successfully');
    wpsec_core_reinstall_update_status($operation_id, 'completed', 'WordPress core files have been reinstalled successfully', 100);
    wpsec_core_reinstall_update_metadata($operation_id, 'completed_at', $end_time);
    
    // Send completion webhook
    if (function_exists('wpsec_send_core_reinstall_complete_webhook')) {
        // Convert mysql datetime to ISO8601 for the webhook
        $completed_at_iso = gmdate('c', strtotime($end_time));
        wpsec_send_core_reinstall_complete_webhook(
            $operation_id, 
            'WordPress core files have been reinstalled successfully',
            $completed_at_iso
        );
    }
    
    // Get the final metadata
    $final_metadata = get_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id);
    
    return $final_metadata;
}

/**
 * Log a message for the core reinstall operation
 * 
 * @param string $operation_id The operation ID
 * @param string $message The message to log
 * @param string $type The type of log message (info, warning, error)
 */
function wpsec_core_reinstall_log($operation_id, $message, $type = 'info') {
    $metadata = get_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id);
    
    if (!$metadata) {
        return;
    }
    
    if (!isset($metadata['log'])) {
        $metadata['log'] = [];
    }
    
    $log_entry = $message;
    if ($type !== 'info') {
        $log_entry = '[' . strtoupper($type) . '] ' . $message;
    }
    
    $metadata['log'][] = $log_entry;
    
    // Prevent log from growing too large
    if (count($metadata['log']) > 100) {
        array_shift($metadata['log']);
    }
    
    update_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id, $metadata);
    
    // Also log to WordPress log if it's an error
    if ($type === 'error') {
        wpsec_log('Core reinstall error: ' . $message, 'error');
    }
}

/**
 * Update the status of the core reinstall operation
 * 
 * @param string $operation_id The operation ID
 * @param string $status The new status
 * @param string $message A message describing the status
 * @param int $progress The progress percentage (0-100)
 */
function wpsec_core_reinstall_update_status($operation_id, $status, $message = '', $progress = null) {
    $metadata = get_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id);
    
    if (!$metadata) {
        return;
    }
    
    $metadata['status'] = $status;
    $metadata['status_message'] = $message;
    
    if ($progress !== null) {
        $metadata['progress'] = $progress;
    }
    
    update_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id, $metadata);
    
    // Log the status change
    wpsec_core_reinstall_log($operation_id, 'Status changed to: ' . $status . ($message ? ' - ' . $message : ''));
}

/**
 * Update a specific metadata field for the operation
 * 
 * @param string $operation_id The operation ID
 * @param string $key The metadata key to update
 * @param mixed $value The new value
 */
function wpsec_core_reinstall_update_metadata($operation_id, $key, $value) {
    $metadata = get_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id);
    
    if (!$metadata) {
        return;
    }
    
    $metadata[$key] = $value;
    update_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id, $metadata);
}

/**
 * Download a file from a URL to a local path
 * 
 * @param string $url The URL to download from
 * @param string $path The local path to save to
 * @return bool|WP_Error True on success or WP_Error on failure
 */
function wpsec_download_file($url, $path) {
    // Use WordPress HTTP API
    $response = wp_remote_get($url, [
        'timeout' => 300,
        'stream' => true,
        'filename' => $path
    ]);
    
    if (is_wp_error($response)) {
        return $response;
    }
    
    $response_code = wp_remote_retrieve_response_code($response);
    
    if ($response_code !== 200) {
        return new WP_Error(
            'download_failed',
            'Failed to download file. Response code: ' . $response_code
        );
    }
    
    if (!file_exists($path)) {
        return new WP_Error(
            'download_failed',
            'File was not saved to the specified path'
        );
    }
    
    return true;
}

/**
 * Extract a ZIP file
 * 
 * @param string $source The path to the ZIP file
 * @param string $destination The path to extract to
 * @return bool|WP_Error True on success or WP_Error on failure
 */
function wpsec_unzip_file($source, $destination) {
    // Use WordPress file system API
    if (!function_exists('WP_Filesystem')) {
        require_once ABSPATH . 'wp-admin/includes/file.php';
    }
    
    WP_Filesystem();
    global $wp_filesystem;
    
    $result = unzip_file($source, $destination);
    
    if (is_wp_error($result)) {
        return $result;
    }
    
    return true;
}

/**
 * Create a backup of WordPress core
 * 
 * @param string $operation_id The operation ID
 * @param string $backup_path The path to save the backup to
 * @param bool $core_only Whether to backup only core files or everything
 * @return bool|WP_Error True on success or WP_Error on failure
 */
function wpsec_core_reinstall_create_backup($operation_id, $backup_path, $core_only = true) {
    // Use WordPress file system API
    if (!function_exists('WP_Filesystem')) {
        require_once ABSPATH . 'wp-admin/includes/file.php';
    }
    
    WP_Filesystem();
    global $wp_filesystem;
    
    // Ensure backup directory exists
    $backup_dir = dirname($backup_path);
    if (!file_exists($backup_dir)) {
        wp_mkdir_p($backup_dir);
    }
    
    // Set up exclude directories and files
    $exclude_dirs = $core_only ? ['wp-content'] : [];
    $exclude_files = ['wp-config.php'];
    
    // Create a list of files to backup
    $files_to_backup = wpsec_core_reinstall_get_files_list(ABSPATH, $exclude_dirs, $exclude_files);
    
    if (empty($files_to_backup)) {
        return new WP_Error('backup_failed', 'No files found to backup');
    }
    
    wpsec_core_reinstall_log($operation_id, 'Found ' . count($files_to_backup) . ' files to backup');
    
    // Use PclZip directly - no dependency on exec() function
    wpsec_core_reinstall_log($operation_id, 'Creating backup archive with PclZip');
    
    if (!class_exists('PclZip')) {
        require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
    }
    
    // Create a new PclZip object
    $zip = new PclZip($backup_path);
    $result = $zip->create($files_to_backup, PCLZIP_OPT_REMOVE_PATH, ABSPATH);
    
    // Check the result
    if ($result === 0) {
        wpsec_core_reinstall_log($operation_id, 'Backup creation failed: ' . $zip->errorInfo(true), 'error');
        return new WP_Error('backup_failed', 'Failed to create backup: ' . $zip->errorInfo(true));
    }
    
    wpsec_core_reinstall_log($operation_id, 'Backup created successfully at: ' . $backup_path);
    return true;
}

/**
 * Get a list of files to backup
 * 
 * @param string $directory The directory to scan
 * @param array $exclude_dirs Directories to exclude
 * @param array $exclude_files Files to exclude
 * @return array List of file paths
 */
function wpsec_core_reinstall_get_files_list($directory, $exclude_dirs = [], $exclude_files = []) {
    $files = [];
    
    $dir_iterator = new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS);
    $iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
    
    foreach ($iterator as $file) {
        $relative_path = str_replace($directory, '', $file->getPathname());
        $relative_path = ltrim($relative_path, '/\\');
        
        // Skip excluded directories
        foreach ($exclude_dirs as $exclude_dir) {
            if (strpos($relative_path, $exclude_dir) === 0) {
                continue 2;
            }
        }
        
        // Skip excluded files
        if (in_array($relative_path, $exclude_files)) {
            continue;
        }
        
        if ($file->isFile()) {
            $files[] = $relative_path;
        }
    }
    
    return $files;
}

/**
 * Verify the checksums of WordPress files
 * 
 * @param string $operation_id The operation ID
 * @param string $directory The directory containing WordPress files
 * @param string $version The WordPress version
 * @return bool|WP_Error True on success or WP_Error on failure
 */
function wpsec_core_reinstall_verify_checksums($operation_id, $directory, $version) {
    // Get checksums from WordPress API
    $checksums = wpsec_core_reinstall_get_checksums($version);
    
    if (is_wp_error($checksums)) {
        return $checksums;
    }
    
    if (empty($checksums)) {
        wpsec_core_reinstall_log($operation_id, 'No checksums available for WordPress ' . $version, 'warning');
        return true; // Continue without verification
    }
    
    wpsec_core_reinstall_log($operation_id, 'Verifying checksums for ' . count($checksums) . ' files');
    
    $failed_files = [];
    $verified_count = 0;
    
    foreach ($checksums as $file => $checksum) {
        $file_path = $directory . '/' . $file;
        
        if (!file_exists($file_path)) {
            $failed_files[] = $file . ' (missing)';
            continue;
        }
        
        $file_checksum = md5_file($file_path);
        
        if ($file_checksum !== $checksum) {
            $failed_files[] = $file . ' (invalid checksum)';
            continue;
        }
        
        $verified_count++;
    }
    
    wpsec_core_reinstall_log($operation_id, 'Verified checksums for ' . $verified_count . ' files');
    
    if (!empty($failed_files)) {
        // If only a few files fail, log a warning but continue
        if (count($failed_files) <= 5) {
            wpsec_core_reinstall_log($operation_id, 'Checksum verification failed for ' . count($failed_files) . ' files: ' . implode(', ', $failed_files), 'warning');
            return true;
        }
        
        return new WP_Error(
            'checksum_verification_failed',
            'Checksum verification failed for ' . count($failed_files) . ' files'
        );
    }
    
    return true;
}

/**
 * Get WordPress checksums from the API
 * 
 * @param string $version The WordPress version
 * @return array|WP_Error Checksums on success or WP_Error on failure
 */
function wpsec_core_reinstall_get_checksums($version) {
    $url = 'https://api.wordpress.org/core/checksums/1.0/?version=' . $version;
    
    $response = wp_remote_get($url);
    
    if (is_wp_error($response)) {
        return $response;
    }
    
    $body = wp_remote_retrieve_body($response);
    $data = json_decode($body, true);
    
    if (empty($data) || !isset($data['checksums'][$version])) {
        return new WP_Error(
            'checksums_not_available',
            'Checksums are not available for WordPress ' . $version
        );
    }
    
    return $data['checksums'][$version];
}

/**
 * Replace WordPress core files
 * 
 * @param string $operation_id The operation ID
 * @param string $source_dir The source directory containing new files
 * @param string $destination_dir The destination directory
 * @param array $options Options for the replacement
 * @return bool|WP_Error True on success or WP_Error on failure
 */
function wpsec_core_reinstall_replace_files($operation_id, $source_dir, $destination_dir, $options) {
    // Use WordPress file system API
    if (!function_exists('WP_Filesystem')) {
        require_once ABSPATH . 'wp-admin/includes/file.php';
    }
    
    WP_Filesystem();
    global $wp_filesystem;
    
    $skip_dirs = isset($options['skip_dirs']) ? $options['skip_dirs'] : ['wp-content'];
    $skip_files = isset($options['skip_files']) ? $options['skip_files'] : ['wp-config.php'];
    
    // Copy files
    $copy_count = 0;
    $error_count = 0;
    
    $dir_iterator = new RecursiveDirectoryIterator($source_dir, FilesystemIterator::SKIP_DOTS);
    $iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
    
    foreach ($iterator as $file) {
        $relative_path = str_replace($source_dir, '', $file->getPathname());
        $relative_path = ltrim($relative_path, '/\\');
        $destination_path = $destination_dir . '/' . $relative_path;
        
        // Skip directories in the skip list
        foreach ($skip_dirs as $skip_dir) {
            if (strpos($relative_path, $skip_dir) === 0) {
                continue 2;
            }
        }
        
        // Skip files in the skip list
        if (in_array($relative_path, $skip_files)) {
            continue;
        }
        
        // Only copy files, not directories
        if ($file->isFile()) {
            // Create parent directory if it doesn't exist
            $parent_dir = dirname($destination_path);
            if (!file_exists($parent_dir)) {
                if (!wp_mkdir_p($parent_dir)) {
                    wpsec_core_reinstall_log($operation_id, 'Failed to create directory: ' . $parent_dir, 'error');
                    $error_count++;
                    continue;
                }
            }
            
            // Copy file
            if (@copy($file->getPathname(), $destination_path)) {
                $copy_count++;
                
                // Log every 100 files
                if ($copy_count % 100 === 0) {
                    wpsec_core_reinstall_log($operation_id, 'Copied ' . $copy_count . ' files so far');
                    wpsec_core_reinstall_update_status($operation_id, 'replacing', 'Replacing WordPress core files', 70 + (int)(($copy_count / 2000) * 20));
                }
            } else {
                wpsec_core_reinstall_log($operation_id, 'Failed to copy file: ' . $relative_path, 'error');
                $error_count++;
            }
        }
    }
    
    wpsec_core_reinstall_log($operation_id, 'Copied ' . $copy_count . ' files. Failed: ' . $error_count);
    
    if ($error_count > 0) {
        if ($error_count > $copy_count / 2) {
            return new WP_Error(
                'file_replacement_failed',
                'Failed to replace a significant number of files: ' . $error_count
            );
        } else {
            wpsec_core_reinstall_log($operation_id, 'Some files could not be replaced (' . $error_count . '), but the operation was mostly successful', 'warning');
        }
    }
    
    return true;
}

/**
 * Clean up temporary files
 * 
 * @param string $temp_dir The temporary directory to clean up
 */
function wpsec_core_reinstall_cleanup($temp_dir) {
    // Use WordPress file system API
    if (!function_exists('WP_Filesystem')) {
        require_once ABSPATH . 'wp-admin/includes/file.php';
    }
    
    WP_Filesystem();
    global $wp_filesystem;
    
    // Remove the temporary directory and all its contents
    $wp_filesystem->delete($temp_dir, true);
}

/**
 * Restore index.php files in wp-content directories
 * 
 * This function creates/restores the standard WordPress index.php files with "Silence is golden"
 * in wp-content directories without affecting any other user content.
 * 
 * @param string $operation_id The operation ID for logging
 * @return int|WP_Error Number of index files created or WP_Error on failure
 */
function wpsec_core_reinstall_restore_index_files($operation_id) {
    // Define content for index.php files
    $index_content = "<?php\n// Silence is golden\n";
    
    // Define key directories to ensure index files exist in
    $content_dirs = array(
        WP_CONTENT_DIR, // wp-content/
        WP_CONTENT_DIR . '/plugins', // wp-content/plugins/
        WP_CONTENT_DIR . '/themes', // wp-content/themes/
        WP_CONTENT_DIR . '/uploads', // wp-content/uploads/
    );
    
    // Add additional common directories if they exist
    $optional_dirs = array(
        '/cache',
        '/upgrade',
        '/languages',
        '/mu-plugins',
        '/uploads/cache',
        '/uploads/backups',
    );
    
    foreach ($optional_dirs as $opt_dir) {
        $full_path = WP_CONTENT_DIR . $opt_dir;
        if (is_dir($full_path)) {
            $content_dirs[] = $full_path;
        }
    }
    
    // Counter for created files
    $created_count = 0;
    
    // Process all directories
    foreach ($content_dirs as $dir) {
        $index_file = trailingslashit($dir) . 'index.php';
        
        // If directory doesn't exist, skip it
        if (!is_dir($dir)) {
            wpsec_core_reinstall_log($operation_id, "Skipping non-existent directory: {$dir}", 'info');
            continue;
        }
        
        // Create index.php if it doesn't exist or update it if it's empty
        if (!file_exists($index_file) || filesize($index_file) === 0) {
            $result = file_put_contents($index_file, $index_content);
            
            if ($result !== false) {
                $created_count++;
                wpsec_core_reinstall_log($operation_id, "Created index.php in {$dir}", 'info');
            } else {
                wpsec_core_reinstall_log($operation_id, "Failed to create index.php in {$dir}", 'warning');
            }
        }
    }
    
    // Also scan plugin directories for missing index.php files
    if (function_exists('get_plugins')) {
        $plugins = array_keys(get_plugins());
        
        foreach ($plugins as $plugin_file) {
            $plugin_dir = dirname(WP_PLUGIN_DIR . '/' . $plugin_file);
            
            // Only process if this is a plugin subfolder, not the main file
            if ($plugin_dir !== WP_PLUGIN_DIR && is_dir($plugin_dir)) {
                $index_file = trailingslashit($plugin_dir) . 'index.php';
                
                if (!file_exists($index_file) || filesize($index_file) === 0) {
                    $result = file_put_contents($index_file, $index_content);
                    
                    if ($result !== false) {
                        $created_count++;
                        wpsec_core_reinstall_log($operation_id, "Created index.php in plugin directory: {$plugin_dir}", 'info');
                    }
                }
            }
        }
    }
    
    // Scan theme directories
    $theme_root = get_theme_root();
    if (is_dir($theme_root)) {
        $themes = wp_get_themes();
        
        foreach ($themes as $theme_name => $theme_obj) {
            $theme_dir = $theme_root . '/' . $theme_name;
            
            if (is_dir($theme_dir)) {
                $index_file = trailingslashit($theme_dir) . 'index.php';
                
                if (!file_exists($index_file) || filesize($index_file) === 0) {
                    $result = file_put_contents($index_file, $index_content);
                    
                    if ($result !== false) {
                        $created_count++;
                        wpsec_core_reinstall_log($operation_id, "Created index.php in theme directory: {$theme_dir}", 'info');
                    }
                }
            }
        }
    }
    
    return $created_count;
}

/**
 * Get the status of a core reinstall operation
 * 
 * @param string $operation_id The operation ID
 * @return array|WP_Error Operation status or WP_Error if operation not found
 */
function wpsec_get_core_reinstall_status($operation_id) {
    $metadata = get_option(WPSEC_CORE_REINSTALL_STATUS_PREFIX . $operation_id);
    
    if (!$metadata) {
        return new WP_Error(
            'operation_not_found',
            'Core reinstall operation not found'
        );
    }
    
    return $metadata;
}
