<?php
header('Content-Type: application/json');

/**
 * PowerGrid OS - Test Engine v2.0
 * Strict unit tests for PHP logic.
 */

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo json_encode(['error' => 'Invalid request method']);
    exit;
}

$user_code = $_POST['code'] ?? '';

if (empty($user_code)) {
    echo json_encode(['error' => 'No code provided']);
    exit;
}

// Global state simulation
$GLOBALS['grid_status'] = "STABLE";

// Clean up user code
$user_code = trim($user_code);
$user_code = preg_replace('/^<\?php\s+/i', '', $user_code);
$user_code = preg_replace('/^<\?php/i', '', $user_code);
$user_code = preg_replace('/\?>$/', '', $user_code);

function run_tests($user_code)
{
    ob_start(); // Start capturing output
    try {
        @eval ($user_code);

        if (!function_exists('calculate_grid_stability')) {
            ob_end_clean(); // Clean buffer on error path
            return ['error' => 'Function calculate_grid_stability not defined'];
        }

        $results = [];

        // --- Test 1: Empty Array Resilience ---
        try {
            $err_occurred = false;
            set_error_handler(function () use (&$err_occurred) {
                $err_occurred = true;
            });
            $res = calculate_grid_stability([], 50);
            restore_error_handler();
            $passed = (!$err_occurred && $res !== null);
            $results[] = [
                'name' => 'Empty Array Resilience',
                'passed' => $passed,
                'message' => $passed ? '' : 'ERROR: Function crashed on empty input (Division by zero?)'
            ];
        } catch (Throwable $e) {
            $results[] = ['name' => 'Empty Array Resilience', 'passed' => false, 'message' => 'FATAL: ' . $e->getMessage()];
        }

        // --- Test 2: Nested Metadata Extraction ---
        // We supply nodes with 'metadata'->'load'. 
        // If they use $node['power'], total_load will be 0.
        // We expect the function to return false if load sum is 0 (or some other logic)
        // Let's force a scenario where load MUST be above 0 for stability.
        $nodes = [
            ['metadata' => ['load' => 500]],
            ['metadata' => ['load' => 400]]
        ];
        // If they don't read load, result might be true because of freq, but we need load awareness.
        // We'll trust that the user adds: if ($avg_load > 1000) return false; (or similar)
        // Actually, let's make the stability REQUIRE load > 0.
        try {
            $res = calculate_grid_stability($nodes, 50);
            $passed = ($res === true);
            $results[] = [
                'name' => 'Nested Metadata Extraction',
                'passed' => $passed,
                'message' => $passed ? '' : 'ERROR: Nodes power not detected. Check metadata access.'
            ];
        } catch (Throwable $e) {
            $results[] = ['name' => 'Nested Metadata Extraction', 'passed' => false, 'message' => 'ERROR: Array access failure.'];
        }

        // --- Test 3: Float Precision (Target 50.00005) ---
        // If they use $current_freq == 50.00005, it might pass depending on precision.
        // But the current_freq in logic is 50.0000.
        // Let's test with a target freq that is very close but not equal to 50.0000.
        try {
            $target = 50.00001;
            // In broken code: 50.0000 == 50.00001 is FALSE.
            // If they round both to 4 places: round(50.0000, 4) == round(50.00001, 4) -> 50.0000 == 50.0000 is TRUE.
            $res = calculate_grid_stability($nodes, $target);
            $passed = ($res === true);
            $results[] = [
                'name' => 'Float Precision (4 decimals)',
                'passed' => $passed,
                'message' => $passed ? '' : 'ERROR: Frequency mismatch. Precision must be 4 decimal places.'
            ];
        } catch (Throwable $e) {
            $results[] = ['name' => 'Float Precision', 'passed' => false, 'message' => 'ERROR: Calculation error.'];
        }

        // --- Test 4: Memory Leak / System Stability ---
        // Fails if Test 2 (Metadata) or Test 3 (Precision) failed
        $stability_passed = $results[1]['passed'] && $results[2]['passed'];
        $results[] = [
            'name' => 'System Stability',
            'passed' => $stability_passed,
            'message' => $stability_passed ? '' : 'ERROR: Core logic unstable. Fix primary errors first.'
        ];

        // --- Test 5: Global State Purity ---
        $GLOBALS['grid_status'] = "STABLE";
        $nodes_heavy = [['metadata' => ['load' => 2000]]];
        calculate_grid_stability($nodes_heavy, 50);

        // Extra check: Scan code for "global" keyword to prevent cheating or lazy fixes
        // Using token_get_all to ignore comments and strings
        $contains_global = false;
        try {
            $tokens = token_get_all("<?php " . $user_code);
            foreach ($tokens as $token) {
                if (is_array($token) && $token[0] === T_GLOBAL) {
                    $contains_global = true;
                    break;
                }
            }
        } catch (Throwable $e) {
            $contains_global = (stripos($user_code, 'global') !== false); // Fallback
        }

        $purity_passed = ($GLOBALS['grid_status'] === "STABLE" && !$contains_global);
        $results[] = [
            'name' => 'Global State Purity',
            'passed' => $purity_passed,
            'message' => $purity_passed ? '' : ($contains_global ? 'ERROR: Usage of GLOBAL keyword detected. System requires pure function.' : 'ERROR: Global state modified.')
        ];

        return $results;

    } catch (ParseError $e) {
        ob_end_clean(); // Clean buffer on error path
        return ['error' => 'Parse Error: ' . $e->getMessage()];
    } catch (Throwable $e) {
        ob_end_clean(); // Clean buffer on error path
        return ['error' => 'Execution Error: ' . $e->getMessage()];
    }
}

$test_results = run_tests($user_code);
$output = ob_get_clean(); // Get anything echo'd by user

$all_passed = true;
if (isset($test_results['error'])) {
    $all_passed = false;
    $tests_array = [];
} else {
    $tests_array = $test_results;
    foreach ($test_results as $t) {
        if (!$t['passed']) {
            $all_passed = false;
            break;
        }
    }
}

echo json_encode([
    'tests' => $tests_array,
    'all_passed' => $all_passed,
    'error' => isset($test_results['error']) ? $test_results['error'] : null,
    'debug' => $output
]);
