<?php
/**
 * CVE Scanner Class - Check WordPress installation for known vulnerabilities
 *
 * @package VMPFence
 * @since 1.0.0
 */

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

/**
 * CVE Scanner Class
 *
 * @since 1.0.0
 */
class VMPFence_CVE_Scanner {

    /**
     * API client instance
     *
     * @var VMPFence_API_Client
     */
    private $api_client;

    /**
     * Constructor
     *
     * @since 1.0.0
     */
    public function __construct() {
        require_once VMPFENCE_PLUGIN_DIR . 'lib/class-api-client.php';
        $this->api_client = new VMPFence_API_Client();
    }

    /**
     * Scan site for CVE vulnerabilities
     *
     * @since 1.0.0
     * @return array Scan results with vulnerability details
     */
    public function scan_site() {
        // Get API key
        $api_key = VMPFence_Config::get('central_api_key');
        
        if (empty($api_key)) {
            return array(
                'success' => false,
                'error' => 'API key not configured'
            );
        }

        // Collect site component inventory
        $site_data = $this->collect_site_components();
        
        // Send to API for vulnerability checking
        $response = $this->api_client->check_site_vulnerabilities($api_key, $site_data);
        
        if (is_wp_error($response)) {
            VMPFence_Secure_Logger::log('error', 'CVE: Scan failed', ['error' => $response->get_error_message()]);
            return array(
                'success' => false,
                'error' => $response->get_error_message()
            );
        }
        
        // Process and cache results
        $results = $this->process_scan_results($response);
        
        // Update last scan timestamp
        update_option('vmpfence_cve_last_scan', current_time('mysql'));
        update_option('vmpfence_cve_last_results', $results);
        
        return $results;
    }

    /**
     * Collect WordPress core, plugins, and themes inventory
     *
     * @since 1.0.0
     * @return array Site component data
     */
    private function collect_site_components() {
        global $wp_version;
        
        // Get installed plugins
        if (!function_exists('get_plugins')) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        
        $all_plugins = get_plugins();
        $active_plugins = get_option('active_plugins', array());
        
        $plugins = array();
        foreach ($all_plugins as $plugin_path => $plugin_data) {
            $slug = dirname($plugin_path);
            // If plugin is in root (single file plugin), use filename without .php
            if ($slug === '.') {
                $slug = basename($plugin_path, '.php');
            }
            
            $plugins[] = array(
                'slug' => $slug,
                'name' => $plugin_data['Name'],
                'version' => $plugin_data['Version'],
                'active' => in_array($plugin_path, $active_plugins)
            );
        }
        
        // Get installed themes
        $all_themes = wp_get_themes();
        $active_theme = wp_get_theme();
        
        $themes = array();
        foreach ($all_themes as $theme) {
            $themes[] = array(
                'slug' => $theme->get_stylesheet(),
                'name' => $theme->get('Name'),
                'version' => $theme->get('Version'),
                'active' => ($theme->get_stylesheet() === $active_theme->get_stylesheet())
            );
        }
        
        return array(
            'wordpress_version' => $wp_version,
            'plugins' => $plugins,
            'themes' => $themes,
            'site_url' => get_site_url(),
            'php_version' => phpversion(),
            'mysql_version' => $this->get_mysql_version()
        );
    }

    /**
     * Get MySQL version
     *
     * @since 1.0.0
     * @return string MySQL version
     */
    private function get_mysql_version() {
        global $wpdb;
        return $wpdb->db_version();
    }

    /**
     * Process scan results from API
     *
     * @since 1.0.0
     * @param array $response API response
     * @return array Processed results
     */
    private function process_scan_results($response) {
        // API returns: {vulnerabilities: [...], summary: {total, critical, high, medium, low}}
        $all_vulns = isset($response['vulnerabilities']) ? $response['vulnerabilities'] : array();
        $summary = isset($response['summary']) ? $response['summary'] : array(
            'total' => 0,
            'critical' => 0,
            'high' => 0,
            'medium' => 0,
            'low' => 0
        );
        
        // Separate vulnerabilities by component type
        $core_vulns = array();
        $plugin_vulns = array();
        $theme_vulns = array();
        
        foreach ($all_vulns as $vuln) {
            $component_type = $vuln['component_type'] ?? 'unknown';
            if ($component_type === 'core') {
                $core_vulns[] = $vuln;
            } elseif ($component_type === 'plugin') {
                $plugin_vulns[] = $vuln;
            } elseif ($component_type === 'theme') {
                $theme_vulns[] = $vuln;
            }
        }
        
        $severity_counts = array(
            'critical' => $summary['critical'],
            'high' => $summary['high'],
            'medium' => $summary['medium'],
            'low' => $summary['low']
        );
        
        return array(
            'success' => true,
            'total_vulnerabilities' => $summary['total'],
            'core_vulnerabilities' => $core_vulns,
            'plugin_vulnerabilities' => $plugin_vulns,
            'theme_vulnerabilities' => $theme_vulns,
            'severity_counts' => $severity_counts,
            'scanned_at' => current_time('mysql'),
            'wp_version' => get_bloginfo('version'),
            'plugin_count' => count($plugin_vulns),
            'theme_count' => count($theme_vulns)
        );
    }

    /**
     * Get cached scan results
     *
     * @since 1.0.0
     * @return array|false Cached results or false
     */
    public static function get_cached_results() {
        $results = get_option('vmpfence_cve_last_results', false);
        $last_scan = get_option('vmpfence_cve_last_scan', false);
        
        if ($results && $last_scan) {
            $results['last_scan'] = $last_scan;
            return $results;
        }
        
        return false;
    }

    /**
     * Check if scan is needed (older than 24 hours)
     *
     * @since 1.0.0
     * @return bool True if scan is needed
     */
    public static function is_scan_needed() {
        $last_scan = get_option('vmpfence_cve_last_scan', false);
        
        if (!$last_scan) {
            return true;
        }
        
        $last_scan_time = strtotime($last_scan);
        $current_time = current_time('timestamp');
        
        // Scan if older than 24 hours
        return ($current_time - $last_scan_time) > (24 * 60 * 60);
    }

    /**
     * Get vulnerability by CVE ID
     *
     * @since 1.0.0
     * @param string $cve_id CVE identifier
     * @return array|false Vulnerability details or false
     */
    public function get_vulnerability_details($cve_id) {
        $api_key = VMPFence_Config::get('central_api_key');
        
        if (empty($api_key)) {
            return false;
        }
        
        $response = $this->api_client->get_cve_details($api_key, $cve_id);
        
        if (is_wp_error($response)) {
            return false;
        }
        
        return $response;
    }

    /**
     * Get vulnerability statistics
     *
     * @since 1.0.0
     * @return array Statistics array
     */
    public static function get_statistics() {
        $results = self::get_cached_results();
        
        if (!$results) {
            return array(
                'total' => 0,
                'critical' => 0,
                'high' => 0,
                'medium' => 0,
                'low' => 0,
                'last_scan' => 'Never'
            );
        }
        
        return array(
            'total' => $results['total_vulnerabilities'],
            'critical' => $results['severity_counts']['critical'],
            'high' => $results['severity_counts']['high'],
            'medium' => $results['severity_counts']['medium'],
            'low' => $results['severity_counts']['low'],
            'last_scan' => $results['scanned_at']
        );
    }
    
    /**
     * Generate fix action HTML for a vulnerability
     * 
     * Determines the best fix approach:
     * - For components with patched_version: Link to update page
     * - For WordPress core: Always recommend latest version
     * - For repairable files: Show repair option
     * - Fallback: Show "No automated fix"
     * 
     * @since 1.0.0
     * @param array $vuln Vulnerability data
     * @return string HTML for fix action
     */
    public static function get_fix_action_html($vuln) {
        $component_type = $vuln['component_type'];
        $patched_version = !empty($vuln['patched_version']) ? $vuln['patched_version'] : null;
        $latest_version = !empty($vuln['latest_version']) ? $vuln['latest_version'] : null;
        $recommended_version = !empty($vuln['recommended_version']) ? $vuln['recommended_version'] : null;
        
        // Determine the version to show
        $fix_version = $patched_version ?: $latest_version ?: $recommended_version;
        
        // WordPress Core fixes
        if ($component_type === 'core') {
            $update_url = admin_url('update-core.php');
            
            if ($fix_version) {
                return sprintf(
                    '<a href="%s" class="button button-primary button-small">
                        <span class="dashicons dashicons-update" style="margin-top:3px;"></span>
                        Update to %s
                    </a>
                    <p class="description" style="margin-top:5px;">Latest: WordPress %s</p>',
                    esc_url($update_url),
                    esc_html($fix_version),
                    esc_html($latest_version ?: $fix_version)
                );
            } else {
                // No specific version info, but still link to updates page
                return sprintf(
                    '<a href="%s" class="button button-primary button-small">
                        <span class="dashicons dashicons-update" style="margin-top:3px;"></span>
                        Check for updates
                    </a>
                    <p class="description" style="margin-top:5px;">Update to latest WordPress version</p>',
                    esc_url($update_url)
                );
            }
        }
        
        // Plugin fixes
        if ($component_type === 'plugin') {
            $plugin_slug = $vuln['component'];
            $component_name = !empty($vuln['component_name']) ? $vuln['component_name'] : ucwords(str_replace('-', ' ', $plugin_slug));
            
            if ($fix_version) {
                $update_url = admin_url('plugins.php');
                
                // Build latest version label for plugins
                $latest_label = '';
                if ($latest_version && $latest_version !== $fix_version) {
                    $latest_label = sprintf(
                        '<p class="description" style="margin-top:5px;">Latest: %s %s</p>',
                        esc_html($component_name),
                        esc_html($latest_version)
                    );
                }
                
                // Check if this is a WordPress.org plugin (can be updated)
                if (self::is_wporg_plugin($plugin_slug)) {
                    return sprintf(
                        '<a href="%s" class="button button-primary button-small">
                            <span class="dashicons dashicons-update" style="margin-top:3px;"></span>
                            Update to %s
                        </a>
                        %s%s',
                        esc_url($update_url),
                        esc_html($fix_version),
                        $latest_label,
                        self::get_repair_button_html($vuln)
                    );
                } else {
                    // Premium/commercial plugin
                    return sprintf(
                        '<span class="button button-small disabled">
                            Update to %s
                        </span>
                        <p class="description" style="margin-top:5px;">Check vendor site for updates</p>',
                        esc_html($fix_version)
                    );
                }
            } else {
                // No patch version available, check if repairable
                $repair_html = self::get_repair_button_html($vuln);
                if ($repair_html) {
                    return $repair_html;
                }
                return '<span class="no-patch">No patch available</span>';
            }
        }
        
        // Theme fixes
        if ($component_type === 'theme') {
            $theme_slug = $vuln['component'];
            $component_name = !empty($vuln['component_name']) ? $vuln['component_name'] : ucwords(str_replace('-', ' ', $theme_slug));
            
            if ($fix_version) {
                $update_url = admin_url('themes.php');
                
                // Build latest version label for themes
                $latest_label = '';
                if ($latest_version && $latest_version !== $fix_version) {
                    $latest_label = sprintf(
                        '<p class="description" style="margin-top:5px;">Latest: %s theme %s</p>',
                        esc_html($component_name),
                        esc_html($latest_version)
                    );
                }
                
                return sprintf(
                    '<a href="%s" class="button button-primary button-small">
                        <span class="dashicons dashicons-update" style="margin-top:3px;"></span>
                        Update to %s
                    </a>
                    %s%s',
                    esc_url($update_url),
                    esc_html($fix_version),
                    $latest_label,
                    self::get_repair_button_html($vuln)
                );
            } else {
                $repair_html = self::get_repair_button_html($vuln);
                if ($repair_html) {
                    return $repair_html;
                }
                return '<span class="no-patch">No patch available</span>';
            }
        }
        
        return '<span class="no-patch">No automated fix</span>';
    }
    
    /**
     * Check if plugin is from WordPress.org repository
     * 
     * @param string $plugin_slug Plugin slug
     * @return bool True if WordPress.org plugin
     */
    private static function is_wporg_plugin($plugin_slug) {
        // Check if plugin exists in WordPress.org repository
        $api_url = "https://api.wordpress.org/plugins/info/1.0/{$plugin_slug}.json";
        
        $response = VMPFence_Secure_HTTP_Client::get($api_url, array('timeout' => 5));
        
        if (is_wp_error($response)) {
            return false;
        }
        
        $code = wp_remote_retrieve_response_code($response);
        return $code === 200;
    }
    
    /**
     * Get repair button HTML if vulnerability can be fixed by file repair
     * 
     * @param array $vuln Vulnerability data
     * @return string HTML for repair button or empty string
     */
    private static function get_repair_button_html($vuln) {
        // Check if file repair engine is available
        if (!class_exists('VMPFence_File_Repair_Engine')) {
            return '';
        }
        
        $component_type = $vuln['component_type'];
        $component_slug = $vuln['component'];
        
        // Only WordPress.org components can be repaired
        if ($component_type === 'core' || self::is_wporg_plugin($component_slug)) {
            return sprintf(
                '<br><a href="#" class="button button-secondary button-small cve-repair-file" data-cve-id="%s" data-component="%s" data-component-type="%s" style="margin-top:5px;">
                    <span class="dashicons dashicons-admin-tools" style="margin-top:3px;"></span>
                    Repair Files
                </a>',
                esc_attr($vuln['cve_id']),
                esc_attr($component_slug),
                esc_attr($component_type)
            );
        }
        
        return '';
    }
}
