{% extends "base.html" %}

{% block title %}Admin | Server-Verwaltung{% endblock %}

{% block content %}
<section class="head">
    <h1>Server-Verwaltung</h1>
    <p>Zentrale Betriebsübersicht und Aktionen rund um Website, Instanzen, Ressourcen und Wartung.</p>
</section>

<section class="kpi-grid">
    <article class="kpi-card">
        <p class="kpi-label">Instanzen (Laufend)</p>
        <p class="kpi-value" id="kpiInstancesRunning">{{ (system_snapshot.runtime.instances | selectattr('status', 'equalto', 'Läuft') | list | length) }}</p>
    </article>
    <article class="kpi-card">
        <p class="kpi-label">Offene Tickets</p>
        <p class="kpi-value" id="kpiTicketsOpen">{{ system_snapshot.ops.tickets_open }}</p>
    </article>
    <article class="kpi-card">
        <p class="kpi-label">Angefragte Termine</p>
        <p class="kpi-value" id="kpiAppointmentsPending">{{ system_snapshot.ops.appointments_pending }}</p>
    </article>
    <article class="kpi-card">
        <p class="kpi-label">Nutzer gesamt</p>
        <p class="kpi-value" id="kpiUsersTotal">{{ system_snapshot.ops.users_total }}</p>
    </article>
    <article class="kpi-card">
        <p class="kpi-label">Host RAM</p>
        <p class="kpi-value" id="kpiHostRam">{{ system_snapshot.runtime.host.used_mem_mib }} MiB</p>
    </article>
    <article class="kpi-card">
        <p class="kpi-label">Docker RAM (Invario)</p>
        <p class="kpi-value" id="kpiDockerManaged">{{ system_snapshot.runtime.docker.managed_used_mem_mib }} MiB</p>
    </article>
</section>

<section class="overview-grid">
    <article class="panel">
        <h2>Systemstatus</h2>
        <dl class="kv-grid">
            <dt>Uptime</dt><dd id="sysUptime">{{ system_snapshot.system.uptime_seconds }} s</dd>
            <dt>Load 1/5/15</dt><dd id="sysLoad">{{ system_snapshot.system.load_1 }} / {{ system_snapshot.system.load_5 }} / {{ system_snapshot.system.load_15 }}</dd>
            <dt>Letztes Update</dt><dd id="sysUpdatedAt">{{ system_snapshot.generated_at }}</dd>
        </dl>
    </article>

    <article class="panel">
        <h2>Speicher (Root)</h2>
        <dl class="kv-grid">
            <dt>Belegt</dt><dd id="rootUsed">{{ system_snapshot.root_disk.used_gib }} GiB</dd>
            <dt>Frei</dt><dd id="rootFree">{{ system_snapshot.root_disk.free_gib }} GiB</dd>
            <dt>Auslastung</dt><dd id="rootPct">{{ system_snapshot.root_disk.used_pct }} %</dd>
        </dl>
    </article>

    <article class="panel">
        <h2>Instanz-Speicher</h2>
        <dl class="kv-grid">
            <dt>Pfad</dt><dd>{{ system_snapshot.instance_disk.path }}</dd>
            <dt>Belegt</dt><dd id="instUsed">{{ system_snapshot.instance_disk.used_gib }} GiB</dd>
            <dt>Frei</dt><dd id="instFree">{{ system_snapshot.instance_disk.free_gib }} GiB</dd>
            <dt>Auslastung</dt><dd id="instPct">{{ system_snapshot.instance_disk.used_pct }} %</dd>
        </dl>
    </article>
</section>

<section class="usage-grid">
    <article class="panel usage-panel">
        <h2>Usage-Diagramme</h2>
        <div class="usage-row">
            <div class="usage-top">
                <span>Host RAM</span>
                <strong id="usageHostRamLabel">0.0 %</strong>
            </div>
            <div class="usage-bar"><span id="usageHostRamFill"></span></div>
        </div>
        <div class="usage-row">
            <div class="usage-top">
                <span>Host CPU</span>
                <strong id="usageHostCpuLabel">0.0 %</strong>
            </div>
            <div class="usage-bar"><span id="usageHostCpuFill"></span></div>
        </div>
        <div class="usage-row">
            <div class="usage-top">
                <span>Root-Disk</span>
                <strong id="usageRootDiskLabel">0.0 %</strong>
            </div>
            <div class="usage-bar"><span id="usageRootDiskFill"></span></div>
        </div>
        <div class="usage-row">
            <div class="usage-top">
                <span>Instanz-Disk</span>
                <strong id="usageInstDiskLabel">0.0 %</strong>
            </div>
            <div class="usage-bar"><span id="usageInstDiskFill"></span></div>
        </div>
    </article>
</section>

<section class="charts-grid">
    <article class="panel chart-panel">
        <h2>Verlauf: RAM</h2>
        <canvas id="ramHistoryChart" height="140"></canvas>
    </article>
    <article class="panel chart-panel">
        <h2>Verlauf: CPU / Load</h2>
        <canvas id="cpuLoadHistoryChart" height="140"></canvas>
    </article>
    <article class="panel chart-panel">
        <h2>Verlauf: Docker-Container</h2>
        <canvas id="containerHistoryChart" height="140"></canvas>
    </article>
</section>

<section class="core-tools panel">
    <h2>Core-Services</h2>
    <div class="actions">
        <form method="post">
            <input type="hidden" name="action" value="restart_core">
            <button type="submit">Website + MongoDB neu starten</button>
        </form>
        <a class="action-link" href="{{ url_for('admin_download_core_logs') }}">Core-Logs herunterladen</a>
    </div>
</section>

<section class="panel logs-panel">
    <h2>Live-Logs (Core + Services)</h2>
    <p class="logs-hint">Zeigt die letzten Zeilen der normalen Dienste direkt im Admin-Frontend an. Aktualisiert automatisch alle 20 Sekunden.</p>
    <div class="logs-toolbar">
        <label for="logSourceSelect">Quelle</label>
        <select id="logSourceSelect"></select>
        <button type="button" id="refreshLiveLogsBtn">Jetzt aktualisieren</button>
        <span id="liveLogsUpdatedAt">Stand: -</span>
    </div>
    <pre id="liveLogsOutput" class="log-output">Lade Logs ...</pre>
</section>

<section class="instance-tools panel">
    <h2>Instanz-Operationen</h2>
    {% if instances %}
    <table>
        <thead>
            <tr>
                <th>Schule</th>
                <th>Subdomain</th>
                <th>Status</th>
                <th>Live</th>
                <th>Aktionen</th>
            </tr>
        </thead>
        <tbody id="instanceMgmtBody">
            {% for item in instances %}
            <tr data-subdomain="{{ item.subdomain }}">
                <td>{{ item.school_name }}</td>
                <td>{{ item.subdomain }}</td>
                <td>{{ item.status }} / {{ item.nginx_status }}</td>
                <td class="live-cell">RAM: - | CPU: -</td>
                <td>
                    <div class="actions row-actions">
                        <form method="post">
                            <input type="hidden" name="action" value="backup_instance">
                            <input type="hidden" name="subdomain" value="{{ item.subdomain }}">
                            <button type="submit">Backup</button>
                        </form>
                        <a class="action-link" href="{{ url_for('admin_export_instance_backup', subdomain=item.subdomain) }}">Slim-Backup exportieren</a>
                        <form method="post">
                            <input type="hidden" name="action" value="update_instance">
                            <input type="hidden" name="subdomain" value="{{ item.subdomain }}">
                            <button type="submit">Update</button>
                        </form>
                        <form method="post">
                            <input type="hidden" name="action" value="restart_instance">
                            <input type="hidden" name="subdomain" value="{{ item.subdomain }}">
                            <button type="submit">Restart</button>
                        </form>
                        <a class="action-link" href="{{ url_for('admin_download_instance_logs', subdomain=item.subdomain) }}">Logs</a>
                    </div>
                    <form method="post" action="{{ url_for('admin_import_instance_backup', subdomain=item.subdomain) }}" enctype="multipart/form-data" class="inline-restore-form">
                        <input type="file" name="backup_file" accept=".tar.gz,.tgz,application/gzip" required>
                        <button type="submit">Backup einspielen</button>
                    </form>
                    <form method="post" class="inline-admin-form">
                        <input type="hidden" name="action" value="create_instance_admin">
                        <input type="hidden" name="subdomain" value="{{ item.subdomain }}">
                        <input type="text" name="admin_username" placeholder="Admin-Username" required>
                        <input type="password" name="admin_password" placeholder="Passwort (>=8)" required>
                        <input type="text" name="admin_first_name" placeholder="Vorname" value="Admin">
                        <input type="text" name="admin_last_name" placeholder="Nachname" value="User">
                        <button type="submit">Admin erstellen</button>
                    </form>
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
    {% else %}
    <p>Keine Instanzen vorhanden.</p>
    {% endif %}
</section>

<style>
:root {
    --term-bg: #0b1114;
    --term-bg-soft: #0f181d;
    --term-border: #1f323a;
    --term-text: #d6f7d8;
    --term-muted: #8db49f;
    --term-accent: #5af78e;
    --term-accent-soft: #2fd06f;
    --term-warn: #f1c75b;
}

.head {
    margin-bottom: 1rem;
    background: radial-gradient(circle at top left, #12311f 0%, #0b1114 58%);
    border: 1px solid var(--term-border);
    border-radius: 12px;
    padding: 1rem;
}

.head h1,
.head p,
.panel h2,
.kpi-value,
.kpi-label,
.kv-grid dt,
.kv-grid dd,
th,
td,
button,
.action-link,
.inline-admin-form input {
    font-family: "JetBrains Mono", "Fira Code", "Consolas", monospace;
}

.head h1 {
    margin: 0;
    color: var(--term-accent);
    font-size: 1.34rem;
}

.head p {
    margin: 0.45rem 0 0;
    color: var(--term-muted);
}

.kpi-grid {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 0.65rem;
    margin-bottom: 1rem;
}
.kpi-card {
    border: 1px solid var(--term-border);
    background: linear-gradient(160deg, var(--term-bg) 0%, var(--term-bg-soft) 100%);
    border-radius: 12px;
    padding: 0.75rem;
    box-shadow: inset 0 0 0 1px rgba(90, 247, 142, 0.04);
}
.kpi-label {
    margin: 0;
    color: var(--term-muted);
    font-size: 0.82rem;
    font-weight: 600;
}
.kpi-value {
    margin: 0.28rem 0 0;
    font-size: 1.35rem;
    color: var(--term-accent);
    font-weight: 800;
}
.overview-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.8rem;
    margin-bottom: 1rem;
}
.charts-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.8rem;
    margin-bottom: 1rem;
}
.usage-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.8rem;
    margin-bottom: 1rem;
}
.panel {
    border: 1px solid var(--term-border);
    background: linear-gradient(180deg, #0f171b 0%, #0b1114 100%);
    border-radius: 14px;
    padding: 1rem;
    margin-bottom: 1rem;
}
.chart-panel {
    min-height: 235px;
}
.chart-panel canvas {
    width: 100% !important;
    height: 220px !important;
    display: block;
}
.panel h2 {
    margin: 0 0 0.65rem;
    color: var(--term-accent);
    font-size: 1rem;
}
.kv-grid {
    display: grid;
    grid-template-columns: 150px 1fr;
    gap: 0.35rem 0.55rem;
    margin: 0;
}
.kv-grid dt { color: var(--term-muted); font-weight: 600; }
.kv-grid dd { margin: 0; font-weight: 700; color: var(--term-text); }

.usage-panel {
    margin-bottom: 0;
}

.usage-row + .usage-row {
    margin-top: 0.7rem;
}

.usage-top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.3rem;
    color: var(--term-muted);
}

.usage-top strong {
    color: var(--term-accent);
}

.usage-bar {
    position: relative;
    height: 11px;
    border: 1px solid var(--term-border);
    border-radius: 999px;
    background: #0b1114;
    overflow: hidden;
}

.usage-bar > span {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 0%;
    background: linear-gradient(90deg, #2fa96e 0%, #63ff9a 100%);
    transition: width 0.25s ease;
}

.actions { display: flex; flex-wrap: wrap; gap: 0.55rem; align-items: center; }
.row-actions { gap: 0.4rem; }
.actions form { margin: 0; }
.logs-panel {
    margin-top: 0;
}
.logs-hint {
    margin-bottom: 0.6rem;
    color: var(--term-muted);
}
.logs-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin-bottom: 0.55rem;
}
.logs-toolbar label,
.logs-toolbar span {
    color: var(--term-muted);
    font-size: 0.85rem;
}
.logs-toolbar select {
    border: 1px solid var(--term-border);
    border-radius: 8px;
    background: #0b1114;
    color: var(--term-text);
    padding: 0.36rem 0.5rem;
    font-family: "JetBrains Mono", "Fira Code", "Consolas", monospace;
}
.log-output {
    margin: 0;
    border: 1px solid var(--term-border);
    border-radius: 10px;
    background: #05090b;
    color: #cbeed0;
    min-height: 260px;
    max-height: 520px;
    overflow: auto;
    padding: 0.72rem;
    font-size: 0.8rem;
    line-height: 1.45;
    white-space: pre-wrap;
    word-break: break-word;
}
.inline-admin-form {
    margin-top: 0.55rem;
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 0.38rem;
}
.inline-restore-form {
    margin-top: 0.55rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.38rem;
    align-items: center;
}
.inline-admin-form input {
    border: 1px solid var(--term-border);
    border-radius: 8px;
    padding: 0.38rem 0.5rem;
    font: inherit;
    min-width: 0;
    color: var(--term-text);
    background: #0b1114;
}
.inline-restore-form input[type="file"] {
    border: 1px solid var(--term-border);
    border-radius: 8px;
    padding: 0.35rem 0.45rem;
    color: var(--term-text);
    background: #0b1114;
}
button,
.action-link {
    border: 1px solid #2f6148;
    background: #0e2218;
    padding: 0.42rem 0.72rem;
    border-radius: 7px;
    font-weight: 700;
    cursor: pointer;
    text-decoration: none;
    color: var(--term-accent);
    display: inline-flex;
    align-items: center;
}
button:hover,
.action-link:hover { background: #133425; }
.live-cell { font-weight: 700; color: var(--term-warn); }
table { width: 100%; border-collapse: collapse; }
th, td {
    text-align: left;
    border-bottom: 1px solid #1f323a;
    padding: 0.62rem;
    vertical-align: top;
}
th {
    color: var(--term-muted);
    font-weight: 700;
}
td {
    color: var(--term-text);
}
@media (max-width: 1180px) {
    .kpi-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .overview-grid { grid-template-columns: 1fr; }
    .charts-grid { grid-template-columns: 1fr; }
}
@media (max-width: 860px) {
    .actions { display: grid; }
    .inline-admin-form { grid-template-columns: 1fr; }
    .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
</style>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
(function () {
    const mib = (value) => `${Number(value || 0).toFixed(1)} MiB`;
    const gib = (value) => `${Number(value || 0).toFixed(2)} GiB`;
    const pct = (value) => `${Number(value || 0).toFixed(1)} %`;
    const clampPct = (value) => Math.max(0, Math.min(100, Number(value || 0)));
    const historyLimit = 24;
    const liveLogsState = {
        sources: [],
        selected: ''
    };

    const history = {
        labels: [],
        hostRam: [],
        dockerManagedRam: [],
        hostCpu: [],
        avgInstanceCpu: [],
        load1: [],
        managedContainers: [],
        allContainers: []
    };

    const chartDefaults = {
        responsive: true,
        maintainAspectRatio: false,
        interaction: {
            mode: 'index',
            intersect: false
        },
        plugins: {
            legend: {
                position: 'bottom'
            }
        },
        scales: {
            x: {
                ticks: { maxRotation: 0, autoSkip: true }
            }
        }
    };

    const makeLineChart = (canvasId, datasets, yTitle) => {
        const el = document.getElementById(canvasId);
        if (!el || typeof Chart === 'undefined') {
            return null;
        }
        return new Chart(el, {
            type: 'line',
            data: {
                labels: history.labels,
                datasets
            },
            options: {
                ...chartDefaults,
                scales: {
                    ...chartDefaults.scales,
                    y: {
                        beginAtZero: true,
                        title: {
                            display: true,
                            text: yTitle
                        }
                    }
                }
            }
        });
    };

    const ramChart = makeLineChart('ramHistoryChart', [
        {
            label: 'Host RAM (MiB)',
            data: history.hostRam,
            borderColor: '#1f7a8c',
            backgroundColor: 'rgba(31,122,140,0.16)',
            tension: 0.25,
            fill: true
        },
        {
            label: 'Docker RAM Invario (MiB)',
            data: history.dockerManagedRam,
            borderColor: '#2a9d8f',
            backgroundColor: 'rgba(42,157,143,0.15)',
            tension: 0.25,
            fill: true
        }
    ], 'MiB');

    const cpuLoadChart = makeLineChart('cpuLoadHistoryChart', [
        {
            label: 'Host CPU (%)',
            data: history.hostCpu,
            borderColor: '#c16200',
            backgroundColor: 'rgba(193,98,0,0.15)',
            tension: 0.25,
            fill: true
        },
        {
            label: 'Instanzen CPU Mittel (%)',
            data: history.avgInstanceCpu,
            borderColor: '#355070',
            backgroundColor: 'rgba(53,80,112,0.15)',
            tension: 0.25,
            fill: true
        },
        {
            label: 'Load 1m',
            data: history.load1,
            borderColor: '#8a5a44',
            backgroundColor: 'rgba(138,90,68,0.13)',
            tension: 0.25,
            fill: true
        }
    ], 'Wert');

    const containerChart = makeLineChart('containerHistoryChart', [
        {
            label: 'Container (Invario)',
            data: history.managedContainers,
            borderColor: '#3f37c9',
            backgroundColor: 'rgba(63,55,201,0.15)',
            tension: 0.2,
            fill: true
        },
        {
            label: 'Container (alle)',
            data: history.allContainers,
            borderColor: '#6c757d',
            backgroundColor: 'rgba(108,117,125,0.13)',
            tension: 0.2,
            fill: true
        }
    ], 'Anzahl');

    const pushHistory = (data) => {
        const runtime = data.runtime || {};
        const host = runtime.host || {};
        const docker = runtime.docker || {};
        const sys = data.system || {};
        const instances = runtime.instances || [];
        const avgInstanceCpu = instances.length
            ? instances.reduce((sum, item) => sum + Number(item.cpu_percent || 0), 0) / instances.length
            : 0;

        const now = new Date();
        const timeLabel = now.toLocaleTimeString('de-DE', {
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit'
        });

        history.labels.push(timeLabel);
        history.hostRam.push(Number(host.used_mem_mib || 0));
        history.dockerManagedRam.push(Number(docker.managed_used_mem_mib || 0));
        history.hostCpu.push(Number(host.cpu_percent || 0));
        history.avgInstanceCpu.push(Number(avgInstanceCpu.toFixed(2)));
        history.load1.push(Number(sys.load_1 || 0));
        history.managedContainers.push(Number(docker.managed_container_count || 0));
        history.allContainers.push(Number(docker.all_container_count || 0));

        if (history.labels.length > historyLimit) {
            Object.keys(history).forEach((key) => {
                history[key].shift();
            });
        }

        [ramChart, cpuLoadChart, containerChart].forEach((chart) => {
            if (chart) {
                chart.update();
            }
        });
    };

    const setText = (id, value) => {
        const el = document.getElementById(id);
        if (el) {
            el.textContent = value;
        }
    };

    const setLiveLogSources = (sources) => {
        const select = document.getElementById('logSourceSelect');
        if (!select) {
            return;
        }

        const previous = liveLogsState.selected;
        select.innerHTML = '';

        (sources || []).forEach((source) => {
            const option = document.createElement('option');
            option.value = source.key;
            option.textContent = source.label;
            select.appendChild(option);
        });

        if (!sources || !sources.length) {
            liveLogsState.sources = [];
            liveLogsState.selected = '';
            return;
        }

        liveLogsState.sources = sources;
        const hasPrevious = sources.some((item) => item.key === previous);
        liveLogsState.selected = hasPrevious ? previous : sources[0].key;
        select.value = liveLogsState.selected;
    };

    const renderLiveLogs = () => {
        const output = document.getElementById('liveLogsOutput');
        const source = liveLogsState.sources.find((item) => item.key === liveLogsState.selected);
        if (!output) {
            return;
        }
        if (!source) {
            output.textContent = 'Keine Log-Quelle verfügbar.';
            return;
        }
        output.textContent = source.logs || 'Keine Ausgabe';
    };

    const updateLiveLogs = async () => {
        try {
            const response = await fetch('/admin/system/logs/live', { cache: 'no-store' });
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}`);
            }

            const data = await response.json();
            const sources = [];
            const core = data.core || {};
            sources.push({
                key: 'core',
                label: `Core Docker (${core.ok ? 'ok' : 'error'})`,
                logs: core.logs || 'Keine Ausgabe'
            });

            (data.services || []).forEach((service) => {
                const name = service.service || 'service';
                const status = service.status || 'unavailable';
                sources.push({
                    key: `svc:${name}`,
                    label: `${name} (${status})`,
                    logs: service.logs || 'Keine Ausgabe'
                });
            });

            setLiveLogSources(sources);
            setText('liveLogsUpdatedAt', `Stand: ${data.generated_at || '-'}`);
            renderLiveLogs();
        } catch (error) {
            setText('liveLogsUpdatedAt', 'Stand: Fehler beim Laden');
            const output = document.getElementById('liveLogsOutput');
            if (output) {
                output.textContent = 'Live-Logs konnten nicht geladen werden.';
            }
        }
    };

    const setUsageBar = (fillId, labelId, valuePct) => {
        const pctValue = clampPct(valuePct);
        const fill = document.getElementById(fillId);
        const label = document.getElementById(labelId);
        if (fill) {
            fill.style.width = `${pctValue.toFixed(1)}%`;
        }
        if (label) {
            label.textContent = `${pctValue.toFixed(1)} %`;
        }
    };

    const updateSystem = async () => {
        try {
            const response = await fetch('/admin/system/stats', { cache: 'no-store' });
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}`);
            }
            const data = await response.json();
            const runtime = data.runtime || {};
            const host = runtime.host || {};
            const docker = runtime.docker || {};
            const ops = data.ops || {};
            const rootDisk = data.root_disk || {};
            const instDisk = data.instance_disk || {};
            const sys = data.system || {};

            setText('kpiInstancesRunning', String((runtime.instances || []).filter(i => (i.status || '') === 'Läuft').length));
            setText('kpiTicketsOpen', String(ops.tickets_open || 0));
            setText('kpiAppointmentsPending', String(ops.appointments_pending || 0));
            setText('kpiUsersTotal', String(ops.users_total || 0));
            setText('kpiHostRam', mib(host.used_mem_mib));
            setText('kpiDockerManaged', mib(docker.managed_used_mem_mib));

            setText('sysUptime', `${Number(sys.uptime_seconds || 0).toFixed(0)} s`);
            setText('sysLoad', `${sys.load_1 || 0} / ${sys.load_5 || 0} / ${sys.load_15 || 0}`);
            setText('sysUpdatedAt', data.generated_at || '-');

            setText('rootUsed', gib(rootDisk.used_gib));
            setText('rootFree', gib(rootDisk.free_gib));
            setText('rootPct', pct(rootDisk.used_pct));

            setText('instUsed', gib(instDisk.used_gib));
            setText('instFree', gib(instDisk.free_gib));
            setText('instPct', pct(instDisk.used_pct));

            setUsageBar('usageHostRamFill', 'usageHostRamLabel', host.used_mem_pct);
            setUsageBar('usageHostCpuFill', 'usageHostCpuLabel', host.cpu_percent);
            setUsageBar('usageRootDiskFill', 'usageRootDiskLabel', rootDisk.used_pct);
            setUsageBar('usageInstDiskFill', 'usageInstDiskLabel', instDisk.used_pct);

            pushHistory(data);

            const bySubdomain = new Map((runtime.instances || []).map(item => [item.subdomain, item]));
            document.querySelectorAll('#instanceMgmtBody tr[data-subdomain]').forEach((row) => {
                const subdomain = row.getAttribute('data-subdomain') || '';
                const cell = row.querySelector('.live-cell');
                if (!cell) {
                    return;
                }
                const stats = bySubdomain.get(subdomain);
                if (!stats) {
                    cell.textContent = 'RAM: - | CPU: -';
                    return;
                }
                cell.textContent = `RAM: ${mib(stats.mem_mib)} | CPU: ${pct(stats.cpu_percent)}`;
            });
        } catch (error) {
            // Keep last values if refresh fails.
        }
    };

    updateSystem();
    window.setInterval(updateSystem, 15000);

    const logSourceSelect = document.getElementById('logSourceSelect');
    if (logSourceSelect) {
        logSourceSelect.addEventListener('change', (event) => {
            liveLogsState.selected = event.target.value || '';
            renderLiveLogs();
        });
    }

    const refreshLiveLogsBtn = document.getElementById('refreshLiveLogsBtn');
    if (refreshLiveLogsBtn) {
        refreshLiveLogsBtn.addEventListener('click', () => {
            updateLiveLogs();
        });
    }

    updateLiveLogs();
    window.setInterval(updateLiveLogs, 20000);
})();
</script>
{% endblock %}
