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

/**
 * Validate a file path for security
 * 
 * @param string $file_path The file path to validate
 * @param bool $inspection_mode Whether this is used for inspection only (defaults to false)
 * @return bool True if the path is valid and safe, false otherwise
 */
function wpsec_validate_file_path($file_path, $inspection_mode = false) {
    // Normalize path
    $file_path = function_exists('wp_normalize_path') ? wp_normalize_path($file_path) : str_replace('\\', '/', $file_path);
    
    // Log the input to help debugging
    wpsec_log('Validating path: ' . $file_path . ' (inspection_mode: ' . ($inspection_mode ? 'true' : 'false') . ')', 'info');
    wpsec_log('ABSPATH: ' . ABSPATH, 'info');
    wpsec_log('WP_CONTENT_DIR: ' . WP_CONTENT_DIR, 'info');
    
    // Must be an absolute path
    if (!path_is_absolute($file_path)) {
        wpsec_log('Path validation failed: Not an absolute path', 'error');
        return false;
    }
    
    // Basic security checks for both modes
    
    // Check for directory traversal attempts
    if (strpos($file_path, '../') !== false || strpos($file_path, '..\\') !== false) {
        wpsec_log('Path validation failed: Directory traversal detected', 'error');
        return false;
    }
    
    // Disallow certain critical WordPress files
    $critical_files = [
        'wp-config.php',
        'wp-settings.php',
        'wp-load.php'
    ];
    
    foreach ($critical_files as $critical_file) {
        if (preg_match('|/' . preg_quote($critical_file, '|') . '$|', $file_path)) {
            wpsec_log('Path validation failed: Critical WordPress file: ' . $file_path, 'error');
            return false;
        }
    }
    
    // For inspection mode, use relaxed validation that accepts paths from scan results
    if ($inspection_mode) {
        // If this is a scan result path, we trust it's valid
        // We only do basic security checks and make sure it looks like a WordPress path
        
        // Most WordPress paths contain one of these standard directories
        if (strpos($file_path, '/wp-content/') !== false || 
            strpos($file_path, '/wp-includes/') !== false || 
            strpos($file_path, '/wp-admin/') !== false) {
            // Path contains a standard WordPress directory, this is good
            return true;
        }
        
        // For paths that don't have standard WordPress directories, we'll do a more flexible check
        // This helps with non-standard installations or paths from different server configurations
        
        // Accept paths that have htdocs/ followed by wp-content or other WordPress patterns
        if (strpos($file_path, '/htdocs/') !== false && 
            (strpos($file_path, '/plugins/') !== false || 
             strpos($file_path, '/themes/') !== false || 
             strpos($file_path, '/uploads/') !== false)) {
            return true;
        }
        
        // If it has a standard PHP/JS/CSS file extension, likely safe for inspection
        $safe_extensions = ['php', 'js', 'css', 'html', 'htm', 'txt', 'md', 'json'];
        $file_extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
        if (in_array($file_extension, $safe_extensions)) {
            wpsec_log('Path validation accepting file with safe extension: ' . $file_path, 'info');
            return true;
        }
        
        // If we're here, the path doesn't match any of our patterns
        wpsec_log('Path validation failed: Not recognized as a WordPress path: ' . $file_path, 'error');
        return false;
    }
    
    // For file operations (non-inspection mode), perform stricter validation
    
    // Must be within WordPress directory
    $wp_root = function_exists('wp_normalize_path') ? wp_normalize_path(ABSPATH) : str_replace('\\', '/', ABSPATH);
    if (strpos($file_path, $wp_root) !== 0) {
        wpsec_log('Path validation failed: Not within WordPress directory', 'error');
        return false;
    }
    
    // Check if file exists using WP_Filesystem
    $wp_filesystem = wpsec_get_filesystem();
    if (is_wp_error($wp_filesystem)) {
        wpsec_log('Path validation failed: WP_Filesystem error: ' . $wp_filesystem->get_error_message(), 'error');
        return false;
    }
    
    if (!$wp_filesystem->exists($file_path)) {
        wpsec_log('Path validation failed: File does not exist: ' . $file_path, 'error');
        return false;
    }
    
    // Check for symlinks (potential security risk)
    if (is_link($file_path)) {
        wpsec_log('Path validation failed: Symlink not allowed: ' . $file_path, 'error');
        return false;
    }
    
    // Check file size limits
    $max_file_size = 100 * 1024 * 1024; // 100MB limit
    // Check file size using WP_Filesystem
    $file_size = $wp_filesystem->size($file_path);
    if ($file_size > $max_file_size) {
        wpsec_log('Path validation failed: File exceeds size limit (' . round($file_size / (1024 * 1024), 2) . 'MB): ' . $file_path, 'error');
        return false;
    }
    
    // Check file permissions
    if (!$wp_filesystem->is_readable($file_path)) {
        wpsec_log('Path validation warning: File not readable: ' . $file_path, 'error');
        return false;
    }
    
    if (!$wp_filesystem->is_writable($file_path)) {
        wpsec_log('Path validation warning: File not writable: ' . $file_path, 'error');
        return false;
    }
    
    // Additional check for critical WordPress files
    $critical_files = [
        function_exists('wp_normalize_path') ? wp_normalize_path(ABSPATH . 'wp-config.php') : str_replace('\\', '/', ABSPATH . 'wp-config.php'),
        function_exists('wp_normalize_path') ? wp_normalize_path(ABSPATH . 'wp-settings.php') : str_replace('\\', '/', ABSPATH . 'wp-settings.php'),
        function_exists('wp_normalize_path') ? wp_normalize_path(ABSPATH . 'wp-load.php') : str_replace('\\', '/', ABSPATH . 'wp-load.php'),
        function_exists('wp_normalize_path') ? wp_normalize_path(ABSPATH . 'index.php') : str_replace('\\', '/', ABSPATH . 'index.php'),
        function_exists('wp_normalize_path') ? wp_normalize_path(WPSEC_PLUGIN_DIR . 'wpfortai-security.php') : str_replace('\\', '/', WPSEC_PLUGIN_DIR . 'wpfortai-security.php')
    ];
    
    if (in_array($file_path, $critical_files)) {
        wpsec_log('Path validation failed: Critical WordPress file: ' . $file_path, 'error');
        return false;
    }
    
    // Check for dangerous file types in uploads directory
    if (strpos($file_path, function_exists('wp_normalize_path') ? wp_normalize_path(WP_CONTENT_DIR . '/uploads') : str_replace('\\', '/', WP_CONTENT_DIR . '/uploads')) === 0) {
        $dangerous_extensions = ['php', 'phtml', 'php5', 'php7', 'phps', 'cgi', 'pl', 'py', 'jsp', 'asp', 'aspx', 'exe', 'sh'];
        $file_extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
        
        if (in_array($file_extension, $dangerous_extensions)) {
            wpsec_log('Path validation warning: Potentially dangerous file type in uploads directory: ' . $file_path, 'info');
            // We don't block these, just log them as they are likely malicious
        }
    }
    
    return true;
}

/**
 * Create and initialize the quarantine directory
 * 
 * @return string|WP_Error The quarantine directory path or error
 */
function wpsec_get_quarantine_dir() {
    $quarantine_dir = WP_CONTENT_DIR . '/wpsec-quarantine';
    
    // Get WP_Filesystem for file operations
    $wp_filesystem = wpsec_get_filesystem();
    if (is_wp_error($wp_filesystem)) {
        wpsec_log('Failed to initialize filesystem: ' . $wp_filesystem->get_error_message(), 'error');
        return $wp_filesystem;
    }
    
    // Create directory if it doesn't exist
    if (!$wp_filesystem->exists($quarantine_dir)) {
        if (!wp_mkdir_p($quarantine_dir)) {
            wpsec_log('Failed to create quarantine directory', 'error');
            return new WP_Error('quarantine_dir_creation_failed', 'Failed to create quarantine directory');
        }
        
        // Create .htaccess to prevent direct access
        $htaccess_content = "# Prevent direct access to files\n";
        $htaccess_content .= "<FilesMatch \".*\">\n";
        $htaccess_content .= "    Order Allow,Deny\n";
        $htaccess_content .= "    Deny from all\n";
        $htaccess_content .= "</FilesMatch>\n";
        
        // Use WP_Filesystem to write files
        $wp_filesystem->put_contents($quarantine_dir . '/.htaccess', $htaccess_content);
        
        // Create index.php to prevent directory listing
        $wp_filesystem->put_contents($quarantine_dir . '/index.php', '<?php // Silence is golden');
        
        // Create manifest file using WP_Filesystem
        if (!$wp_filesystem->exists($quarantine_dir . '/manifest.json')) {
            $wp_filesystem->put_contents($quarantine_dir . '/manifest.json', json_encode([
                'quarantined_files' => [],
                'last_updated' => time()
            ]));
        }
    }
    
    return $quarantine_dir;
}

/**
 * Get WordPress filesystem object
 * 
 * @return WP_Filesystem_Base|WP_Error WordPress filesystem object or error
 */
function wpsec_get_filesystem() {
    global $wp_filesystem;
    
    if (!function_exists('WP_Filesystem')) {
        require_once ABSPATH . 'wp-admin/includes/file.php';
    }
    
    // Initialize the filesystem if it's not already initialized
    if (!$wp_filesystem) {
        if (false === WP_Filesystem()) {
            wpsec_log('Failed to initialize WordPress filesystem', 'error');
            return new WP_Error('filesystem_init_failed', 'Failed to initialize WordPress filesystem');
        }
    }
    
    return $wp_filesystem;
}

/**
 * Quarantine a file identified as malicious
 * 
 * @param string $file_path The path to the file to quarantine
 * @param string $scan_finding_id Optional scan finding ID for reference
 * @return array|WP_Error Quarantine metadata or error
 */
function wpsec_quarantine_file($file_path, $scan_finding_id = '') {
    wpsec_log('Starting quarantine process for file: ' . $file_path, 'info');
    
    // Get quarantine directory
    $quarantine_dir = wpsec_get_quarantine_dir();
    if (is_wp_error($quarantine_dir)) {
        return $quarantine_dir;
    }
    
    // Generate a unique quarantine ID
    $quarantine_id = uniqid('q_', true);
    
    // Create a safe filename for the quarantined file
    $file_info = pathinfo($file_path);
    $quarantine_filename = $file_info['basename'] . '.' . $quarantine_id . '.quarantine';
    $quarantine_path = $quarantine_dir . '/' . $quarantine_filename;
    
    wpsec_log('Quarantine path: ' . $quarantine_path, 'info');
    
    // Try to use WordPress filesystem API for better security
    $wp_filesystem = wpsec_get_filesystem();
    $using_wp_filesystem = !is_wp_error($wp_filesystem);
    
    if ($using_wp_filesystem) {
        wpsec_log('Using WordPress filesystem API', 'info');
        
        // Get file content for backup before moving
        if (!$wp_filesystem->exists($file_path)) {
            wpsec_log('File does not exist (WP_Filesystem): ' . $file_path, 'error');
            return new WP_Error('file_not_found', 'File does not exist');
        }
        
        $file_content = $wp_filesystem->get_contents($file_path);
        if (false === $file_content) {
            wpsec_log('Failed to read file content (WP_Filesystem): ' . $file_path, 'error');
            return new WP_Error('file_read_failed', 'Failed to read file content');
        }
        
        // Calculate file hash for verification
        $original_hash = md5($file_content);
        wpsec_log('Original file hash: ' . $original_hash, 'info');
        
        // Save file to quarantine
        $quarantine_result = $wp_filesystem->put_contents($quarantine_path, $file_content);
        if (false === $quarantine_result) {
            wpsec_log('Failed to write file to quarantine (WP_Filesystem): ' . $quarantine_path, 'error');
            return new WP_Error('quarantine_write_failed', 'Failed to write file to quarantine');
        }
        
        // Verify the quarantined file
        if (!$wp_filesystem->exists($quarantine_path)) {
            wpsec_log('Quarantine verification failed - file does not exist (WP_Filesystem): ' . $quarantine_path, 'error');
            return new WP_Error('quarantine_verification_failed', 'Failed to verify quarantined file');
        }
        
        // Now delete the original file
        if (!$wp_filesystem->delete($file_path)) {
            wpsec_log('Warning: Failed to delete original file after quarantine (WP_Filesystem): ' . $file_path, 'error');
            // We continue anyway since we have a good backup in quarantine
        } else {
            wpsec_log('Original file deleted successfully (WP_Filesystem): ' . $file_path, 'info');
        }
    } else {
        // Fallback to direct file operations if WP_Filesystem is not available
        wpsec_log('Falling back to direct file operations: ' . $wp_filesystem->get_error_message(), 'warning');
        
        // Get file content for backup before moving
        $file_content = @file_get_contents($file_path);
        if ($file_content === false) {
            wpsec_log('Failed to read file content: ' . $file_path, 'error');
            return new WP_Error('file_read_failed', 'Failed to read file content');
        }
        
        // Calculate file hash for verification
        $original_hash = md5($file_content);
        wpsec_log('Original file hash: ' . $original_hash, 'info');
        
        // Save file to quarantine
        $quarantine_result = @file_put_contents($quarantine_path, $file_content);
        if ($quarantine_result === false) {
            wpsec_log('Failed to write file to quarantine: ' . $quarantine_path, 'error');
            return new WP_Error('quarantine_write_failed', 'Failed to write file to quarantine');
        }
        
        // Verify the quarantined file exists and has the correct content
        if (!file_exists($quarantine_path)) {
            wpsec_log('Quarantine verification failed - file does not exist: ' . $quarantine_path, 'error');
            return new WP_Error('quarantine_verification_failed', 'Failed to verify quarantined file');
        }
        
        $quarantine_hash = md5_file($quarantine_path);
        if ($quarantine_hash !== $original_hash) {
            wpsec_log('Quarantine verification failed - hash mismatch: ' . $quarantine_hash . ' vs ' . $original_hash, 'error');
            @wp_delete_file($quarantine_path); // Clean up the bad quarantine file
            return new WP_Error('quarantine_hash_mismatch', 'Quarantined file hash does not match original');
        }
        
        wpsec_log('Quarantine file verified successfully. Removing original file.', 'info');
        
        // Now that we have a verified backup, delete the original file using WP_Filesystem
        $wp_filesystem = wpsec_get_filesystem();
        if (is_wp_error($wp_filesystem)) {
            wpsec_log('Warning: Failed to initialize WP_Filesystem: ' . $wp_filesystem->get_error_message(), 'error');
            // We continue anyway since we have a good backup in quarantine
        } elseif (!$wp_filesystem->delete($file_path)) {
            wpsec_log('Warning: Failed to delete original file after quarantine: ' . $file_path, 'error');
            // We continue anyway since we have a good backup in quarantine
        } else {
            wpsec_log('Original file deleted successfully: ' . $file_path, 'info');
        }
    }
    
    // Record metadata
    $timestamp = current_time('mysql');
    $metadata = [
        'quarantine_id' => $quarantine_id,
        'original_path' => $file_path,
        'quarantine_path' => $quarantine_path,
        'timestamp' => $timestamp,
        'scan_finding_id' => $scan_finding_id,
        'file_size' => filesize($quarantine_path),
        'file_type' => isset($file_info['extension']) ? $file_info['extension'] : '',
        'file_hash' => $quarantine_hash,
        'detection_type' => 'manual_quarantine'
    ];
    
    // Update manifest
    $manifest_path = $quarantine_dir . '/manifest.json';
    $manifest = json_decode(file_get_contents($manifest_path), true) ?: [];
    $manifest[$quarantine_id] = $metadata;
    file_put_contents($manifest_path, json_encode($manifest, JSON_PRETTY_PRINT));
    
    // Log the action
    wpsec_log(sprintf(
        'File quarantined successfully - ID: %s, Original: %s, Size: %s bytes',
        $quarantine_id,
        $file_path,
        $metadata['file_size']
    ), 'action');
    
    return $metadata;
}

/**
 * Delete a file identified as malicious
 * 
 * @param string $file_path The path to the file to delete
 * @param string $scan_finding_id Optional scan finding ID for reference
 * @param bool $permanent_deletion Whether to permanently delete without quarantine
 * @return bool|WP_Error True on success or error
 */
function wpsec_delete_file($file_path, $scan_finding_id = '', $permanent_deletion = false) {
    // Check if we're doing permanent deletion
    if ($permanent_deletion) {
        wpsec_log('Permanent deletion requested for file: ' . $file_path, 'action');
        
        // Try to use WordPress filesystem API for better security
        $wp_filesystem = wpsec_get_filesystem();
        $using_wp_filesystem = !is_wp_error($wp_filesystem);
        
        if ($using_wp_filesystem) {
            wpsec_log('Using WordPress filesystem API for permanent deletion', 'info');
            
            // Check if file exists
            if (!$wp_filesystem->exists($file_path)) {
                wpsec_log('File does not exist (WP_Filesystem): ' . $file_path, 'error');
                return new WP_Error('file_not_found', 'File does not exist');
            }
            
            // Delete the file
            if (!$wp_filesystem->delete($file_path)) {
                wpsec_log('Failed to permanently delete file (WP_Filesystem): ' . $file_path, 'error');
                return new WP_Error('deletion_failed', 'Failed to permanently delete file');
            }
            
            wpsec_log('File permanently deleted successfully (WP_Filesystem): ' . $file_path, 'action');
        } else {
            // Fallback to direct file operations
            wpsec_log('Falling back to direct file operations for permanent deletion: ' . $wp_filesystem->get_error_message(), 'warning');
            
            // Check if file exists
            if (!file_exists($file_path)) {
                wpsec_log('File does not exist: ' . $file_path, 'error');
                return new WP_Error('file_not_found', 'File does not exist');
            }
            
            // Delete the file
            if (!@wp_delete_file($file_path)) {
                wpsec_log('Failed to permanently delete file: ' . $file_path, 'error');
                return new WP_Error('deletion_failed', 'Failed to permanently delete file');
            }
            
            wpsec_log('File permanently deleted successfully: ' . $file_path, 'action');
        }
        
        return true;
    }
    
    // For standard deletion, first quarantine the file
    $quarantine_result = wpsec_quarantine_file($file_path, $scan_finding_id);
    if (is_wp_error($quarantine_result)) {
        wpsec_log('Failed to quarantine file before deletion: ' . $quarantine_result->get_error_message(), 'error');
        return $quarantine_result;
    }
    
    // File is already moved to quarantine, mark it as deleted in the manifest
    $quarantine_dir = wpsec_get_quarantine_dir();
    if (is_wp_error($quarantine_dir)) {
        return $quarantine_dir;
    }
    
    $manifest_path = $quarantine_dir . '/manifest.json';
    $manifest = json_decode(file_get_contents($manifest_path), true) ?: [];
    
    if (isset($manifest[$quarantine_result['quarantine_id']])) {
        $manifest[$quarantine_result['quarantine_id']]['deleted'] = true;
        $manifest[$quarantine_result['quarantine_id']]['deletion_timestamp'] = current_time('mysql');
        file_put_contents($manifest_path, json_encode($manifest, JSON_PRETTY_PRINT));
    }
    
    // Log the action
    wpsec_log(sprintf(
        'File deleted (with quarantine backup) - Path: %s, Quarantine ID: %s',
        $file_path,
        $quarantine_result['quarantine_id']
    ), 'action');
    
    return $quarantine_result;
}

/**
 * Restore a quarantined file to its original location
 * 
 * @param string $quarantine_id The ID of the quarantined file to restore
 * @return array|WP_Error Restore metadata or error
 */
function wpsec_restore_quarantined_file($quarantine_id) {
    wpsec_log('Starting restore process for quarantine ID: ' . $quarantine_id, 'info');
    
    // Get quarantine directory
    $quarantine_dir = wpsec_get_quarantine_dir();
    if (is_wp_error($quarantine_dir)) {
        return $quarantine_dir;
    }
    
    // Get manifest
    $manifest_path = $quarantine_dir . '/manifest.json';
    $manifest = json_decode(file_get_contents($manifest_path), true) ?: [];
    
    // Check if quarantine ID exists
    if (!isset($manifest[$quarantine_id])) {
        wpsec_log('Quarantine ID not found: ' . $quarantine_id, 'error');
        return new WP_Error('quarantine_id_not_found', 'Quarantine ID not found');
    }
    
    $metadata = $manifest[$quarantine_id];
    $quarantine_path = $metadata['quarantine_path'];
    $original_path = $metadata['original_path'];
    
    wpsec_log('Restoring file from: ' . $quarantine_path . ' to: ' . $original_path, 'info');
    
    // Try to use WordPress filesystem API for better security
    $wp_filesystem = wpsec_get_filesystem();
    $using_wp_filesystem = !is_wp_error($wp_filesystem);
    
    if ($using_wp_filesystem) {
        wpsec_log('Using WordPress filesystem API for restore', 'info');
        
        // Check if quarantined file exists
        if (!$wp_filesystem->exists($quarantine_path)) {
            wpsec_log('Quarantined file not found (WP_Filesystem): ' . $quarantine_path, 'error');
            return new WP_Error('quarantined_file_not_found', 'Quarantined file not found');
        }
        
        // Get file content
        $file_content = $wp_filesystem->get_contents($quarantine_path);
        if (false === $file_content) {
            wpsec_log('Failed to read quarantined file (WP_Filesystem): ' . $quarantine_path, 'error');
            return new WP_Error('quarantine_read_failed', 'Failed to read quarantined file');
        }
        
        // Ensure the directory for the original path exists
        $original_dir = dirname($original_path);
        if (!$wp_filesystem->exists($original_dir)) {
            if (!$wp_filesystem->mkdir($original_dir, FS_CHMOD_DIR)) {
                wpsec_log('Failed to create directory for restore (WP_Filesystem): ' . $original_dir, 'error');
                return new WP_Error('restore_dir_creation_failed', 'Failed to create directory for restore');
            }
        }
        
        // Write the file to its original location
        if (!$wp_filesystem->put_contents($original_path, $file_content)) {
            wpsec_log('Failed to write restored file (WP_Filesystem): ' . $original_path, 'error');
            return new WP_Error('restore_write_failed', 'Failed to write restored file');
        }
        
        // Verify the restored file
        if (!$wp_filesystem->exists($original_path)) {
            wpsec_log('Restore verification failed (WP_Filesystem): ' . $original_path, 'error');
            return new WP_Error('restore_verification_failed', 'Failed to verify restored file');
        }
        
        // Delete the quarantined file
        if (!$wp_filesystem->delete($quarantine_path)) {
            wpsec_log('Warning: Failed to delete quarantined file after restore (WP_Filesystem): ' . $quarantine_path, 'warning');
            // Continue anyway as the restore was successful
        }
    } else {
        // Fallback to direct file operations if WP_Filesystem is not available
        wpsec_log('Falling back to direct file operations for restore: ' . $wp_filesystem->get_error_message(), 'warning');
        
        // Check if quarantined file exists
        if (!file_exists($quarantine_path)) {
            wpsec_log('Quarantined file not found: ' . $quarantine_path, 'error');
            return new WP_Error('quarantined_file_not_found', 'Quarantined file not found');
        }
        
        // Ensure the directory for the original path exists
        $original_dir = dirname($original_path);
        if (!file_exists($original_dir)) {
            if (!wp_mkdir_p($original_dir)) {
                wpsec_log('Failed to create directory for restore: ' . $original_dir, 'error');
                return new WP_Error('restore_dir_creation_failed', 'Failed to create directory for restore');
            }
        }
        
        // Move the file back to its original location
        global $wp_filesystem;
        if (!$wp_filesystem) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
            WP_Filesystem();
        }
        
        if (!$wp_filesystem->move($quarantine_path, $original_path, true)) {
            // If move fails, try copy and delete
            if (!$wp_filesystem->copy($quarantine_path, $original_path, true)) {
                wpsec_log('Failed to restore file: ' . $quarantine_path, 'error');
                return new WP_Error('restore_failed', 'Failed to restore file');
            }
            
            // Delete quarantined file after successful copy
            @wp_delete_file($quarantine_path);
        }
        
        // Verify the restored file exists
        if (!file_exists($original_path)) {
            wpsec_log('Restore verification failed: ' . $original_path, 'error');
            return new WP_Error('restore_verification_failed', 'Failed to verify restored file');
        }
    }
    
    // Update manifest
    $metadata['restored'] = true;
    $metadata['restore_timestamp'] = current_time('mysql');
    $manifest[$quarantine_id] = $metadata;
    file_put_contents($manifest_path, json_encode($manifest, JSON_PRETTY_PRINT));
    
    // Log the action
    wpsec_log(sprintf(
        'File restored - ID: %s, Path: %s',
        $quarantine_id,
        $original_path
    ), 'action');
    
    return $metadata;
}

/**
 * Get a list of all quarantined files
 * 
 * @return array List of quarantined files with metadata
 */
function wpsec_get_quarantined_files() {
    // Get quarantine directory
    $quarantine_dir = wpsec_get_quarantine_dir();
    if (is_wp_error($quarantine_dir)) {
        return [];
    }
    
    // Get manifest
    $manifest_path = $quarantine_dir . '/manifest.json';
    if (!file_exists($manifest_path)) {
        return [];
    }
    
    $manifest = json_decode(file_get_contents($manifest_path), true) ?: [];
    
    // Filter out restored files
    $quarantined_files = array_filter($manifest, function($item) {
        return !isset($item['restored']) || !$item['restored'];
    });
    
    return array_values($quarantined_files);
}

/**
 * Log file action events
 * 
 * @param string $message The log message
 * @param string $type The type of log (info, error, action)
 * @return void
 */
function wpsec_log($message, $type = 'info') {
    // Use the new logger class if it exists, otherwise fall back to error_log
    if (class_exists('WPSEC_Logger')) {
        wpsec_debug_log($message, $type);
    } else if (function_exists('error_log')) {
        $prefix = '';
        switch ($type) {
            case 'error':
                $prefix = '❌ WPSEC ERROR: ';
                break;
            case 'action':
                $prefix = '🔧 WPSEC ACTION: ';
                break;
            default:
                $prefix = '🔍 WPSEC INFO: ';
                break;
        }
        
        wpsec_debug_log($prefix . $message, 'info');
    }
}

/**
 * Process multiple files in batch mode
 * 
 * @param array $files Array of file paths and actions to perform
 * @param string $operation The operation to perform ('quarantine', 'delete')
 * @return array Results of batch operation
 */
function wpsec_batch_process_files($files, $operation = 'quarantine') {
    wpsec_log('Starting batch ' . $operation . ' operation for ' . count($files) . ' files', 'action');
    
    $results = [
        'success' => [],
        'failed' => [],
        'total' => count($files),
        'success_count' => 0,
        'failed_count' => 0,
        'operation' => $operation
    ];
    
    // Process each file
    foreach ($files as $file_data) {
        $file_path = isset($file_data['file_path']) ? $file_data['file_path'] : '';
        $scan_finding_id = isset($file_data['scan_finding_id']) ? $file_data['scan_finding_id'] : '';
        
        if (empty($file_path)) {
            wpsec_log('Skipping file with empty path in batch operation', 'error');
            continue;
        }
        
        // Normalize the file path
        $normalized_path = wpsec_normalize_scan_path($file_path);
        wpsec_log('Batch processing - Original path: ' . $file_path, 'info');
        wpsec_log('Batch processing - Normalized path: ' . $normalized_path, 'info');
        
        // Update file_path to use the normalized version
        $file_path = $normalized_path;
        
        // Validate file path
        if (!wpsec_validate_file_path($file_path)) {
            $results['failed'][] = [
                'file_path' => $file_path,
                'error' => 'Invalid or unsafe file path',
                'scan_finding_id' => $scan_finding_id
            ];
            $results['failed_count']++;
            continue;
        }
        
        // Perform the requested operation
        $operation_result = null;
        
        if ($operation === 'quarantine') {
            $operation_result = wpsec_quarantine_file($file_path, $scan_finding_id);
        } elseif ($operation === 'delete') {
            // For delete operations, we also get quarantine data when not permanent
            $permanent_deletion = isset($file_data['permanent_deletion']) ? ($file_data['permanent_deletion'] === 'yes') : false;
            $operation_result = wpsec_delete_file($file_path, $scan_finding_id, $permanent_deletion);
        } else {
            wpsec_log('Invalid batch operation: ' . $operation, 'error');
            $results['failed'][] = [
                'file_path' => $file_path,
                'error' => 'Invalid operation: ' . $operation,
                'scan_finding_id' => $scan_finding_id
            ];
            $results['failed_count']++;
            continue;
        }
        
        // Process the result
        if (is_wp_error($operation_result)) {
            $results['failed'][] = [
                'file_path' => $file_path,
                'error' => $operation_result->get_error_message(),
                'scan_finding_id' => $scan_finding_id
            ];
            $results['failed_count']++;
        } else {
            // Format the success result based on operation
            $success_item = [
                'file_path' => $file_path,
                'scan_finding_id' => $scan_finding_id
            ];
            
            // For quarantine and non-permanent delete operations, include the full quarantine data
            if (is_array($operation_result) && isset($operation_result['quarantine_id'])) {
                $success_item['result'] = $operation_result;
            } else {
                $success_item['result'] = true;
            }
            
            $results['success'][] = $success_item;
            $results['success_count']++;
        }
    }
    
    // Log summary
    wpsec_log(
        sprintf(
            'Batch %s completed: %d/%d successful, %d failed', 
            $operation, 
            $results['success_count'], 
            $results['total'], 
            $results['failed_count']
        ),
        'action'
    );
    
    return $results;
}

/**
 * Restore multiple quarantined files in batch mode
 * 
 * @param array $quarantine_ids Array of quarantine IDs to restore
 * @return array Results of batch restore operation
 */
function wpsec_batch_restore_files($quarantine_ids) {
    wpsec_log('Starting batch restore operation for ' . count($quarantine_ids) . ' files', 'action');
    
    $results = [
        'success' => [],
        'failed' => [],
        'total' => count($quarantine_ids),
        'success_count' => 0,
        'failed_count' => 0,
        'operation' => 'restore'
    ];
    
    // Process each quarantine ID
    foreach ($quarantine_ids as $quarantine_id) {
        if (empty($quarantine_id)) {
            wpsec_log('Skipping empty quarantine ID in batch restore operation', 'error');
            continue;
        }
        
        wpsec_log('Batch restore - Processing quarantine ID: ' . $quarantine_id, 'info');
        
        // Perform the restore operation
        $operation_result = wpsec_restore_quarantined_file($quarantine_id);
        
        // Process the result
        if (is_wp_error($operation_result)) {
            $results['failed'][] = [
                'quarantine_id' => $quarantine_id,
                'error' => $operation_result->get_error_message()
            ];
            $results['failed_count']++;
        } else {
            $results['success'][] = [
                'quarantine_id' => $quarantine_id,
                'original_path' => $operation_result['original_path'],
                'restored' => true,
                'timestamp' => current_time('mysql')
            ];
            $results['success_count']++;
        }
    }
    
    // Log summary
    wpsec_log(
        sprintf(
            'Batch restore completed: %d/%d successful, %d failed', 
            $results['success_count'], 
            $results['total'], 
            $results['failed_count']
        ),
        'action'
    );
    
    return $results;
}

/**
 * Get detailed file information for better reporting
 * 
 * @param string $file_path Path to the file
 * @return array File information
 */
function wpsec_get_file_info($file_path) {
    // Use WP_Filesystem for file operations
    $wp_filesystem = wpsec_get_filesystem();
    $use_wp_fs = !is_wp_error($wp_filesystem) && is_object($wp_filesystem);
    
    // Check if file exists
    $file_exists = $use_wp_fs ? $wp_filesystem->exists($file_path) : file_exists($file_path);
    if (!$file_exists) {
        return [
            'exists' => false,
            'path' => $file_path
        ];
    }
    
    $file_info = pathinfo($file_path);
    $stat = stat($file_path);
    
    // Get file size using WP_Filesystem or fallback
    $file_size = $use_wp_fs ? $wp_filesystem->size($file_path) : filesize($file_path);
    
    // Unfortunately WP_Filesystem doesn't have a direct equivalent to fileperms
    // so we'll use the direct function for this specific operation
    $file_perms = substr(sprintf('%o', fileperms($file_path)), -4);
    
    return [
        'exists' => true,
        'path' => $file_path,
        'basename' => $file_info['basename'],
        'filename' => $file_info['filename'],
        'extension' => isset($file_info['extension']) ? $file_info['extension'] : '',
        'directory' => $file_info['dirname'],
        'size' => $file_size,
        'size_human' => wpsec_format_file_size($file_size),
        'permissions' => $file_perms,
        'readable' => $wp_filesystem->is_readable($file_path),
        'writable' => $wp_filesystem->is_writable($file_path),
        'owner' => $stat['uid'],
        'group' => $stat['gid'],
        'modified_time' => gmdate('Y-m-d H:i:s', $stat['mtime']),
        'access_time' => gmdate('Y-m-d H:i:s', $stat['atime']),
        'is_file' => is_file($file_path),
        'is_dir' => is_dir($file_path),
        'is_link' => is_link($file_path),
        'mime_type' => function_exists('mime_content_type') ? mime_content_type($file_path) : 'unknown',
        'hash_md5' => md5_file($file_path),
        'hash_sha1' => sha1_file($file_path),
        'relative_path' => str_replace(ABSPATH, '', $file_path)
    ];
}

/**
 * Format file size for human readability
 * 
 * @param int $bytes File size in bytes
 * @return string Formatted file size
 */
function wpsec_format_file_size($bytes) {
    if ($bytes >= 1073741824) {
        return number_format($bytes / 1073741824, 2) . ' GB';
    } elseif ($bytes >= 1048576) {
        return number_format($bytes / 1048576, 2) . ' MB';
    } elseif ($bytes >= 1024) {
        return number_format($bytes / 1024, 2) . ' KB';
    } else {
        return $bytes . ' bytes';
    }
}

/**
 * Convert an absolute server path to a WordPress path relative to ABSPATH
 * 
 * @param string $server_path The absolute server path
 * @return string|false WordPress path relative to ABSPATH or false if not within WordPress
 */
function wpsec_server_path_to_wp_path($server_path) {
    // Normalize paths to handle different directory separators
    $server_path = function_exists('wp_normalize_path') ? wp_normalize_path($server_path) : str_replace('\\', '/', $server_path);
    $abspath = function_exists('wp_normalize_path') ? wp_normalize_path(ABSPATH) : str_replace('\\', '/', ABSPATH);
    
    // Check if the path is within WordPress
    if (strpos($server_path, $abspath) === 0) {
        return ltrim(substr($server_path, strlen($abspath)), '/');
    }
    
    // If not within ABSPATH, try to detect common server path patterns
    // Example: /var/www/site.com/htdocs/wp-content/... -> wp-content/...
    $path_parts = explode('/', $server_path);
    $wp_content_pos = array_search('wp-content', $path_parts);
    
    if ($wp_content_pos !== false) {
        return implode('/', array_slice($path_parts, $wp_content_pos));
    }
    
    // If we can't determine the path, return false
    wpsec_log('Unable to convert server path to WordPress path: ' . $server_path, 'error');
    return false;
}

/**
 * Convert a WordPress path to an absolute server path
 * 
 * @param string $wp_path WordPress path (can be relative to ABSPATH or a full URL)
 * @return string Absolute server path
 */
function wpsec_wp_path_to_server_path($wp_path) {
    // If it's a URL, convert to a path
    if (strpos($wp_path, 'http://') === 0 || strpos($wp_path, 'https://') === 0) {
        $site_url = site_url();
        $wp_path = str_replace($site_url, '', $wp_path);
        $wp_path = ltrim($wp_path, '/');
    }
    
    // If path already starts with ABSPATH, it might already be a server path
    $abspath = function_exists('wp_normalize_path') ? wp_normalize_path(ABSPATH) : str_replace('\\', '/', ABSPATH);
    if (strpos($wp_path, $abspath) === 0) {
        return $wp_path;
    }
    
    // Otherwise, prepend ABSPATH
    return function_exists('path_join') ? path_join($abspath, $wp_path) : rtrim($abspath, '/') . '/' . ltrim($wp_path, '/');
}

/**
 * Normalize a file path from scan results to work with the local system
 * 
 * @param string $file_path The file path from scan results
 * @return string Normalized file path for the current system
 */
function wpsec_normalize_scan_path($file_path) {
    // First, try to convert to a WordPress path
    $wp_path = wpsec_server_path_to_wp_path($file_path);
    
    // If conversion was successful, convert back to a server path for the current system
    if ($wp_path !== false) {
        return wpsec_wp_path_to_server_path($wp_path);
    }
    
    // If conversion failed, check if the file exists as-is
    if (file_exists($file_path)) {
        return $file_path;
    }
    
    // Last resort: try to guess based on common patterns
    if (strpos($file_path, '/wp-content/') !== false) {
        $parts = explode('/wp-content/', $file_path);
        if (count($parts) > 1) {
            return function_exists('path_join') ? path_join(WP_CONTENT_DIR, $parts[1]) : rtrim(WP_CONTENT_DIR, '/') . '/' . ltrim($parts[1], '/');
        }
    }
    
    // If all else fails, return the original path
    wpsec_log('Unable to normalize scan path: ' . $file_path, 'warning');
    return $file_path;
}
