<?php
/**
 * VMPFence File Repair Engine
 *
 * 
 * Repairs WordPress core, plugin, and theme files from official repositories
 *
 * @package VMPFence
 * @since 1.0.0
 */

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

class VMPFence_File_Repair_Engine {
    
    /**
     * WordPress.org API endpoints
     */
    const WORDPRESS_API_BASE = 'https://api.wordpress.org';
    const WORDPRESS_CHECKSUMS_API = 'https://api.wordpress.org/core/checksums/1.0/';
    const WORDPRESS_PLUGIN_API = 'https://api.wordpress.org/plugins/info/1.0/';
    const WORDPRESS_THEME_API = 'https://api.wordpress.org/themes/info/1.0/';
    const WORDPRESS_DOWNLOAD_BASE = 'https://downloads.wordpress.org';
    
    /**
     * File types that can be repaired
     */
    const REPAIRABLE_TYPES = ['core', 'plugin', 'theme'];
    
    /**
     * Maximum file size for repair (100MB)
     */
    const MAX_REPAIR_FILE_SIZE = 104857600;
    
    /**
     * Repair status constants
     */
    const STATUS_PENDING = 'pending';
    const STATUS_IN_PROGRESS = 'in_progress';
    const STATUS_SUCCESS = 'success';
    const STATUS_FAILED = 'failed';
    const STATUS_NOT_REPAIRABLE = 'not_repairable';
    
    /**
     * Class constructor
     */
    public function __construct() {
        add_action('wp_ajax_vmpfence_repair_file', [$this, 'handle_repair_file']);
        add_action('wp_ajax_vmpfence_bulk_repair', [$this, 'handle_bulk_repair']);
        add_action('wp_ajax_vmpfence_check_repairability', [$this, 'handle_check_repairability']);
    }
    
    /**
     * Initialize the repair engine
     */
    public static function init() {
        return new self();
    }
    
    /**
     * Check if a file is repairable
     *
     * @param string $file_path Absolute file path
     * @param string $file_type Type: core, plugin, theme
     * @param string $component Component name (plugin/theme slug)
     * @param string $version Component version
     * @return bool
     */
    public function is_file_repairable($file_path, $file_type, $component = null, $version = null) {
        // Convert to absolute path for file operations
        $absolute_file_path = $this->ensure_absolute_path($file_path);
        
        // Only repair files from official WordPress.org repositories
        if (!in_array($file_type, self::REPAIRABLE_TYPES)) {
            return false;
        }
        
        // Check if file exists and is writable (using absolute path)
        // phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_is_writable -- Direct check needed for repair engine validation
        if (!file_exists($absolute_file_path) || !is_writable($absolute_file_path)) {
        // phpcs:enable WordPress.WP.AlternativeFunctions.file_system_operations_is_writable
            return false;
        }
        
        // Check file size limit
        if (filesize($absolute_file_path) > self::MAX_REPAIR_FILE_SIZE) {
            return false;
        }
        
        switch ($file_type) {
            case 'core':
                return $this->is_core_file_repairable($absolute_file_path);
            case 'plugin':
                return $this->is_plugin_file_repairable($absolute_file_path, $component, $version);
            case 'theme':
                return $this->is_theme_file_repairable($absolute_file_path, $component, $version);
            default:
                return false;
        }
    }
    
    /**
     * Check if WordPress core file is repairable
     *
     * @param string $file_path
     * @return bool
     */
    private function is_core_file_repairable($file_path) {
        // Get WordPress version
        $wp_version = get_bloginfo('version');
        
        // Get core checksums from WordPress.org
        $checksums = $this->get_wordpress_core_checksums($wp_version);
        
        if (!$checksums) {
            return false;
        }
        
        // Convert absolute path to relative path from WordPress root
        $relative_path = $this->get_relative_path_from_wp_root($file_path);
        
        // Check if file exists in official checksums
        return isset($checksums[$relative_path]);
    }
    
    /**
     * Check if plugin file is repairable
     *
     * @param string $file_path
     * @param string $plugin_slug
     * @param string $version
     * @return bool
     */
    private function is_plugin_file_repairable($file_path, $plugin_slug, $version) {
        if (!$plugin_slug || !$version) {
            return false;
        }
        
        // Check if plugin exists in WordPress.org repository
        $plugin_info = $this->get_plugin_info($plugin_slug);
        
        if (!$plugin_info || !isset($plugin_info['version'])) {
            return false;
        }
        
        // Only repair if we have the exact version
        return version_compare($plugin_info['version'], $version, '>=');
    }
    
    /**
     * Check if theme file is repairable
     *
     * @param string $file_path
     * @param string $theme_slug
     * @param string $version
     * @return bool
     */
    private function is_theme_file_repairable($file_path, $theme_slug, $version) {
        if (!$theme_slug || !$version) {
            return false;
        }
        
        // Check if theme exists in WordPress.org repository
        $theme_info = $this->get_theme_info($theme_slug);
        
        if (!$theme_info || !isset($theme_info['version'])) {
            return false;
        }
        
        // Only repair if we have the exact version
        return version_compare($theme_info['version'], $version, '>=');
    }
    
    /**
     * Repair a single file
     *
     * @param int $issue_id Scan issue ID
     * @return array Result with status and message
     */
    public function repair_file($issue_id) {
        global $wpdb;
        
        // Get issue details
        $issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from WordPress prefix
        $issue = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$issues_table} WHERE id = %d",
            $issue_id
        ));
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        
        if (!$issue) {
            return [
                'success' => false,
                'message' => 'Issue not found',
                'status' => self::STATUS_FAILED
            ];
        }
        
        // Update status to in progress
        $this->update_issue_status($issue_id, self::STATUS_IN_PROGRESS);
        
        // Determine file type and component from known_files table
        $file_info = $this->get_file_info_from_database($issue->file_path);
        
        if (!$file_info) {
            $this->update_issue_status($issue_id, self::STATUS_NOT_REPAIRABLE);
            return [
                'success' => false,
                'message' => 'File not found in known files database',
                'status' => self::STATUS_NOT_REPAIRABLE
            ];
        }
        
        // Check if file is repairable
        $is_repairable = $this->is_file_repairable($issue->file_path, $file_info->file_type, $file_info->component, $file_info->version);
        
        if (!$is_repairable) {
            $this->update_issue_status($issue_id, self::STATUS_NOT_REPAIRABLE);
            return [
                'success' => false,
                'message' => 'File is not repairable',
                'status' => self::STATUS_NOT_REPAIRABLE
            ];
        }
        
        try {
            // Ensure we have an absolute path for file operations
            $absolute_file_path = $this->ensure_absolute_path($issue->file_path);
            
            // Create backup before repair
            $backup_path = $this->create_file_backup($absolute_file_path);
            
            if (!$backup_path) {
                throw new Exception('Failed to create backup');
            }
            
            // Download clean file
            $clean_content = $this->download_clean_file($absolute_file_path, $file_info->file_type, $file_info->component, $file_info->version);
            
            if (!$clean_content) {
                throw new Exception('Failed to download clean file');
            }
            
            // Verify checksum
            if (!$this->verify_clean_file_checksum($clean_content, $absolute_file_path, $file_info)) {
                throw new Exception('Clean file checksum verification failed');
            }
            
            // Replace file
            $original_permissions = fileperms($absolute_file_path);
            
            $write_result = file_put_contents($absolute_file_path, $clean_content);
            //error_log("Write result: " . ($write_result !== false ? $write_result . ' bytes written' : 'FAILED'));
            
            if (!$write_result) {
                throw new Exception('Failed to write clean file');
            }
            
            // Verify file was actually written
            $new_content = file_get_contents($absolute_file_path);
            $new_hash = hash('sha1', $new_content);
            $clean_hash = hash('sha1', $clean_content);
            
            // Restore original permissions
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod -- Direct chmod needed to restore exact original permissions after repair
            chmod($absolute_file_path, $original_permissions);
            
            // Log repair in database
            $this->log_file_repair($issue_id, $absolute_file_path, $backup_path);
            
            // Update issue status
            $this->update_issue_status($issue_id, self::STATUS_SUCCESS);
            
            // Update file_mods table
            $this->update_file_mods_after_repair($absolute_file_path, $file_info);
            
            return [
                'success' => true,
                'message' => 'File repaired successfully',
                'status' => self::STATUS_SUCCESS,
                'backup_path' => $backup_path
            ];
            
        } catch (Exception $e) {
            // Restore backup if repair failed
            $absolute_file_path = $this->ensure_absolute_path($issue->file_path);
            if (isset($backup_path) && file_exists($backup_path)) {
                copy($backup_path, $absolute_file_path);
            }
            
            $this->update_issue_status($issue_id, self::STATUS_FAILED);
            
            return [
                'success' => false,
                'message' => 'Repair failed: ' . $e->getMessage(),
                'status' => self::STATUS_FAILED
            ];
        }
    }
    
    /**
     * Get WordPress core checksums
     *
     * @param string $version WordPress version
     * @return array|false
     */
    private function get_wordpress_core_checksums($version) {
        $cache_key = 'vmpfence_wp_checksums_' . $version;
        $checksums = get_transient($cache_key);
        
        if ($checksums !== false) {
            return $checksums;
        }
        
        $response = wp_remote_get(
            self::WORDPRESS_CHECKSUMS_API . '?version=' . $version,
            ['timeout' => 30]
        );
        
        if (is_wp_error($response)) {
            return false;
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if (!isset($data['checksums'])) {
            return false;
        }
        
        // Cache for 24 hours
        set_transient($cache_key, $data['checksums'], DAY_IN_SECONDS);
        
        return $data['checksums'];
    }
    
    /**
     * Get plugin information from WordPress.org
     *
     * @param string $plugin_slug
     * @return array|false
     */
    private function get_plugin_info($plugin_slug) {
        $cache_key = 'vmpfence_plugin_info_' . $plugin_slug;
        $plugin_info = get_transient($cache_key);
        
        if ($plugin_info !== false) {
            return $plugin_info;
        }
        
        $response = wp_remote_get(
            self::WORDPRESS_PLUGIN_API . $plugin_slug . '.json',
            ['timeout' => 30]
        );
        
        if (is_wp_error($response)) {
            return false;
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if (!$data || isset($data['error'])) {
            return false;
        }
        
        // Cache for 1 hour
        set_transient($cache_key, $data, HOUR_IN_SECONDS);
        
        return $data;
    }
    
    /**
     * Get theme information from WordPress.org
     *
     * @param string $theme_slug
     * @return array|false
     */
    private function get_theme_info($theme_slug) {
        $cache_key = 'vmpfence_theme_info_' . $theme_slug;
        $theme_info = get_transient($cache_key);
        
        if ($theme_info !== false) {
            return $theme_info;
        }
        
        $response = wp_remote_get(
            self::WORDPRESS_THEME_API . $theme_slug . '.json',
            ['timeout' => 30]
        );
        
        if (is_wp_error($response)) {
            return false;
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if (!$data || isset($data['error'])) {
            return false;
        }
        
        // Cache for 1 hour
        set_transient($cache_key, $data, HOUR_IN_SECONDS);
        
        return $data;
    }
    
    /**
     * Download clean file from WordPress.org
     *
     * @param string $file_path
     * @param string $file_type
     * @param string $component
     * @param string $version
     * @return string|false
     */
    private function download_clean_file($file_path, $file_type, $component, $version) {
        switch ($file_type) {
            case 'core':
                return $this->download_core_file($file_path);
            case 'plugin':
                return $this->download_plugin_file($file_path, $component, $version);
            case 'theme':
                return $this->download_theme_file($file_path, $component, $version);
            default:
                return false;
        }
    }
    
    /**
     * Download WordPress core file
     *
     * @param string $file_path
     * @return string|false
     */
    private function download_core_file($file_path) {
        $wp_version = get_bloginfo('version');
        $relative_path = $this->get_relative_path_from_wp_root($file_path);
        
        // Try direct download from WordPress.org SVN
        $svn_url = "https://core.svn.wordpress.org/tags/{$wp_version}/{$relative_path}";
        
        $response = wp_remote_get($svn_url, [
            'timeout' => 30,
            'headers' => [
                'User-Agent' => 'VMPFence-FileRepair/1.0'
            ]
        ]);
        
        if (is_wp_error($response)) {
            // Try trunk if version-specific fails
            $svn_url = "https://core.svn.wordpress.org/trunk/{$relative_path}";
            $response = wp_remote_get($svn_url, [
                'timeout' => 30,
                'headers' => [
                    'User-Agent' => 'VMPFence-FileRepair/1.0'
                ]
            ]);
            
            if (is_wp_error($response)) {
                return false;
            }
        }
        
        $response_code = wp_remote_retrieve_response_code($response);
        
        if ($response_code !== 200) {
            return false;
        }
        
        $body = wp_remote_retrieve_body($response);
        
        return $body;
    }
    
    /**
     * Download plugin file
     *
     * @param string $file_path
     * @param string $plugin_slug
     * @param string $version
     * @return string|false
     */
    private function download_plugin_file($file_path, $plugin_slug, $version) {
        // Download plugin ZIP file
        $download_url = "https://downloads.wordpress.org/plugin/{$plugin_slug}.{$version}.zip";
        
        $response = wp_remote_get($download_url, ['timeout' => 60]);
        
        if (is_wp_error($response)) {
            return false;
        }
        return false;
    }
    
    /**
     * Download theme file
     *
     * @param string $file_path
     * @param string $theme_slug
     * @param string $version
     * @return string|false
     */
    private function download_theme_file($file_path, $theme_slug, $version) {
        // Download theme ZIP file
        $download_url = "https://downloads.wordpress.org/theme/{$theme_slug}.{$version}.zip";
        
        $response = wp_remote_get($download_url, ['timeout' => 60]);
        
        if (is_wp_error($response)) {
            return false;
        }
        return false;
    }
    
    /**
     * Create backup of file before repair
     *
     * @param string $file_path
     * @return string|false Backup path or false on failure
     */
    private function create_file_backup($file_path) {
        $upload_dir = wp_upload_dir();
        $backup_dir = $upload_dir['basedir'] . '/vmpfence-backups';
        
        // Create backup directory if it doesn't exist
        if (!file_exists($backup_dir)) {
            wp_mkdir_p($backup_dir);
        }
        
        // Generate unique backup filename
        $backup_filename = basename($file_path) . '.' . time() . '.backup';
        $backup_path = $backup_dir . '/' . $backup_filename;
        
        // Copy file to backup location
        if (copy($file_path, $backup_path)) {
            return $backup_path;
        }
        
        return false;
    }
    
    /**
     * Verify clean file checksum
     *
     * @param string $content
     * @param string $file_path
     * @param object $file_info
     * @return bool
     */
    private function verify_clean_file_checksum($content, $file_path, $file_info) {
        $content_hash = hash('sha1', $content);
        
        // Check if we have a proper SHA1 hash in database
        if (!isset($file_info->shac) || empty($file_info->shac)) {
            return true;
        }
        
        // Check if the hash is binary (length 20 or 32) or hex string (length 40 or 64)
        $hash_length = strlen($file_info->shac);
        
        if ($hash_length == 32) {
            // This is likely a SHA256 stored as binary, convert to hex and skip for now
            $db_hash_hex = bin2hex($file_info->shac);
            return true;
        } elseif ($hash_length == 20) {
            // This is SHA1 stored as binary, convert to hex
            $expected_hash = bin2hex($file_info->shac);
        } elseif ($hash_length == 40) {
            // This is SHA1 stored as hex string
            $expected_hash = $file_info->shac;
        } elseif ($hash_length == 64) {
            // This is SHA256 stored as hex string, skip verification
            return true;
        } else {
            // Unknown hash format
            return true;
        }
        
        $match = ($content_hash === $expected_hash);
        return $match;
    }
    
    /**
     * Get file information from database
     *
     * @param string $file_path
     * @return object|null
     */
    private function get_file_info_from_database($file_path) {
        global $wpdb;
        
        $known_files_table = $wpdb->prefix . 'vmpfence_known_files';
        $relative_path = $this->get_relative_path_from_wp_root($file_path);
        
        // Normalize path separators to forward slashes for database lookup
        $relative_path = str_replace('\\', '/', $relative_path);
        
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from WordPress prefix
        $result = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$known_files_table} WHERE file_path = %s",
            $relative_path
        ));
        
        if (!$result) {
            // Try without leading/trailing slashes
            $alt_path = trim($relative_path, '/');
            $result = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$known_files_table} WHERE file_path = %s",
                $alt_path
            ));
        }
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        
        return $result;
    }
    
    /**
     * Ensure we have an absolute file path
     *
     * @param string $file_path
     * @return string
     */
    private function ensure_absolute_path($file_path) {
        // If already absolute, return as is
        if (strpos($file_path, '/') === 0 || preg_match('/^[A-Za-z]:/', $file_path)) {
            return $file_path;
        }
        
        // Convert relative path to absolute by prepending WordPress root
        return ABSPATH . $file_path;
    }
    
    /**
     * Get relative path from WordPress root
     *
     * @param string $absolute_path
     * @return string
     */
    private function get_relative_path_from_wp_root($absolute_path) {
        // Normalize both paths to use forward slashes
        $wp_root = str_replace('\\', '/', ABSPATH);
        $normalized_path = str_replace('\\', '/', $absolute_path);
        
        // Remove trailing slash from wp_root for consistent comparison
        $wp_root = rtrim($wp_root, '/') . '/';
        
        // If path starts with wp_root, remove it
        if (strpos($normalized_path, $wp_root) === 0) {
            return substr($normalized_path, strlen($wp_root));
        }
        
        // If path doesn't start with wp_root, it might already be relative
        return ltrim($normalized_path, '/');
    }
    
    /**
     * Update issue status in database
     *
     * @param int $issue_id
     * @param string $status
     */
    private function update_issue_status($issue_id, $status) {
        global $wpdb;
        
        $issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        
        $wpdb->update(
            $issues_table,
            ['status' => $status],
            ['id' => $issue_id],
            ['%s'],
            ['%d']
        );
    }
    
    /**
     * Log file repair in database
     *
     * @param int $issue_id
     * @param string $file_path
     * @param string $backup_path
     */
    private function log_file_repair($issue_id, $file_path, $backup_path) {
        global $wpdb;
        
        $file_changes_table = $wpdb->prefix . 'vmpfence_file_changes';
        
        $wpdb->insert(
            $file_changes_table,
            [
                'file' => $file_path,
                'md5' => md5_file($file_path),
                'timestamp' => microtime(true),
                'action' => 'repaired'
            ],
            ['%s', '%s', '%f', '%s']
        );
    }
    
    /**
     * Update file_mods table after repair
     *
     * @param string $file_path
     * @param object $file_info
     */
    private function update_file_mods_after_repair($file_path, $file_info) {
        global $wpdb;
        
        $file_mods_table = $wpdb->prefix . 'vmpfence_file_mods';
        $new_md5 = md5_file($file_path);
        
        // Check if record exists
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from WordPress prefix
        $existing = $wpdb->get_row($wpdb->prepare(
            "SELECT id FROM {$file_mods_table} WHERE filename = %s",
            $file_path
        ));
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        
        if ($existing) {
            // Update existing record
            $wpdb->update(
                $file_mods_table,
                [
                    'newMD5' => $new_md5,
                    'isSafeFile' => 'Y'
                ],
                ['id' => $existing->id],
                ['%s', '%s'],
                ['%d']
            );
        } else {
            // Insert new record
            $wpdb->insert(
                $file_mods_table,
                [
                    'filename' => $file_path,
                    'knownFile' => 1,
                    'oldMD5' => '', // We don't have the old MD5
                    'newMD5' => $new_md5,
                    'isSafeFile' => 'Y'
                ],
                ['%s', '%d', '%s', '%s', '%s']
            );
        }
    }
    
    /**
     * Handle repair file AJAX request
     */
    public function handle_repair_file() {
        // Verify nonce
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!wp_verify_nonce($nonce, 'vmpfence_scan_nonce')) {
            wp_die('Security check failed');
        }
        
        // Check user capabilities
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions');
        }
        
        $issue_id = isset($_POST['issue_id']) ? intval($_POST['issue_id']) : 0;
        
        if (!$issue_id) {
            wp_send_json_error(['message' => 'Invalid issue ID']);
            return;
        }
        
        $result = $this->repair_file($issue_id);
        
        if ($result['success']) {
            wp_send_json_success($result);
        } else {
            wp_send_json_error($result);
        }
    }
    
    /**
     * Handle bulk repair AJAX request
     */
    public function handle_bulk_repair() {
        // Verify nonce
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!wp_verify_nonce($nonce, 'vmpfence_scan_nonce')) {
            wp_die('Security check failed');
        }
        
        // Check user capabilities
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions');
        }
        
        $issue_ids = isset($_POST['issue_ids']) ? array_map('intval', $_POST['issue_ids']) : array();
        
        if (empty($issue_ids)) {
            wp_send_json_error(['message' => 'No issues selected']);
            return;
        }
        
        $results = [];
        $success_count = 0;
        $failure_count = 0;
        
        foreach ($issue_ids as $issue_id) {
            $result = $this->repair_file($issue_id);
            $results[$issue_id] = $result;
            
            if ($result['success']) {
                $success_count++;
            } else {
                $failure_count++;
            }
        }
        
        wp_send_json_success([
            'message' => sprintf(
                'Bulk repair completed: %d successful, %d failed',
                $success_count,
                $failure_count
            ),
            'results' => $results,
            'success_count' => $success_count,
            'failure_count' => $failure_count
        ]);
    }
    
    /**
     * Handle check repairability AJAX request
     */
    public function handle_check_repairability() {
        // Verify nonce
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!wp_verify_nonce($nonce, 'vmpfence_scan_nonce')) {
            wp_die('Security check failed');
        }
        
        // Check user capabilities
        if (!current_user_can('manage_options')) {
            wp_die('Insufficient permissions');
        }
        
        global $wpdb;
        
        $issues_table = $wpdb->prefix . 'vmpfence_scan_issues';
        $known_files_table = $wpdb->prefix . 'vmpfence_known_files';
        
        // Get all issues and check repairability
        // Note: We need to normalize paths for proper JOIN since Windows paths use backslashes
        // but database likely stores forward slashes
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table names from WordPress prefix
        $issues = $wpdb->get_results(
            "SELECT si.*, kf.file_type, kf.component, kf.version 
             FROM {$issues_table} si 
             LEFT JOIN {$known_files_table} kf ON REPLACE(si.file_path, '\\\\', '/') = kf.file_path 
             WHERE si.status = 'new'"
        );
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        
        $repairable_count = 0;
        $repairable_issues = [];
        
        foreach ($issues as $issue) {
            if ($this->is_file_repairable($issue->file_path, $issue->file_type, $issue->component, $issue->version)) {
                $repairable_count++;
                $repairable_issues[] = $issue->id;
            }
        }
        
        wp_send_json_success([
            'total_issues' => count($issues),
            'repairable_count' => $repairable_count,
            'repairable_issues' => $repairable_issues
        ]);
    }
}

// Initialize the repair engine
add_action('init', function() {
    VMPFence_File_Repair_Engine::init();
});
