<?php
/**
 * speed_test.php — Escobar Web Page Speed Tester
 * Taruh di folder root (sejajar config.php)
 * Akses: http://localhost/escobarweb/speed_test.php
 */

// Halaman yang akan ditest (tambah/kurang sesuai kebutuhan)
$pages = [
    'index.php'        => 'Dashboard',
    'history.php'      => 'Riwayat Transaksi',
    'closing.php'      => 'Closing Shift',
    'inventory.php'    => 'Paket & Stok',
    'units.php'        => 'Kelola Unit',
    'members.php'      => 'Member VIP',
    'settings.php'     => 'Pengaturan',
    'users.php'        => 'Kelola Operator',
    'tuya_control.php' => 'Smart Plug Tuya',
    'absensi.php'      => 'Absensi Online',
    'laporan_wa.php'   => 'Laporan WA',
    'pembayaran.php'   => 'Pembayaran',
    'guide.php'        => 'Panduan',
    'about.php'        => 'Tentang',
    'sticks.php'       => 'Management Stik',
    'setup_tv.php'     => 'Setup TV',
    'export_pdf.php'   => 'Export PDF',
    'process.php'      => 'Process (API)',
    'tuya_api.php'     => 'Tuya API',
    'sync_report.php'  => 'Sync Report',
    'config.php'       => 'Config (Core)',
];

// Ukur waktu load setiap file (PHP parse + top-level execution)
function measure_file($file) {
    $path = __DIR__ . '/' . $file;
    if (!file_exists($path)) return ['exists' => false, 'ms' => 0, 'size' => 0, 'lines' => 0];

    $size  = filesize($path);
    $lines = count(file($path));

    // Ukur waktu token_get_all (parse overhead)
    $src   = file_get_contents($path);
    $t0    = microtime(true);
    @token_get_all($src);
    $parse_ms = round((microtime(true) - $t0) * 1000, 2);

    // Deteksi potensi masalah
    $issues = [];
    if (strpos($src, 'shell_exec') !== false || strpos($src, 'exec(') !== false)
        $issues[] = 'shell_exec';
    if (strpos($src, 'curl_exec') !== false)
        $issues[] = 'cURL';
    if (substr_count($src, 'sleep(') + substr_count($src, 'usleep(') > 0)
        $issues[] = 'sleep()';
    if (strpos($src, 'setInterval') !== false)
        $issues[] = 'setInterval';
    if (strpos($src, 'setInterval') !== false) {
        preg_match_all('/setInterval\s*\([^,]+,\s*(\d+)\)/', $src, $m);
        foreach ($m[1] as $ms) {
            if ((int)$ms < 5000) $issues[] = 'interval<5s';
        }
    }
    if (strpos($src, "mysqli_query\|->query(") !== false || substr_count($src, '->query(') > 5)
        $issues[] = 'banyak query';
    if (strpos($src, 'file_get_contents') !== false && strpos($src, 'http') !== false)
        $issues[] = 'HTTP request';

    // Hitung jumlah query DB
    $query_count = substr_count($src, '->query(') + substr_count($src, 'mysqli_query(');
    // Hitung jumlah setInterval
    $interval_count = substr_count($src, 'setInterval');
    // Hitung jumlah fetch/XHR
    $fetch_count = substr_count($src, "fetch(") + substr_count($src, 'XMLHttpRequest');

    return [
        'exists'         => true,
        'ms'             => $parse_ms,
        'size'           => $size,
        'lines'          => $lines,
        'issues'         => $issues,
        'query_count'    => $query_count,
        'interval_count' => $interval_count,
        'fetch_count'    => $fetch_count,
    ];
}

$results = [];
$t_global = microtime(true);
foreach ($pages as $file => $label) {
    $results[$file] = array_merge(['label' => $label], measure_file($file));
}
$total_scan_ms = round((microtime(true) - $t_global) * 1000);

// Sort by issues count desc untuk tampilkan yang paling bermasalah duluan
usort($results, function($a, $b) {
    $score_a = count($a['issues'] ?? []) * 10 + ($a['interval_count'] ?? 0) * 3 + ($a['fetch_count'] ?? 0);
    $score_b = count($b['issues'] ?? []) * 10 + ($b['interval_count'] ?? 0) * 3 + ($b['fetch_count'] ?? 0);
    return $score_b - $score_a;
});

function fmt_size($bytes) {
    if ($bytes > 1024*1024) return round($bytes/1024/1024, 1) . ' MB';
    if ($bytes > 1024) return round($bytes/1024, 1) . ' KB';
    return $bytes . ' B';
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Escobar — Speed Test</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=DM+Sans:wght@400;500;600;700&display=swap');

:root {
    --bg: #070b12;
    --surface: #0d1520;
    --surface2: #111d2e;
    --border: rgba(0,200,150,0.12);
    --accent: #00c896;
    --accent2: #00a8ff;
    --warn: #ffb800;
    --danger: #ff4560;
    --text: #d4e8e0;
    --muted: #4a6472;
    --mono: 'Space Mono', monospace;
    --sans: 'DM Sans', sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--sans);
    min-height: 100vh;
    padding: 32px 24px;
    background-image:
        radial-gradient(ellipse 60% 40% at 80% 10%, rgba(0,200,150,0.06) 0%, transparent 60%),
        radial-gradient(ellipse 40% 60% at 10% 80%, rgba(0,168,255,0.05) 0%, transparent 60%);
}

/* ── HEADER ── */
.header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    margin-bottom: 36px;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--border);
}
.header-left h1 {
    font-family: var(--mono);
    font-size: 1.6rem;
    color: var(--accent);
    letter-spacing: -1px;
    line-height: 1;
}
.header-left p {
    color: var(--muted);
    font-size: 0.8rem;
    margin-top: 6px;
    font-family: var(--mono);
}
.scan-time {
    font-family: var(--mono);
    font-size: 0.72rem;
    color: var(--muted);
    background: var(--surface);
    padding: 6px 14px;
    border-radius: 20px;
    border: 1px solid var(--border);
}

/* ── SUMMARY CARDS ── */
.summary {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 14px;
    margin-bottom: 32px;
}
.scard {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 16px 18px;
}
.scard .label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--muted);
    margin-bottom: 8px;
    font-family: var(--mono);
}
.scard .value {
    font-family: var(--mono);
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1;
}
.scard .value.danger { color: var(--danger); }
.scard .value.warn   { color: var(--warn); }
.scard .value.ok     { color: var(--accent); }

/* ── FILTER BAR ── */
.filter-bar {
    display: flex;
    gap: 8px;
    margin-bottom: 20px;
    flex-wrap: wrap;
    align-items: center;
}
.filter-btn {
    padding: 6px 16px;
    border-radius: 20px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--muted);
    font-size: 0.78rem;
    font-family: var(--mono);
    cursor: pointer;
    transition: 0.2s;
}
.filter-btn:hover, .filter-btn.active {
    border-color: var(--accent);
    color: var(--accent);
    background: rgba(0,200,150,0.07);
}
.filter-btn.danger.active { border-color: var(--danger); color: var(--danger); background: rgba(255,69,96,0.07); }
.filter-btn.warn.active   { border-color: var(--warn); color: var(--warn); background: rgba(255,184,0,0.07); }

.search-input {
    margin-left: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 6px 14px;
    border-radius: 20px;
    font-size: 0.8rem;
    font-family: var(--mono);
    outline: none;
    width: 180px;
    transition: 0.2s;
}
.search-input:focus { border-color: var(--accent); }

/* ── TABLE ── */
.table-wrap {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    overflow: hidden;
}

table {
    width: 100%;
    border-collapse: collapse;
}

thead tr {
    background: var(--surface2);
    border-bottom: 1px solid var(--border);
}
th {
    padding: 12px 16px;
    text-align: left;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--muted);
    font-family: var(--mono);
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
th:hover { color: var(--accent); }
th .sort-icon { opacity: 0.4; margin-left: 4px; }
th.sorted .sort-icon { opacity: 1; color: var(--accent); }

tbody tr {
    border-bottom: 1px solid rgba(0,200,150,0.05);
    transition: background 0.15s;
}
tbody tr:last-child { border-bottom: none; }
tbody tr:hover { background: rgba(0,200,150,0.03); }
tbody tr.hidden-row { display: none; }

td {
    padding: 13px 16px;
    font-size: 0.84rem;
    vertical-align: middle;
}

/* file name */
.file-name {
    font-family: var(--mono);
    font-size: 0.8rem;
    color: var(--accent2);
}
.file-label {
    font-size: 0.75rem;
    color: var(--muted);
    margin-top: 2px;
}

/* risk score bar */
.risk-wrap { display: flex; align-items: center; gap: 10px; }
.risk-bar-bg {
    flex: 1;
    height: 6px;
    background: rgba(255,255,255,0.05);
    border-radius: 10px;
    overflow: hidden;
    min-width: 60px;
}
.risk-bar-fill {
    height: 100%;
    border-radius: 10px;
    transition: width 0.6s cubic-bezier(0.4,0,0.2,1);
}
.risk-val {
    font-family: var(--mono);
    font-size: 0.75rem;
    min-width: 24px;
    text-align: right;
}

/* badges */
.badges { display: flex; flex-wrap: wrap; gap: 4px; }
.badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 20px;
    font-size: 0.68rem;
    font-family: var(--mono);
    font-weight: 700;
    white-space: nowrap;
}
.badge-danger { background: rgba(255,69,96,0.15); color: var(--danger); border: 1px solid rgba(255,69,96,0.3); }
.badge-warn   { background: rgba(255,184,0,0.12); color: var(--warn);   border: 1px solid rgba(255,184,0,0.3); }
.badge-ok     { background: rgba(0,200,150,0.1);  color: var(--accent); border: 1px solid rgba(0,200,150,0.25); }
.badge-info   { background: rgba(0,168,255,0.1);  color: var(--accent2);border: 1px solid rgba(0,168,255,0.25); }

/* stats cells */
.stat-num {
    font-family: var(--mono);
    font-size: 0.82rem;
    text-align: center;
}
.stat-num.hot { color: var(--danger); font-weight: 700; }
.stat-num.warm { color: var(--warn); }
.stat-num.cool { color: var(--muted); }

/* size */
.size-text {
    font-family: var(--mono);
    font-size: 0.78rem;
    color: var(--muted);
}

/* not found */
.not-found { color: var(--muted); font-style: italic; font-size: 0.78rem; }

/* ── DETAIL DRAWER ── */
.drawer {
    display: none;
    background: var(--bg);
    border-top: 1px solid var(--border);
}
.drawer.open { display: table-row; }
.drawer td { padding: 0; }
.drawer-inner {
    padding: 20px 24px;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 16px;
}
.drawer-section h4 {
    font-family: var(--mono);
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--muted);
    margin-bottom: 10px;
}
.drawer-section ul { list-style: none; }
.drawer-section ul li {
    font-size: 0.8rem;
    padding: 4px 0;
    border-bottom: 1px solid rgba(255,255,255,0.04);
    display: flex;
    justify-content: space-between;
    gap: 16px;
}
.drawer-section ul li span { color: var(--muted); font-size: 0.75rem; font-family: var(--mono); }

/* ── LEGEND ── */
.legend {
    margin-top: 24px;
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    padding: 16px 20px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
}
.legend-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.75rem;
    color: var(--muted);
}

/* ── LIVE TEST SECTION ── */
.live-section {
    margin-top: 28px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 24px;
}
.live-section h2 {
    font-family: var(--mono);
    font-size: 1rem;
    color: var(--accent);
    margin-bottom: 6px;
}
.live-section p {
    font-size: 0.8rem;
    color: var(--muted);
    margin-bottom: 20px;
}
.btn-run {
    background: var(--accent);
    color: #000;
    border: none;
    padding: 10px 24px;
    border-radius: 10px;
    font-family: var(--mono);
    font-weight: 700;
    font-size: 0.82rem;
    cursor: pointer;
    transition: 0.2s;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.btn-run:hover { filter: brightness(1.15); transform: translateY(-1px); }
.btn-run:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

.live-results { margin-top: 20px; display: none; }
.live-bar-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 10px;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.3s, transform 0.3s;
}
.live-bar-row.visible { opacity: 1; transform: none; }
.live-bar-name {
    font-family: var(--mono);
    font-size: 0.75rem;
    width: 160px;
    flex-shrink: 0;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.live-bar-track {
    flex: 1;
    height: 8px;
    background: rgba(255,255,255,0.05);
    border-radius: 10px;
    overflow: hidden;
}
.live-bar-fill {
    height: 100%;
    border-radius: 10px;
    width: 0;
    transition: width 0.5s cubic-bezier(0.4,0,0.2,1);
}
.live-bar-ms {
    font-family: var(--mono);
    font-size: 0.75rem;
    width: 60px;
    text-align: right;
    flex-shrink: 0;
}
.live-status {
    font-size: 0.7rem;
    width: 60px;
    flex-shrink: 0;
}
.progress-info {
    font-family: var(--mono);
    font-size: 0.78rem;
    color: var(--muted);
    margin-bottom: 14px;
}

@media (max-width: 768px) {
    .drawer-inner { grid-template-columns: 1fr; }
    .summary { grid-template-columns: repeat(2, 1fr); }
    th:nth-child(n+5) { display: none; }
    td:nth-child(n+5) { display: none; }
}
</style>
</head>
<body>

<?php
// Hitung summary stats
$total_files   = count($results);
$exist_count   = count(array_filter($results, fn($r) => $r['exists']));
$danger_count  = count(array_filter($results, fn($r) => count($r['issues'] ?? []) >= 3));
$warn_count    = count(array_filter($results, fn($r) => count($r['issues'] ?? []) >= 1 && count($r['issues'] ?? []) < 3));
$total_shell   = array_sum(array_column(array_filter($results, fn($r) => in_array('shell_exec', $r['issues'] ?? [])), 'exists'));
$total_curl    = count(array_filter($results, fn($r) => in_array('cURL', $r['issues'] ?? [])));
$total_sleep   = count(array_filter($results, fn($r) => in_array('sleep()', $r['issues'] ?? [])));
?>

<div class="header">
    <div class="header-left">
        <h1>⚡ SPEED_TEST</h1>
        <p>Escobar Web · Analisa kecepatan &amp; risiko per file</p>
    </div>
    <div class="scan-time">Scan selesai dalam <?= $total_scan_ms ?>ms · <?= date('H:i:s') ?></div>
</div>

<!-- Summary -->
<div class="summary">
    <div class="scard">
        <div class="label">Total File</div>
        <div class="value ok"><?= $exist_count ?></div>
    </div>
    <div class="scard">
        <div class="label">Risiko Tinggi</div>
        <div class="value danger"><?= $danger_count ?></div>
    </div>
    <div class="scard">
        <div class="label">Risiko Sedang</div>
        <div class="value warn"><?= $warn_count ?></div>
    </div>
    <div class="scard">
        <div class="label">shell_exec</div>
        <div class="value <?= $total_shell > 0 ? 'danger' : 'ok' ?>"><?= $total_shell ?></div>
    </div>
    <div class="scard">
        <div class="label">cURL</div>
        <div class="value <?= $total_curl > 0 ? 'warn' : 'ok' ?>"><?= $total_curl ?></div>
    </div>
    <div class="scard">
        <div class="label">sleep()</div>
        <div class="value <?= $total_sleep > 0 ? 'warn' : 'ok' ?>"><?= $total_sleep ?></div>
    </div>
</div>

<!-- Filter -->
<div class="filter-bar">
    <button class="filter-btn active" onclick="filterRows('all', this)">Semua</button>
    <button class="filter-btn danger" onclick="filterRows('danger', this)">🔴 Risiko Tinggi</button>
    <button class="filter-btn warn" onclick="filterRows('warn', this)">🟡 Risiko Sedang</button>
    <button class="filter-btn" onclick="filterRows('ok', this)">🟢 Aman</button>
    <input class="search-input" type="text" placeholder="cari file..." oninput="searchRows(this.value)">
</div>

<!-- Table -->
<div class="table-wrap">
<table id="main-table">
<thead>
    <tr>
        <th onclick="sortTable(0)">File <span class="sort-icon">↕</span></th>
        <th onclick="sortTable(1)">Risk Score <span class="sort-icon">↕</span></th>
        <th>Masalah Terdeteksi</th>
        <th onclick="sortTable(3)" title="Jumlah DB query">DB <span class="sort-icon">↕</span></th>
        <th onclick="sortTable(4)" title="setInterval count">⏱ <span class="sort-icon">↕</span></th>
        <th onclick="sortTable(5)" title="fetch/XHR count">📡 <span class="sort-icon">↕</span></th>
        <th onclick="sortTable(6)">Ukuran <span class="sort-icon">↕</span></th>
        <th onclick="sortTable(7)">Baris <span class="sort-icon">↕</span></th>
    </tr>
</thead>
<tbody>
<?php
foreach ($results as $file => $r):
    if (!$r['exists']) continue;

    $issue_count = count($r['issues']);
    $risk = $r['interval_count'] * 3 + $r['fetch_count'] * 2 + $issue_count * 10;
    $risk = min($risk, 100);

    if ($risk >= 30) $risk_class = 'danger';
    elseif ($risk >= 10) $risk_class = 'warn';
    else $risk_class = 'ok';

    $bar_color = $risk_class === 'danger' ? 'var(--danger)' : ($risk_class === 'warn' ? 'var(--warn)' : 'var(--accent)');
    $row_id = 'row-' . md5($file);
    $drawer_id = 'drawer-' . md5($file);
?>
<tr class="data-row <?= $risk_class ?>" id="<?= $row_id ?>" onclick="toggleDrawer('<?= $drawer_id ?>', this)">
    <td>
        <div class="file-name"><?= htmlspecialchars($file) ?></div>
        <div class="file-label"><?= htmlspecialchars($r['label']) ?></div>
    </td>
    <td>
        <div class="risk-wrap">
            <div class="risk-bar-bg">
                <div class="risk-bar-fill" style="width:<?= $risk ?>%;background:<?= $bar_color ?>"></div>
            </div>
            <div class="risk-val" style="color:<?= $bar_color ?>"><?= $risk ?></div>
        </div>
    </td>
    <td>
        <div class="badges">
        <?php if (empty($r['issues'])): ?>
            <span class="badge badge-ok">✓ bersih</span>
        <?php else: foreach ($r['issues'] as $iss):
            $bc = in_array($iss, ['shell_exec','sleep()']) ? 'badge-danger' : 'badge-warn';
        ?>
            <span class="badge <?= $bc ?>"><?= htmlspecialchars($iss) ?></span>
        <?php endforeach; endif; ?>
        </div>
    </td>
    <td class="stat-num <?= $r['query_count'] > 5 ? 'hot' : ($r['query_count'] > 2 ? 'warm' : 'cool') ?>">
        <?= $r['query_count'] ?: '—' ?>
    </td>
    <td class="stat-num <?= $r['interval_count'] > 2 ? 'hot' : ($r['interval_count'] > 0 ? 'warm' : 'cool') ?>">
        <?= $r['interval_count'] ?: '—' ?>
    </td>
    <td class="stat-num <?= $r['fetch_count'] > 5 ? 'hot' : ($r['fetch_count'] > 2 ? 'warm' : 'cool') ?>">
        <?= $r['fetch_count'] ?: '—' ?>
    </td>
    <td class="size-text"><?= fmt_size($r['size']) ?></td>
    <td class="stat-num cool"><?= number_format($r['lines']) ?></td>
</tr>
<tr class="drawer" id="<?= $drawer_id ?>">
    <td colspan="8">
        <div class="drawer-inner">
            <div class="drawer-section">
                <h4>📊 Statistik File</h4>
                <ul>
                    <li>Ukuran <span><?= fmt_size($r['size']) ?></span></li>
                    <li>Baris kode <span><?= number_format($r['lines']) ?></span></li>
                    <li>Query DB <span><?= $r['query_count'] ?></span></li>
                    <li>setInterval <span><?= $r['interval_count'] ?></span></li>
                    <li>fetch/XHR <span><?= $r['fetch_count'] ?></span></li>
                    <li>Risk Score <span><?= $risk ?>/100</span></li>
                </ul>
            </div>
            <div class="drawer-section">
                <h4>⚠️ Masalah Terdeteksi</h4>
                <ul>
                <?php if (empty($r['issues'])): ?>
                    <li>Tidak ada masalah terdeteksi <span>✓</span></li>
                <?php else: foreach ($r['issues'] as $iss): ?>
                    <li><?= htmlspecialchars($iss) ?> <span style="color:var(--danger)">⚠</span></li>
                <?php endforeach; endif; ?>
                </ul>
            </div>
            <div class="drawer-section">
                <h4>💡 Rekomendasi</h4>
                <ul>
                <?php
                if (in_array('shell_exec', $r['issues'])):
                    echo '<li>Pindahkan shell_exec ke background job <span>penting</span></li>';
                endif;
                if (in_array('cURL', $r['issues'])):
                    echo '<li>Cache hasil cURL di session/DB <span>penting</span></li>';
                endif;
                if (in_array('sleep()', $r['issues'])):
                    echo '<li>Hapus sleep(), ganti dengan async/retry <span>sedang</span></li>';
                endif;
                if ($r['interval_count'] > 2):
                    echo '<li>Kurangi setInterval, gabung jadi 1 poller <span>sedang</span></li>';
                endif;
                if ($r['fetch_count'] > 5):
                    echo '<li>Batasi jumlah concurrent fetch <span>sedang</span></li>';
                endif;
                if ($r['query_count'] > 5):
                    echo '<li>Review query N+1, pertimbangkan JOIN <span>sedang</span></li>';
                endif;
                if (empty($r['issues']) && $r['query_count'] <= 2 && $r['interval_count'] == 0):
                    echo '<li>File ini sudah optimal <span>✓</span></li>';
                endif;
                ?>
                </ul>
            </div>
        </div>
    </td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>

<!-- Legend -->
<div class="legend">
    <div class="legend-item"><span style="color:var(--danger)">●</span> Risk ≥30 = Bermasalah (kemungkinan sebabkan loading lambat)</div>
    <div class="legend-item"><span style="color:var(--warn)">●</span> Risk 10–29 = Perlu diperhatikan</div>
    <div class="legend-item"><span style="color:var(--accent)">●</span> Risk &lt;10 = Aman</div>
    <div class="legend-item">⏱ = jumlah setInterval (JS polling)</div>
    <div class="legend-item">📡 = jumlah fetch/XHR</div>
    <div class="legend-item">DB = jumlah database query</div>
</div>

<!-- Live HTTP Test -->
<div class="live-section">
    <h2>🌐 Live HTTP Speed Test</h2>
    <p>Test waktu response nyata tiap file via HTTP request — hasilnya lebih akurat dari simulasi. Klik baris untuk detail.</p>
    <button class="btn-run" id="btn-run" onclick="runLiveTest()">▶ Jalankan Live Test</button>
    <div class="live-results" id="live-results">
        <div class="progress-info" id="progress-info">Mempersiapkan...</div>
        <div id="live-bars"></div>
    </div>
</div>

<script>
// ── DRAWER TOGGLE ──
function toggleDrawer(id, row) {
    const drawer = document.getElementById(id);
    const isOpen = drawer.classList.contains('open');
    document.querySelectorAll('.drawer.open').forEach(d => d.classList.remove('open'));
    document.querySelectorAll('.data-row.selected').forEach(r => r.classList.remove('selected'));
    if (!isOpen) {
        drawer.classList.add('open');
        row.classList.add('selected');
        row.style.background = 'rgba(0,200,150,0.05)';
    } else {
        row.style.background = '';
    }
}

// ── FILTER ──
let currentFilter = 'all';
function filterRows(type, btn) {
    currentFilter = type;
    document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
    btn.classList.add('active');
    applyFilters();
}
function applyFilters() {
    document.querySelectorAll('.data-row').forEach(row => {
        const matchFilter = currentFilter === 'all' || row.classList.contains(currentFilter);
        const search = document.querySelector('.search-input').value.toLowerCase();
        const matchSearch = !search || row.textContent.toLowerCase().includes(search);
        row.style.display = (matchFilter && matchSearch) ? '' : 'none';
        // also hide drawer
        const drawerId = row.id.replace('row-', 'drawer-');
        const drawer = document.getElementById(drawerId);
        if (drawer) drawer.style.display = (matchFilter && matchSearch) ? '' : 'none';
    });
}
function searchRows(val) { applyFilters(); }

// ── SORT ──
let sortDir = {};
function sortTable(col) {
    const tbody = document.querySelector('#main-table tbody');
    const rows  = [...tbody.querySelectorAll('tr.data-row')];
    const dir   = (sortDir[col] = !(sortDir[col]));

    rows.sort((a, b) => {
        const ta = a.querySelectorAll('td')[col]?.textContent.trim() || '';
        const tb = b.querySelectorAll('td')[col]?.textContent.trim() || '';
        const na = parseFloat(ta.replace(/[^\d.]/g, ''));
        const nb = parseFloat(tb.replace(/[^\d.]/g, ''));
        const isNum = !isNaN(na) && !isNaN(nb);
        const cmp = isNum ? na - nb : ta.localeCompare(tb);
        return dir ? cmp : -cmp;
    });

    document.querySelectorAll('th').forEach((th, i) => {
        th.classList.toggle('sorted', i === col);
        const icon = th.querySelector('.sort-icon');
        if (icon) icon.textContent = i === col ? (dir ? '↑' : '↓') : '↕';
    });

    rows.forEach(row => {
        tbody.appendChild(row);
        const drawerId = row.id.replace('row-', 'drawer-');
        const drawer = document.getElementById(drawerId);
        if (drawer) tbody.appendChild(drawer);
    });
}

// ── LIVE HTTP TEST ──
const livePages = <?= json_encode(array_keys(array_filter($results, fn($r) => $r['exists']))) ?>;

async function runLiveTest() {
    const btn      = document.getElementById('btn-run');
    const section  = document.getElementById('live-results');
    const barsDiv  = document.getElementById('live-bars');
    const progress = document.getElementById('progress-info');

    btn.disabled   = true;
    btn.innerHTML  = '⏳ Testing...';
    section.style.display = 'block';
    barsDiv.innerHTML     = '';

    // Buat placeholder bar dulu
    const barEls = {};
    livePages.forEach(file => {
        const row = document.createElement('div');
        row.className = 'live-bar-row';
        row.id = 'live-row-' + file.replace('.', '_');
        row.innerHTML = `
            <div class="live-bar-name" title="${file}">${file}</div>
            <div class="live-bar-track"><div class="live-bar-fill" id="fill-${file.replace('.','_')}" style="background:var(--muted)"></div></div>
            <div class="live-bar-ms" id="ms-${file.replace('.','_')}">—</div>
            <div class="live-status" id="st-${file.replace('.','_')}">⏳</div>
        `;
        barsDiv.appendChild(row);
        setTimeout(() => row.classList.add('visible'), 50);
        barEls[file] = row;
    });

    // Jalankan test satu per satu agar tidak flood server
    const timings = {};
    let maxMs = 0;

    for (let i = 0; i < livePages.length; i++) {
        const file = livePages[i];
        progress.textContent = `Testing ${i+1}/${livePages.length}: ${file}`;

        const fillEl = document.getElementById('fill-' + file.replace('.','_'));
        const msEl   = document.getElementById('ms-' + file.replace('.','_'));
        const stEl   = document.getElementById('st-' + file.replace('.','_'));

        fillEl.style.background = 'var(--accent2)';
        fillEl.style.width = '5%';

        try {
            const t0  = performance.now();
            const res = await fetch(file + '?_speedtest=1&_t=' + Date.now(), {
                method: 'GET',
                cache: 'no-store',
                credentials: 'include',
            });
            const ms = Math.round(performance.now() - t0);
            timings[file] = { ms, status: res.status };
            maxMs = Math.max(maxMs, ms);

            // Update bar placeholder dengan nilai sementara
            msEl.textContent = ms + 'ms';
            stEl.textContent = res.status === 200 ? '✓' : '⚠' + res.status;
            fillEl.style.background = ms > 3000 ? 'var(--danger)' : ms > 1000 ? 'var(--warn)' : 'var(--accent)';
        } catch(e) {
            timings[file] = { ms: 0, status: 'ERR' };
            msEl.textContent = 'ERR';
            stEl.textContent = '✗';
            fillEl.style.background = 'var(--danger)';
        }
    }

    // Update semua bar width berdasarkan max
    progress.textContent = `✅ Selesai — ${livePages.length} file ditest`;
    livePages.forEach(file => {
        const t = timings[file];
        if (!t || t.ms === 0) return;
        const pct = Math.max(4, Math.round((t.ms / maxMs) * 100));
        const fillEl = document.getElementById('fill-' + file.replace('.','_'));
        fillEl.style.width = pct + '%';
        const msEl = document.getElementById('ms-' + file.replace('.','_'));
        msEl.style.color = t.ms > 3000 ? 'var(--danger)' : t.ms > 1000 ? 'var(--warn)' : 'var(--accent)';
    });

    // Sort live bars by ms desc
    const sorted = Object.entries(timings).sort((a,b) => (b[1].ms||0) - (a[1].ms||0));
    sorted.forEach(([file]) => {
        const row = document.getElementById('live-row-' + file.replace('.','_'));
        if (row) barsDiv.appendChild(row);
    });

    btn.disabled  = false;
    btn.innerHTML = '🔄 Ulangi Test';
}
</script>
</body>
</html>