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

/**
 * Enhanced Scan Diagnostics Endpoint
 * 
 * This endpoint provides detailed diagnostics about scan performance,
 * including resource usage, slow files, and patterns that could cause failures.
 */
function wpsec_scan_diagnostics_endpoint($request) {
    // Validate API key
    if (!wpsec_validate_api_key()) {
        return new WP_Error(
            'rest_forbidden',
            'Sorry, you are not allowed to do that.',
            array('status' => 401)
        );
    }

    // Get scan ID from request or use latest scan
    $scan_id = isset($request['scan_id']) ? $request['scan_id'] : get_option('wpsec_current_scan_id');
    
    if (!$scan_id) {
        return rest_ensure_response([
            'status' => 'error',
            'message' => 'No scan ID provided and no recent scan found'
        ]);
    }
    
    // Load scan monitor module if not already loaded
    if (!function_exists('wpsec_analyze_scan_performance')) {
        require_once WPSEC_PLUGIN_DIR . 'includes/scan-monitor.php';
    }
    
    // Load advanced diagnostics if not already loaded
    if (!function_exists('wpsec_diagnose_scan_bottlenecks')) {
        require_once WPSEC_PLUGIN_DIR . 'includes/scan-recovery.php';
    }
    
    // Get advanced bottleneck diagnostics
    $bottleneck_analysis = wpsec_diagnose_scan_bottlenecks($scan_id);
    
    // Also get the comprehensive analysis from scan monitor for backward compatibility
    if (function_exists('wpsec_analyze_scan_performance')) {
        $analysis = wpsec_analyze_scan_performance($scan_id);
    } else {
        $analysis = [];
    }
    
    // Get timeout diagnostics
    $timeout_diagnostics = json_decode(get_option('wpsec_scan_' . $scan_id . '_timeout_diagnostics', '{}'), true);
    $critical_error = json_decode(get_option('wpsec_scan_' . $scan_id . '_critical_error', '{}'), true);
    $file_errors = json_decode(get_option('wpsec_scan_' . $scan_id . '_file_errors', '[]'), true);
    
    // Get memory and resource information
    $memory_peak = get_option('wpsec_scan_' . $scan_id . '_memory_peak', 0);
    $memory_limit = ini_get('memory_limit');
    $memory_limit_bytes = wp_convert_hr_to_bytes($memory_limit);
    $memory_usage_percent = $memory_peak > 0 ? round(($memory_peak / $memory_limit_bytes) * 100, 1) : 0;
    
    // Check for potential resource bottlenecks
    $bottlenecks = [];
    
    // Memory issues
    if ($memory_usage_percent > 80) {
        $bottlenecks[] = [
            'type' => 'memory',
            'severity' => 'high',
            'message' => "Memory usage reached {$memory_usage_percent}% of the available limit ({$memory_limit}). Consider increasing PHP memory limit."
        ];
    }
    
    // Slow file processing
    $slow_files = json_decode(get_option('wpsec_scan_' . $scan_id . '_large_files', '[]'), true);
    if (!empty($slow_files) && isset($slow_files[0]['size']) && $slow_files[0]['size'] > 5000000) { // 5MB+
        $size_mb = round($slow_files[0]['size'] / 1024 / 1024, 2);
        $bottlenecks[] = [
            'type' => 'large_file',
            'severity' => 'medium',
            'message' => "Very large file detected: {$slow_files[0]['file']} ({$size_mb}MB). Large files can cause scan timeouts."
        ];
    }
    
    // Get enhanced cache statistics with real-time data
    $cache_stats = [];
    if (function_exists('wpsec_get_file_hash_cache_stats')) {
        // Include recent entries in the development endpoint for debugging
        $include_recent_entries = true;
        $cache_stats = wpsec_get_file_hash_cache_stats($include_recent_entries);
        
        // Add scan-specific cache tracking
        $scan_cached_count = (int)get_option('wpsec_scan_' . $scan_id . '_files_cached', 0);
        $scan_skipped_count = (int)get_option('wpsec_scan_' . $scan_id . '_files_skipped', 0);
        
        // Track scan-specific cache metrics
        $cache_stats['scan_specific'] = [
            'scan_id' => $scan_id,
            'cached_in_current_scan' => $scan_cached_count,
            'skipped_in_current_scan' => $scan_skipped_count,
            'cache_hit_rate' => $scan_cached_count > 0 ? 
                round(($scan_cached_count / (get_option('wpsec_scan_' . $scan_id . '_files_scanned', 1))) * 100, 2) . '%' : '0%'
        ];
    }
    
    // Track cache operations during this scan
    $cached_files = (int)get_option('wpsec_scan_' . $scan_id . '_files_cached', 0);
    $cache_updates = (int)get_option('wpsec_scan_' . $scan_id . '_cache_updates', 0);
    
    // Build scan diagnostics response
    $response = [
        'status' => 'success',
        'scan_id' => $scan_id,
        'diagnostics' => [
            'general' => [
                'status' => get_option('wpsec_scan_' . $scan_id . '_status', 'unknown'),
                'error' => get_option('wpsec_scan_' . $scan_id . '_error', ''),
                'progress' => get_option('wpsec_scan_' . $scan_id . '_progress', 0),
                'files_scanned' => get_option('wpsec_scan_' . $scan_id . '_files_scanned', 0),
                'total_files' => get_option('wpsec_scan_' . $scan_id . '_total_files', 0),
                'start_time' => gmdate('Y-m-d H:i:s', get_option('wpsec_scan_' . $scan_id . '_start', 0)),
                'end_time' => get_option('wpsec_scan_' . $scan_id . '_end', 0) ? gmdate('Y-m-d H:i:s', get_option('wpsec_scan_' . $scan_id . '_end', 0)) : null,
                'duration' => get_option('wpsec_scan_' . $scan_id . '_duration', 0),
                'last_file' => get_option('wpsec_scan_' . $scan_id . '_last_scanned_file', ''),
            ],
            'performance' => [
                'memory_peak' => size_format($memory_peak),
                'memory_limit' => $memory_limit,
                'memory_usage_percent' => $memory_usage_percent . '%',
                'timeout_diagnostics' => $timeout_diagnostics,
                'critical_error' => $critical_error,
                'file_errors_count' => count($file_errors),
                'file_errors' => array_slice($file_errors, 0, 10), // Return only the first 10 errors for brevity
                'bottlenecks' => $bottlenecks,
                'performance_analysis' => $analysis,
                'cache_stats' => $cache_stats,
                'cached_files' => $cached_files,
                'chunking_info' => [
                    'chunk_size' => get_option('wpsec_scan_' . $scan_id . '_chunk_size', 0),
                    'last_scanned_index' => get_option('wpsec_scan_' . $scan_id . '_last_scanned_index', 0),
                    'resume_position' => get_option('wpsec_scan_' . $scan_id . '_resume_position', 0),
                    'resume_scheduled' => wp_next_scheduled('wpsec_resume_scan', [['scan_id' => $scan_id]]) !== false,
                    'resume_count' => get_option('wpsec_scan_' . $scan_id . '_resume_count', 0),
                    'server_environment' => function_exists('wpsec_detect_server_environment') ? wpsec_detect_server_environment() : ['type' => 'unknown'],
                ],
            ],
        ],
        'recommendations' => []
    ];
    
    // Generate actionable recommendations
    $recommendations = [];
    
    // Check for resource limitations
    if ($memory_usage_percent > 80) {
        $recommendations[] = [
            'action' => 'increase_memory',
            'message' => 'Increase PHP memory limit in wp-config.php (e.g., define("WP_MEMORY_LIMIT", "256M");)',
            'priority' => 'high'
        ];
    }
    
    // Check for large file problems
    if (!empty($slow_files) && isset($slow_files[0]['size']) && $slow_files[0]['size'] > 5000000) {
        $recommendations[] = [
            'action' => 'exclude_large_files',
            'message' => 'Consider excluding very large files from scanning',
            'priority' => 'medium',
            'example_files' => array_slice($slow_files, 0, 3)
        ];
    }
    
    // Add timeout prevention recommendation
    if (get_option('wpsec_scan_' . $scan_id . '_status', '') === 'error' && 
        strpos(get_option('wpsec_scan_' . $scan_id . '_error', ''), 'timeout') !== false) {
        $recommendations[] = [
            'action' => 'increase_timeout',
            'message' => 'Increase timeout check duration in webhooks.php from 120 seconds to 300 seconds',
            'priority' => 'high',
            'file_path' => WPSEC_PLUGIN_DIR . 'includes/webhooks.php',
            'line_number' => 338
        ];
    }
    
    // Add recommendations for file hash caching
    if (function_exists('wpsec_get_file_hash_cache_stats') && isset($cache_stats['total_files'])) {
        // If cache is empty or very small compared to total files
        if ($cache_stats['total_files'] < 100) {
            $recommendations[] = [
                'action' => 'run_regular_scan',
                'message' => 'Your file hash cache is empty or very small. Run a regular scan (not deep scan) to build up the cache.',
                'priority' => 'medium'
            ];
        }
        
        // If cached files percentage is low during this scan
        $total_scanned = get_option('wpsec_scan_' . $scan_id . '_files_scanned', 0);
        if ($total_scanned > 0 && $cached_files > 0) {
            $cache_percent = round(($cached_files / $total_scanned) * 100, 1);
            
            if ($cache_percent < 20) {
                $recommendations[] = [
                    'action' => 'optimize_cache',
                    'message' => "Only {$cache_percent}% of files were cached in this scan. Regular scans will improve this percentage and speed up future scans.",
                    'priority' => 'medium'
                ];
            } else if ($cache_percent > 80) {
                $recommendations[] = [
                    'action' => 'cache_effective',
                    'message' => "File hash caching is working effectively, {$cache_percent}% of files were served from cache.",
                    'priority' => 'low',
                    'type' => 'info'
                ];
            }
        }
    }
    
    // Add recommendation about chunk size if it's enabled
    $chunk_size = get_option('wpsec_scan_' . $scan_id . '_chunk_size', 0);
    if ($chunk_size > 0) {
        if ($chunk_size < 1000 && get_option('wpsec_scan_' . $scan_id . '_status', '') === 'paused') {
            $recommendations[] = [
                'action' => 'increase_chunk_size',
                'message' => "The current chunk size of {$chunk_size} files may be too small for efficient scanning. Consider increasing it to at least 2000 files.",
                'priority' => 'medium'
            ];
        }
    }
    
    // Add the recommendations to the response
    $response['recommendations'] = $recommendations;
    
    // Add bottleneck analysis to response
    $response['bottleneck_analysis'] = $bottleneck_analysis;
    
    // Add specific actions based on bottlenecks found
    if (!empty($bottleneck_analysis['bottlenecks'])) {
        foreach ($bottleneck_analysis['bottlenecks'] as $bottleneck) {
            // Add specific recommendations based on bottleneck type
            if (strpos($bottleneck, 'Low memory') !== false) {
                $recommendations[] = [
                    'action' => 'increase_memory',
                    'message' => 'Increase PHP memory limit in wp-config.php due to memory constraints',
                    'priority' => 'critical'
                ];
            }
            if (strpos($bottleneck, 'High CPU') !== false) {
                $recommendations[] = [
                    'action' => 'reduce_chunk_size',
                    'message' => 'Server under high CPU load. Consider reducing chunk size or scanning during off-peak hours',
                    'priority' => 'high'
                ];
            }
            if (strpos($bottleneck, 'Slow file processing') !== false) {
                $recommendations[] = [
                    'action' => 'optimize_scan',
                    'message' => 'File processing is unusually slow. Consider excluding large/binary files or optimizing scan rules',
                    'priority' => 'medium'
                ];
            }
            if (strpos($bottleneck, 'Large file') !== false) {
                $recommendations[] = [
                    'action' => 'exclude_large_file',
                    'message' => $bottleneck . '. Consider excluding this file from scanning',
                    'priority' => 'medium'
                ];
            }
            if (strpos($bottleneck, 'infinite loop') !== false) {
                $recommendations[] = [
                    'action' => 'fix_infinite_loop',
                    'message' => 'Scan appears to be stuck in an infinite loop. Try restarting the scan or excluding the problematic file',
                    'priority' => 'critical'
                ];
            }
        }
    }
    
    // Update the recommendations in the response
    $response['recommendations'] = $recommendations;
    
    return rest_ensure_response($response);
}

/**
 * Direct test file scan endpoint handler
 * 
 * This is a simplified version that manually handles the request parameters to avoid issues
 * Tests a specific file with all detection engines and returns detailed results
 */
function wpsec_test_file_endpoint($request = null) {
    // For debugging
    wpsec_debug_log('🔍 TEST FILE SCAN: Request received', 'info');
    
    // Handle both REST and direct endpoint calls
    if (empty($request)) {
        // Direct endpoint call
        $file_path = isset($_GET['file_path']) ? sanitize_text_field($_GET['file_path']) : '';
        wpsec_debug_log('🔍 TEST FILE SCAN: Direct endpoint mode, got path: ' . $file_path, 'info');
    } else {
        // REST API call
        if (is_object($request) && method_exists($request, 'get_param')) {
            $file_path = $request->get_param('file_path');
            wpsec_debug_log('🔍 TEST FILE SCAN: REST API mode, got path: ' . $file_path, 'info');
        } else if (is_array($request) && isset($request['file_path'])) {
            $file_path = $request['file_path'];
            wpsec_debug_log('🔍 TEST FILE SCAN: Array request mode, got path: ' . $file_path, 'info');
        } else {
            // Fallback mode
            $file_path = isset($_GET['file_path']) ? sanitize_text_field($_GET['file_path']) : '';
            wpsec_debug_log('🔍 TEST FILE SCAN: Fallback mode, got path: ' . $file_path, 'info');
        }
    }
    
    // Sanitize file path
    $file_path = sanitize_text_field($file_path);
    
    wpsec_debug_log('🔍 TEST FILE SCAN: File path after sanitization: ' . $file_path, 'info');
    
    // Validate API key
    if (!wpsec_validate_api_key()) {
        wpsec_debug_log('❌ TEST FILE SCAN: API key validation failed', 'error');
        $response = [
            'status' => 'error',
            'message' => 'Invalid API key',
            'code' => 'unauthorized'
        ];
        
        // Direct output for standard endpoint
        if (empty($request)) {
            header('Content-Type: application/json');
            echo json_encode($response);
            exit;
        }
        
        return new WP_Error(
            'rest_forbidden',
            'Sorry, you are not allowed to do that.',
            array('status' => 401)
        );
    }
    
    if (empty($file_path)) {
        wpsec_debug_log('❌ TEST FILE SCAN: No file path provided', 'error');
        $response = [
            'status' => 'error',
            'message' => 'No file path provided',
            'code' => 'missing_parameter'
        ];
        
        // Direct output for standard endpoint
        if (empty($request)) {
            header('Content-Type: application/json');
            echo json_encode($response);
            exit;
        }
        
        return rest_ensure_response($response);
    }
    
    // Load our diagnostic functions
    try {
        require_once WPSEC_PLUGIN_DIR . 'includes/scan-diagnostics.php';
    } catch (Exception $e) {
        wpsec_debug_log('❌ TEST FILE SCAN: Failed to load diagnostic functions: ' . $e->getMessage(), 'error');
        $response = [
            'status' => 'error',
            'message' => 'Failed to load diagnostic functions',
            'code' => 'internal_error'
        ];
        
        // Direct output for standard endpoint
        if (empty($request)) {
            header('Content-Type: application/json');
            echo json_encode($response);
            exit;
        }
        
        return rest_ensure_response($response);
    }
    
    // Ensure path is absolute
    if (strpos($file_path, '/') !== 0 && strpos($file_path, ':\\') !== 1) { 
        // If path is relative, make it absolute from WordPress root
        $file_path = ABSPATH . ltrim($file_path, '/');
    }
    
    wpsec_debug_log('✅ TEST FILE SCAN: Processing file: ' . $file_path, 'info');
    
    // Check if file exists
    if (!file_exists($file_path)) {
        wpsec_debug_log('❌ TEST FILE SCAN: File does not exist: ' . $file_path, 'error');
        $response = [
            'status' => 'error',
            'message' => 'File does not exist: ' . $file_path,
            'code' => 'file_not_found'
        ];
        
        // Direct output for standard endpoint
        if (empty($request)) {
            header('Content-Type: application/json');
            echo json_encode($response);
            exit;
        }
        
        return rest_ensure_response($response);
    }
    
    try {
        // Initialize WordPress Filesystem
        global $wp_filesystem;
        if (empty($wp_filesystem)) {
            require_once(ABSPATH . '/wp-admin/includes/file.php');
            WP_Filesystem();
        }
        
        // Run a simpler diagnostic test to avoid function compatibility issues
        $diagnosis = [
            'file_path' => $file_path,
            'file_exists' => $wp_filesystem->exists($file_path),
            'file_size' => $wp_filesystem->size($file_path),
            'file_modified' => $wp_filesystem->mtime($file_path),
            'is_readable' => $wp_filesystem->is_readable($file_path),
            'file_content_sample' => substr($wp_filesystem->get_contents($file_path), 0, 200) . '...',
            'file_extension' => pathinfo($file_path, PATHINFO_EXTENSION),
            'test_status' => 'Simple scan mode - detailed diagnosis disabled for compatibility'
        ];
        
        // Try to get additional diagnostics if available
        if (function_exists('wpsec_scan_file_with_tracing')) {
            wpsec_debug_log('✅ TEST FILE SCAN: Running detailed scan with tracing', 'info');
            $full_diagnosis = wpsec_scan_file_with_tracing($file_path);
            if (is_array($full_diagnosis)) {
                $diagnosis['detailed_scan'] = $full_diagnosis;
            } else {
                wpsec_debug_log('⚠️ TEST FILE SCAN: Detailed scan returned non-array: ' . gettype($full_diagnosis), 'warning');
            }
        } else {
            wpsec_debug_log('⚠️ TEST FILE SCAN: Detailed scan function not available', 'warning');
        }
        
        // Use direct scan function to test for malware
        if (function_exists('wpsec_scan_single_file')) {
            wpsec_debug_log('✅ TEST FILE SCAN: Running standard scan', 'info');
            // Force skip whitelist and caching
            $scan_results = wpsec_scan_single_file($file_path, 'test-scan-' . time(), true, true);
            $diagnosis['standard_scan_results'] = $scan_results;
        }
        
        $response = [
            'status' => 'success',
            'file_path' => $file_path,
            'timestamp' => time(),
            'diagnosis' => $diagnosis
        ];
        
        wpsec_debug_log('✅ TEST FILE SCAN: Scan complete for: ' . $file_path, 'info');
        
        // Direct output for standard endpoint
        if (empty($request)) {
            header('Content-Type: application/json');
            echo json_encode($response);
            exit;
        }
        
        return rest_ensure_response($response);
        
    } catch (Exception $e) {
        wpsec_debug_log('❌ TEST FILE SCAN ERROR: ' . $e->getMessage(), 'error');
        $response = [
            'status' => 'error',
            'message' => 'Error scanning file: ' . $e->getMessage(),
            'code' => 'scan_error',
            'file_path' => $file_path
        ];
        
        // Direct output for standard endpoint
        if (empty($request)) {
            header('Content-Type: application/json');
            echo json_encode($response);
            exit;
        }
        
        return rest_ensure_response($response);
    }
}

// Register the endpoint
add_action('rest_api_init', function () {
    // Test file endpoint
    register_rest_route('wpsec/v1', '/test-file-scan', [
        'methods' => 'GET',
        'callback' => 'wpsec_test_file_endpoint',
        'args' => [
            'file_path' => [
                'required' => true,
                'description' => 'Full path to the file to test',
                'type' => 'string'
            ],
        ],
        'permission_callback' => function() { return true; }
    ]);
    
    // Main diagnostics endpoint
    register_rest_route('wpsec/v1', '/scan-diagnostics(?:/(?P<scan_id>[^/]+))?', [
        'methods' => 'GET',
        'callback' => 'wpsec_scan_diagnostics_endpoint',
        'permission_callback' => '__return_true',
        'args' => [
            'scan_id' => [
                'required' => false,
                'validate_callback' => function($param) {
                    return is_string($param);
                }
            ]
        ]
    ]);
});
