<?php
/**
 * ERP Smoke Tester — UI-level automated testing
 *
 * Crawls every route, loads every page, checks for PHP errors,
 * SQL errors, broken views, and slow pages.
 *
 * Access via browser: /tools/smoke-test (requires super_admin)
 * Access via CLI:     php tools/smoke_test.php [base_url] [email] [password]
 */

declare(strict_types=1);

$isCli = php_sapi_name() === 'cli';

// ─── Configuration ──────────────────────────────────────────────────────────
if ($isCli) {
    $baseUrl = $argv[1] ?? getenv('APP_URL') ?: 'http://localhost';
    $adminEmail = $argv[2] ?? getenv('ADMIN_EMAIL') ?: 'admin';
    $adminPassword = $argv[3] ?? getenv('ADMIN_PASSWORD') ?: 'ClubManagement';
} else {
    // Browser mode — auto-detect URL and use session auth
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $baseUrl = $scheme . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost');
    $adminEmail = $_POST['email'] ?? $_GET['email'] ?? 'admin';
    $adminPassword = $_POST['password'] ?? $_GET['password'] ?? 'ClubManagement';
}
$baseUrl = rtrim($baseUrl, '/');

$timeout = 15;
$maxPages = 500;

// ─── Results Collection ─────────────────────────────────────────────────────
$results = [
    'total_routes' => 0,
    'tested' => 0,
    'passed' => 0,
    'failed' => 0,
    'skipped' => 0,
    'errors' => [],
    'warnings' => [],
    'start_time' => microtime(true),
];

// ─── Output Helpers ─────────────────────────────────────────────────────────
function output(string $msg, string $type = 'info'): void {
    global $isCli;
    if ($isCli) {
        $colors = ['info' => "\033[0m", 'success' => "\033[32m", 'error' => "\033[31m", 'warning' => "\033[33m", 'header' => "\033[36m"];
        echo ($colors[$type] ?? '') . $msg . "\033[0m\n";
    }
}

// ─── Browser: Output HTML header ────────────────────────────────────────────
if (!$isCli) {
    if (!ob_get_level()) header('Content-Type: text/html; charset=utf-8');
    echo '<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8"><title>ERP Smoke Test</title>';
    echo '<style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #0f172a; color: #e2e8f0; padding: 20px; line-height: 1.6; }
        .container { max-width: 1200px; margin: 0 auto; }
        h1 { color: #38bdf8; margin-bottom: 5px; font-size: 24px; }
        .subtitle { color: #64748b; margin-bottom: 20px; font-size: 14px; }
        .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 20px; }
        .stat { background: #1e293b; border-radius: 8px; padding: 15px; text-align: center; border: 1px solid #334155; }
        .stat .num { font-size: 28px; font-weight: 700; }
        .stat .label { font-size: 12px; color: #94a3b8; margin-top: 4px; }
        .stat.pass .num { color: #4ade80; }
        .stat.fail .num { color: #f87171; }
        .stat.skip .num { color: #fbbf24; }
        .stat.total .num { color: #38bdf8; }
        .section { background: #1e293b; border-radius: 8px; padding: 20px; margin-bottom: 15px; border: 1px solid #334155; }
        .section h2 { font-size: 16px; margin-bottom: 12px; color: #f87171; }
        .error-item { background: #0f172a; border: 1px solid #374151; border-radius: 6px; padding: 12px; margin-bottom: 10px; }
        .error-item .path { font-family: monospace; color: #38bdf8; font-size: 13px; }
        .error-item .module { color: #a78bfa; font-size: 12px; }
        .error-item .detail { color: #fbbf24; font-size: 12px; margin-top: 6px; font-family: monospace; }
        .error-item .http { display: inline-block; background: #7f1d1d; color: #fca5a5; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
        .passed-item { color: #4ade80; font-size: 13px; font-family: monospace; padding: 3px 0; }
        .warning-item { color: #fbbf24; font-size: 13px; padding: 3px 0; }
        .copy-box { background: #020617; border: 1px solid #334155; border-radius: 8px; padding: 15px; margin-top: 20px; position: relative; }
        .copy-box pre { font-size: 12px; white-space: pre-wrap; word-break: break-all; color: #cbd5e1; max-height: 400px; overflow-y: auto; }
        .copy-btn { position: absolute; top: 10px; left: 10px; background: #3b82f6; color: white; border: none; padding: 6px 14px; border-radius: 5px; cursor: pointer; font-size: 12px; }
        .copy-btn:hover { background: #2563eb; }
        .progress { color: #64748b; font-size: 13px; margin-bottom: 10px; }
    </style></head><body><div class="container">';
    echo '<h1>ERP Smoke Test</h1>';
    echo '<p class="subtitle">Testing: ' . htmlspecialchars($baseUrl) . ' | ' . date('Y-m-d H:i:s') . '</p>';
    if (!ob_get_level()) { ob_flush(); flush(); }
}

// ─── Step 1: Discover All Routes ────────────────────────────────────────────
output("═══════════════════════════════════════════════", 'header');
output("  ERP SMOKE TESTER", 'header');
output("  Base URL: {$baseUrl}", 'header');
output("═══════════════════════════════════════════════", 'header');
output("");

$modulesDir = __DIR__ . '/../app/Modules';
$routeFiles = glob($modulesDir . '/*/Routes.php');

$allRoutes = [];
foreach ($routeFiles as $file) {
    $routes = require $file;
    if (!is_array($routes)) continue;
    foreach ($routes as $route) {
        if (!is_array($route) || count($route) < 3) continue;
        $allRoutes[] = [
            'method' => $route[0],
            'path'   => $route[1],
            'handler'=> $route[2],
            'module' => basename(dirname($file)),
        ];
    }
}

$results['total_routes'] = count($allRoutes);
output("Found " . count($allRoutes) . " routes across " . count($routeFiles) . " modules\n");

if (!$isCli) {
    echo '<p class="progress">Found ' . count($allRoutes) . ' routes across ' . count($routeFiles) . ' modules. Testing...</p>';
    if (!ob_get_level()) { ob_flush(); flush(); }
}

// ─── Step 2: Authenticate ───────────────────────────────────────────────────
output("Authenticating as {$adminEmail}...", 'info');

$cookieFile = sys_get_temp_dir() . '/erp_smoke_test_cookies_' . getmypid() . '.txt';

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $baseUrl . '/login',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_COOKIEJAR => $cookieFile,
    CURLOPT_COOKIEFILE => $cookieFile,
    CURLOPT_TIMEOUT => $timeout,
    CURLOPT_SSL_VERIFYPEER => false,
]);
$loginPage = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!$loginPage || $httpCode >= 400) {
    $msg = "FATAL: Cannot reach login page (HTTP {$httpCode})";
    output($msg, 'error');
    if (!$isCli) {
        echo '<p style="color:#f87171;font-weight:bold;">' . htmlspecialchars($msg) . '</p></div></body></html>';
        return;
    }
    exit(1);
}

$csrfToken = '';
if (preg_match('/name=["\']_csrf_token["\']\s+value=["\']([^"\']+)["\']/', $loginPage, $m)) {
    $csrfToken = $m[1];
} elseif (preg_match('/name=["\']csrf_token["\']\s+value=["\']([^"\']+)["\']/', $loginPage, $m)) {
    $csrfToken = $m[1];
}

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $baseUrl . '/login',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_COOKIEJAR => $cookieFile,
    CURLOPT_COOKIEFILE => $cookieFile,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query([
        'username' => $adminEmail,
        'password' => $adminPassword,
        '_csrf_token' => $csrfToken,
    ]),
    CURLOPT_TIMEOUT => $timeout,
    CURLOPT_SSL_VERIFYPEER => false,
]);
$loginResult = curl_exec($ch);
$loginCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$loginUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
curl_close($ch);

$isLoggedIn = ($loginCode < 400 && strpos($loginUrl, '/login') === false);

if (!$isLoggedIn) {
    output("WARNING: Login may have failed (landed on: {$loginUrl}). Continuing anyway...", 'warning');
    $results['warnings'][] = "Authentication may have failed — some pages may return 403/401";
}
output("Auth complete. Testing routes...\n", 'success');

// ─── Step 3: Test Each GET Route ────────────────────────────────────────────
$getRoutes = array_filter($allRoutes, fn($r) => $r['method'] === 'GET');
$tested = 0;
$passedRoutes = [];

foreach ($getRoutes as $route) {
    if ($tested >= $maxPages) break;

    $path = $route['path'];

    $testPath = preg_replace('/\{[^}]+:\\\d\+\}/', '1', $path);
    $testPath = preg_replace('/\{[^}]+\}/', 'test', $testPath);

    $url = $baseUrl . $testPath;
    $tested++;

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_COOKIEJAR => $cookieFile,
        CURLOPT_COOKIEFILE => $cookieFile,
        CURLOPT_TIMEOUT => $timeout,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_HEADER => true,
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $totalTime = round(curl_getinfo($ch, CURLINFO_TOTAL_TIME), 2);
    $curlError = curl_error($ch);
    curl_close($ch);

    $headerSize = strpos($response, "\r\n\r\n");
    $body = $headerSize !== false ? substr($response, $headerSize + 4) : $response;

    $hasError = false;
    $errorDetails = [];

    if ($curlError) {
        $hasError = true;
        $errorDetails[] = "CURL: {$curlError}";
    }

    if ($httpCode >= 500) {
        $hasError = true;
        $errorDetails[] = "HTTP {$httpCode} Server Error";

        if (preg_match('/Exception.*?Message:\s*(.+?)(?:<|$)/s', $body, $em)) {
            $errorDetails[] = "Exception: " . trim(strip_tags($em[1]));
        } elseif (preg_match('/<h1[^>]*>(.+?)<\/h1>/i', $body, $em)) {
            $errorDetails[] = "Page: " . trim(strip_tags($em[1]));
        }

        if (preg_match('/File:\s*(.+?\.php):?(\d+)?/i', $body, $fm)) {
            $errorDetails[] = "File: " . trim($fm[0]);
        }
        if (preg_match('/SQLSTATE\[.+?\]:.+/i', $body, $sqlm)) {
            $errorDetails[] = "SQL: " . trim(substr($sqlm[0], 0, 200));
        }
        if (preg_match('/Stack trace:(.+?)(?:<\/pre>|<br|$)/s', $body, $stm)) {
            $trace = trim(strip_tags($stm[1]));
            $traceLines = array_filter(explode("\n", $trace));
            $errorDetails[] = "Trace: " . implode(' | ', array_slice($traceLines, 0, 3));
        }
    }

    if ($httpCode === 403) {
        $results['skipped']++;
        continue;
    }

    if ($httpCode === 404) {
        if (strpos($body, 'غير موجود') !== false || strpos($body, 'not found') !== false) {
            $results['passed']++;
            $passedRoutes[] = "[200~] {$testPath} (entity not found - OK)";
            output("  ✓ [{$httpCode}] {$testPath} (entity not found - OK) [{$totalTime}s]", 'success');
            continue;
        }
    }

    $phpErrors = [];
    if (preg_match_all('/(Fatal error|Parse error|Warning|Notice|Deprecated):(.+?)(?:in\s+\/[^\s]+)?(?:\s+on\s+line\s+\d+)?/i', $body, $matches, PREG_SET_ORDER)) {
        foreach ($matches as $match) {
            $phpErrors[] = trim($match[0]);
        }
    }
    if (preg_match('/PDOException|RuntimeException|TypeError|Error\b/', $body, $exMatch)) {
        $phpErrors[] = "Uncaught: " . $exMatch[0];
        if (preg_match('/Message:\s*(.+?)(<|\n)/s', $body, $msgMatch)) {
            $phpErrors[] = trim(strip_tags($msgMatch[1]));
        }
    }
    if (preg_match('/Undefined (variable|index|array key|property)/', $body, $undMatch)) {
        $phpErrors[] = $undMatch[0];
    }

    if (!empty($phpErrors)) {
        $hasError = true;
        $errorDetails = array_merge($errorDetails, $phpErrors);
    }

    if ($totalTime > 5.0) {
        $results['warnings'][] = "SLOW [{$totalTime}s]: {$testPath}";
    }

    if ($hasError) {
        $results['failed']++;
        $results['errors'][] = [
            'route'   => $route['path'],
            'url'     => $testPath,
            'module'  => $route['module'],
            'handler' => $route['handler'],
            'http'    => $httpCode,
            'time'    => $totalTime,
            'details' => $errorDetails,
        ];
        output("  ✗ [{$httpCode}] {$testPath} — " . implode(' | ', array_slice($errorDetails, 0, 2)), 'error');
    } else {
        $results['passed']++;
        $passedRoutes[] = "[{$httpCode}] {$testPath} [{$totalTime}s]";
        if ($httpCode >= 200 && $httpCode < 400) {
            output("  ✓ [{$httpCode}] {$testPath} [{$totalTime}s]", 'success');
        } else {
            output("  ? [{$httpCode}] {$testPath} [{$totalTime}s]", 'warning');
        }
    }
}

$results['tested'] = $tested;
$results['duration'] = round(microtime(true) - $results['start_time'], 1);

// ─── Step 4: Output Report ──────────────────────────────────────────────────
if ($isCli) {
    output("\n═══════════════════════════════════════════════", 'header');
    output("  SMOKE TEST REPORT", 'header');
    output("═══════════════════════════════════════════════", 'header');
    output("");
    output("Total Routes:  {$results['total_routes']}");
    output("GET Tested:    {$results['tested']}");
    output("Passed:        {$results['passed']}", 'success');
    output("Failed:        {$results['failed']}", $results['failed'] > 0 ? 'error' : 'success');
    output("Skipped(403):  {$results['skipped']}");
    output("Duration:      " . $results['duration'] . "s");
    output("");

    if (!empty($results['errors'])) {
        output("─── ERRORS (" . count($results['errors']) . ") ───────────────────────────────", 'error');
        output("");
        foreach ($results['errors'] as $i => $err) {
            $num = $i + 1;
            output("  [{$num}] {$err['module']} :: {$err['handler']}", 'error');
            output("      Route: {$err['route']}");
            output("      URL:   {$err['url']} (HTTP {$err['http']})");
            foreach ($err['details'] as $detail) {
                output("      → {$detail}", 'warning');
            }
            output("");
        }
    }

    if (!empty($results['warnings'])) {
        output("─── WARNINGS (" . count($results['warnings']) . ") ─────────────────────────────", 'warning');
        foreach ($results['warnings'] as $w) {
            output("  ⚠ {$w}", 'warning');
        }
        output("");
    }

    // Compact output for Claude
    if (!empty($results['errors'])) {
        output("\n─── COPY BELOW TO CLAUDE ────────────────────────", 'header');
        output("```");
        output("SMOKE TEST: {$results['failed']} errors / {$results['passed']} passed / {$results['tested']} tested");
        foreach ($results['errors'] as $i => $err) {
            $num = $i + 1;
            output("[{$num}] {$err['module']}::{$err['handler']} HTTP={$err['http']} PATH={$err['url']}");
            foreach ($err['details'] as $detail) {
                output("    {$detail}");
            }
        }
        if (!empty($results['warnings'])) {
            output("WARNINGS:");
            foreach ($results['warnings'] as $w) {
                output("  {$w}");
            }
        }
        output("```");
        output("─── END COPY ───────────────────────────────────", 'header');
    }
} else {
    // ─── Browser HTML Report ────────────────────────────────────────────────
    echo '<div class="stats">';
    echo '<div class="stat total"><div class="num">' . $results['total_routes'] . '</div><div class="label">Total Routes</div></div>';
    echo '<div class="stat total"><div class="num">' . $results['tested'] . '</div><div class="label">Tested</div></div>';
    echo '<div class="stat pass"><div class="num">' . $results['passed'] . '</div><div class="label">Passed</div></div>';
    echo '<div class="stat fail"><div class="num">' . $results['failed'] . '</div><div class="label">Failed</div></div>';
    echo '<div class="stat skip"><div class="num">' . $results['skipped'] . '</div><div class="label">Skipped (403)</div></div>';
    echo '<div class="stat"><div class="num">' . $results['duration'] . 's</div><div class="label">Duration</div></div>';
    echo '</div>';

    // Errors section
    if (!empty($results['errors'])) {
        echo '<div class="section"><h2>Errors (' . count($results['errors']) . ')</h2>';
        foreach ($results['errors'] as $i => $err) {
            echo '<div class="error-item">';
            echo '<span class="http">HTTP ' . $err['http'] . '</span> ';
            echo '<span class="module">' . htmlspecialchars($err['module']) . ' :: ' . htmlspecialchars($err['handler']) . '</span><br>';
            echo '<span class="path">' . htmlspecialchars($err['url']) . '</span>';
            foreach ($err['details'] as $detail) {
                echo '<div class="detail">' . htmlspecialchars($detail) . '</div>';
            }
            echo '</div>';
        }
        echo '</div>';
    }

    // Warnings section
    if (!empty($results['warnings'])) {
        echo '<div class="section"><h2 style="color:#fbbf24;">Warnings (' . count($results['warnings']) . ')</h2>';
        foreach ($results['warnings'] as $w) {
            echo '<div class="warning-item">' . htmlspecialchars($w) . '</div>';
        }
        echo '</div>';
    }

    // Passed routes (collapsible)
    if (!empty($passedRoutes)) {
        echo '<details style="margin-bottom:15px;"><summary style="cursor:pointer;color:#4ade80;padding:10px;background:#1e293b;border-radius:8px;border:1px solid #334155;">Passed Routes (' . count($passedRoutes) . ') — click to expand</summary>';
        echo '<div class="section" style="margin-top:5px;">';
        foreach ($passedRoutes as $pr) {
            echo '<div class="passed-item">' . htmlspecialchars($pr) . '</div>';
        }
        echo '</div></details>';
    }

    // Copy-to-Claude box
    $claudeText = "SMOKE TEST: {$results['failed']} errors / {$results['passed']} passed / {$results['tested']} tested\n";
    foreach ($results['errors'] as $i => $err) {
        $num = $i + 1;
        $claudeText .= "[{$num}] {$err['module']}::{$err['handler']} HTTP={$err['http']} PATH={$err['url']}\n";
        foreach ($err['details'] as $detail) {
            $claudeText .= "    {$detail}\n";
        }
    }
    if (!empty($results['warnings'])) {
        $claudeText .= "WARNINGS:\n";
        foreach ($results['warnings'] as $w) {
            $claudeText .= "  {$w}\n";
        }
    }

    echo '<div class="copy-box">';
    echo '<button class="copy-btn" onclick="copyReport()">Copy for Claude</button>';
    echo '<pre id="claude-report">' . htmlspecialchars($claudeText) . '</pre>';
    echo '</div>';

    echo '<script>
    function copyReport() {
        const text = document.getElementById("claude-report").textContent;
        navigator.clipboard.writeText(text).then(() => {
            const btn = document.querySelector(".copy-btn");
            btn.textContent = "Copied!";
            btn.style.background = "#059669";
            setTimeout(() => { btn.textContent = "Copy for Claude"; btn.style.background = "#3b82f6"; }, 2000);
        });
    }
    </script>';

    echo '</div></body></html>';
}

// ─── Save JSON report ───────────────────────────────────────────────────────
$reportFile = sys_get_temp_dir() . '/erp_smoke_test_report.json';
@file_put_contents($reportFile, json_encode($results, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
if ($isCli) output("Full report saved to: {$reportFile}");

@unlink($cookieFile);

if ($isCli && !defined('SMOKE_TEST_INCLUDED')) exit($results['failed'] > 0 ? 1 : 0);
