{% extends "base.html" %}

{% block title %}SFM Admin - Seismo Fleet Manager{% endblock %}

{% block content %}
<div class="mb-8 flex items-center justify-between">
    <div>
        <a href="/settings#developer" class="text-sm text-seismo-orange hover:text-seismo-burgundy">← Back to Developer Tools</a>
        <h1 class="text-3xl font-bold text-gray-900 dark:text-white mt-1">SFM Admin</h1>
        <p class="text-gray-600 dark:text-gray-400 mt-1">Diagnostics for the Seismograph Field Module (SFM) backend.</p>
    </div>
    <button onclick="loadSfmOverview()"
            class="px-4 py-2 bg-seismo-orange hover:bg-orange-600 text-white text-sm font-medium rounded-lg">
        <span id="refresh-label">↻ Refresh</span>
    </button>
</div>

<!-- Health Banner -->
<div id="health-banner" class="rounded-xl p-4 mb-6 bg-gray-100 dark:bg-slate-800 border border-gray-200 dark:border-gray-700">
    <p class="text-sm text-gray-500 dark:text-gray-400">Loading SFM status…</p>
</div>

<!-- Connection Info -->
<div class="rounded-xl bg-white dark:bg-slate-800 shadow-lg p-4 mb-6">
    <h2 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider mb-2">Connection</h2>
    <div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
        <div>
            <span class="text-gray-500 dark:text-gray-400">terra-view → SFM URL</span>
            <div class="font-mono text-gray-900 dark:text-white mt-0.5">{{ sfm_base_url }}</div>
        </div>
        <div>
            <span class="text-gray-500 dark:text-gray-400">Last checked</span>
            <div class="font-mono text-gray-900 dark:text-white mt-0.5" id="checked-at">—</div>
        </div>
        <div>
            <span class="text-gray-500 dark:text-gray-400">Version</span>
            <div class="font-mono text-gray-900 dark:text-white mt-0.5" id="sfm-version">—</div>
        </div>
    </div>
</div>

<!-- Stats Grid -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
    <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-4">
        <div class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Known Units</div>
        <div class="text-2xl font-bold text-gray-900 dark:text-white mt-1" id="stat-units">—</div>
    </div>
    <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-4">
        <div class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Total Events</div>
        <div class="text-2xl font-bold text-gray-900 dark:text-white mt-1" id="stat-events">—</div>
    </div>
    <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-4">
        <div class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider" title="Rows in SFM's deprecated monitor_log table (from paused Python-ACH experiment)">Stale: monitor_log</div>
        <div class="text-2xl font-bold text-gray-400 dark:text-gray-500 mt-1" id="stat-stale-monitor">—</div>
    </div>
    <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-4">
        <div class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider" title="Rows in SFM's deprecated ach_sessions table (from paused Python-ACH experiment)">Stale: ach_sessions</div>
        <div class="text-2xl font-bold text-gray-400 dark:text-gray-500 mt-1" id="stat-stale-sessions">—</div>
    </div>
</div>

<!-- Units Table -->
<div class="rounded-xl bg-white dark:bg-slate-800 shadow-lg p-4 mb-6">
    <h2 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider mb-3">Per-Unit Roll-up</h2>
    <p class="text-xs text-gray-500 dark:text-gray-400 mb-3">All seismograph serials SFM has ever seen, with their last-event timestamp and total event count.  Sourced from <code class="font-mono">GET /db/units</code>.</p>
    <div class="overflow-x-auto">
        <table class="w-full text-left text-sm">
            <thead class="bg-gray-50 dark:bg-slate-700">
                <tr>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase">Serial</th>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase">Last Seen</th>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase text-right">Events</th>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase text-right">Monitor (stale)</th>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase text-right">Sessions (stale)</th>
                </tr>
            </thead>
            <tbody id="units-tbody" class="divide-y divide-gray-200 dark:divide-gray-700">
                <tr><td colspan="5" class="px-3 py-6 text-center text-gray-500">Loading…</td></tr>
            </tbody>
        </table>
    </div>
</div>

<!-- Recent Events with Latency -->
<div class="rounded-xl bg-white dark:bg-slate-800 shadow-lg p-4 mb-6">
    <h2 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider mb-3">Recent Events — Forwarding Latency</h2>
    <p class="text-xs text-gray-500 dark:text-gray-400 mb-3">The last 25 events SFM ingested, with the gap between the event's recorded timestamp and when SFM received the forward.  Large latencies indicate the watcher is forwarding stale files (e.g. after a network outage).</p>
    <div class="overflow-x-auto">
        <table class="w-full text-left text-sm">
            <thead class="bg-gray-50 dark:bg-slate-700">
                <tr>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase">Recorded</th>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase">Serial</th>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase">Forwarded</th>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase">Latency</th>
                    <th class="px-3 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 uppercase">File</th>
                </tr>
            </thead>
            <tbody id="events-tbody" class="divide-y divide-gray-200 dark:divide-gray-700">
                <tr><td colspan="5" class="px-3 py-6 text-center text-gray-500">Loading…</td></tr>
            </tbody>
        </table>
    </div>
</div>

<!-- Raw API tester -->
<div class="rounded-xl bg-white dark:bg-slate-800 shadow-lg p-4 mb-6">
    <h2 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider mb-3">Raw API Tester</h2>
    <p class="text-xs text-gray-500 dark:text-gray-400 mb-3">Send a GET request to any SFM endpoint via the terra-view <code class="font-mono">/api/sfm/*</code> proxy.  Path is relative to SFM root (no leading slash).</p>
    <div class="flex gap-2 mb-3">
        <span class="px-3 py-2 text-sm bg-gray-100 dark:bg-slate-700 text-gray-700 dark:text-gray-300 font-mono rounded-l-lg">/api/sfm/</span>
        <input id="raw-path" type="text" placeholder="db/units" value="db/units"
               class="flex-1 px-3 py-2 text-sm bg-white dark:bg-slate-900 text-gray-900 dark:text-white border border-gray-300 dark:border-gray-600 rounded font-mono"
               onkeydown="if(event.key==='Enter') sendRaw();">
        <button onclick="sendRaw()"
                class="px-4 py-2 bg-seismo-orange hover:bg-orange-600 text-white text-sm rounded-lg">
            GET
        </button>
    </div>
    <pre id="raw-response" class="bg-gray-900 dark:bg-black text-gray-200 font-mono text-xs p-3 rounded-lg max-h-96 overflow-auto whitespace-pre hidden"></pre>
</div>

<script>
function _fmtAge(seconds) {
    if (seconds == null) return '—';
    const abs = Math.abs(seconds);
    if (abs < 60) return seconds.toFixed(0) + 's';
    if (abs < 3600) return (seconds / 60).toFixed(1) + 'm';
    if (abs < 86400) return (seconds / 3600).toFixed(1) + 'h';
    return (seconds / 86400).toFixed(1) + 'd';
}

function _latencyClass(seconds) {
    if (seconds == null) return 'text-gray-400';
    if (seconds < 600) return 'text-green-600 dark:text-green-400';        // <10 min
    if (seconds < 3600) return 'text-amber-600 dark:text-amber-400';       // <1 hr
    return 'text-red-600 dark:text-red-400 font-semibold';                  // 1hr+
}

function _esc(s) {
    if (s == null) return '';
    return String(s).replace(/&/g, '&amp;')
                    .replace(/</g, '&lt;')
                    .replace(/>/g, '&gt;')
                    .replace(/"/g, '&quot;');
}

async function loadSfmOverview() {
    const lbl = document.getElementById('refresh-label');
    lbl.textContent = '↻ Loading…';
    try {
        const r = await fetch('/api/admin/sfm/overview');
        if (!r.ok) throw new Error('HTTP ' + r.status);
        const d = await r.json();
        renderOverview(d);
    } catch (e) {
        document.getElementById('health-banner').innerHTML = `
            <div class="text-red-600 dark:text-red-400 text-sm font-medium">
                Failed to load SFM overview: ${_esc(e.message)}
            </div>`;
    } finally {
        lbl.textContent = '↻ Refresh';
    }
}

function renderOverview(d) {
    // Banner
    const banner = document.getElementById('health-banner');
    if (d.reachable) {
        banner.className = 'rounded-xl p-4 mb-6 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800';
        banner.innerHTML = `
            <div class="flex items-center gap-3">
                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                <div>
                    <div class="font-semibold text-green-800 dark:text-green-300">SFM reachable</div>
                    <div class="text-xs text-green-700 dark:text-green-400">${_esc(d.health?.service || 'sfm')} v${_esc(d.health?.version || '?')}</div>
                </div>
            </div>`;
    } else {
        banner.className = 'rounded-xl p-4 mb-6 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800';
        const errs = Object.entries(d.errors || {}).map(([k, v]) => `${k}: ${v}`).join('; ');
        banner.innerHTML = `
            <div class="flex items-center gap-3">
                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                <div>
                    <div class="font-semibold text-red-800 dark:text-red-300">SFM unreachable</div>
                    <div class="text-xs text-red-700 dark:text-red-400">${_esc(errs || 'no details')}</div>
                </div>
            </div>`;
    }

    // Header info
    document.getElementById('checked-at').textContent = d.checked_at ? d.checked_at.slice(0, 19).replace('T', ' ') : '—';
    document.getElementById('sfm-version').textContent = d.health?.version || '—';

    // Stats
    const t = d.totals || {};
    document.getElementById('stat-units').textContent  = (t.units ?? 0).toLocaleString();
    document.getElementById('stat-events').textContent = (t.events_total ?? 0).toLocaleString();
    document.getElementById('stat-stale-monitor').textContent  = t.stale_monitor_log != null ? t.stale_monitor_log.toLocaleString() : '—';
    document.getElementById('stat-stale-sessions').textContent = t.stale_sessions != null ? t.stale_sessions.toLocaleString() : '—';

    // Units table
    const unitsBody = document.getElementById('units-tbody');
    if (!d.units || d.units.length === 0) {
        unitsBody.innerHTML = `<tr><td colspan="5" class="px-3 py-6 text-center text-gray-500">No units in SFM yet.</td></tr>`;
    } else {
        const sorted = [...d.units].sort((a, b) => (b.last_seen || '').localeCompare(a.last_seen || ''));
        unitsBody.innerHTML = sorted.map(u => {
            const ls = u.last_seen ? u.last_seen.replace('T', ' ').slice(0, 19) : '—';
            return `<tr class="hover:bg-gray-50 dark:hover:bg-slate-700/50">
                <td class="px-3 py-2 font-mono text-seismo-orange"><a href="/unit/${encodeURIComponent(u.serial)}" class="hover:underline">${_esc(u.serial)}</a></td>
                <td class="px-3 py-2 text-gray-900 dark:text-gray-200">${_esc(ls)}</td>
                <td class="px-3 py-2 text-right text-gray-900 dark:text-gray-200">${(u.total_events || 0).toLocaleString()}</td>
                <td class="px-3 py-2 text-right text-gray-500">${(u.total_monitor_entries || 0).toLocaleString()}</td>
                <td class="px-3 py-2 text-right text-gray-500">${(u.total_sessions || 0).toLocaleString()}</td>
            </tr>`;
        }).join('');
    }

    // Events table
    const evBody = document.getElementById('events-tbody');
    if (!d.events || d.events.length === 0) {
        evBody.innerHTML = `<tr><td colspan="5" class="px-3 py-6 text-center text-gray-500">No events.</td></tr>`;
    } else {
        evBody.innerHTML = d.events.map(ev => {
            const ts = ev.timestamp ? ev.timestamp.replace('T', ' ').slice(0, 19) : '—';
            const ca = ev.created_at ? ev.created_at.replace('T', ' ').slice(0, 19) : '—';
            const lat = ev.forwarding_latency_seconds;
            return `<tr class="hover:bg-gray-50 dark:hover:bg-slate-700/50">
                <td class="px-3 py-2 text-gray-900 dark:text-gray-200 whitespace-nowrap">${_esc(ts)}</td>
                <td class="px-3 py-2 font-mono text-seismo-orange">${_esc(ev.serial)}</td>
                <td class="px-3 py-2 text-gray-600 dark:text-gray-400 whitespace-nowrap">${_esc(ca)}</td>
                <td class="px-3 py-2 font-mono ${_latencyClass(lat)}">${_fmtAge(lat)}</td>
                <td class="px-3 py-2 font-mono text-xs text-gray-500 dark:text-gray-400">${_esc(ev.blastware_filename || '—')}</td>
            </tr>`;
        }).join('');
    }
}

async function sendRaw() {
    const path = document.getElementById('raw-path').value.trim().replace(/^\//, '');
    if (!path) return;
    const pre = document.getElementById('raw-response');
    pre.classList.remove('hidden');
    pre.textContent = 'Loading…';
    try {
        const r = await fetch('/api/sfm/' + path);
        const text = await r.text();
        try {
            const j = JSON.parse(text);
            pre.textContent = `HTTP ${r.status}\n\n${JSON.stringify(j, null, 2)}`;
        } catch {
            pre.textContent = `HTTP ${r.status}\n\n${text.slice(0, 8000)}`;
        }
    } catch (e) {
        pre.textContent = 'Error: ' + e.message;
    }
}

loadSfmOverview();
setInterval(loadSfmOverview, 30000);
</script>
{% endblock %}
