/* public/js/siteHealth.js — live "site health" badge
 *
 * Renders a colored dot somewhere on the page (typically the topbar).
 * Polls /health every 30s. Colors:
 *   green  = ok
 *   yellow = degraded (a worker is down or keys exhausted)
 *   red    = db or process down
 *
 * Usage — drop these into any page you want a dot on:
 *
 *   <span id="siteHealthDot" class="site-health-dot" title="checking…"></span>
 *   <script src="/public/js/siteHealth.js" defer></script>
 *
 * The dot auto-updates its color, tooltip (uptime + last tick age + db status),
 * and stays in sync without reloading. Clicks open a small popover with
 * full worker + key health.
 */

(function () {
  'use strict';
  const POLL_MS = 30 * 1000;

  function fmtAge(ms) {
    if (ms == null) return '—';
    const s = Math.floor(ms / 1000);
    if (s < 60) return s + 's ago';
    if (s < 3600) return Math.floor(s / 60) + 'm ago';
    return Math.floor(s / 3600) + 'h ago';
  }

  function dot() {
    return document.getElementById('siteHealthDot');
  }

  function render(snap) {
    const el = dot();
    if (!el) return;
    if (!snap) { el.className = 'site-health-dot unknown'; el.title = 'Health check failed — see /health'; return; }
    const status = snap.status || 'unknown';
    const workers = snap.workers || {};
    const failedWorker = Object.entries(workers).filter(([k, v]) => v === 'failed').map(([k]) => k);
    const runningCount = Object.values(workers).filter(v => v === 'running' || v === 'unknown').length;
    const totalWorkers = Object.keys(workers).length;

    el.className = 'site-health-dot ' + (status === 'ok' ? 'ok' : status === 'degraded' ? 'warn' : 'danger');
    const uptimeH = snap.uptime_seconds ? Math.floor(snap.uptime_seconds / 3600) : 0;
    const parts = [
      'Status: ' + status,
      'DB: ' + (snap.db || '?'),
      'Uptime: ' + uptimeH + 'h',
      'Workers: ' + runningCount + '/' + totalWorkers + ' running',
    ];
    if (failedWorker.length) parts.push('FAILED: ' + failedWorker.join(', '));
    el.title = parts.join(' · ');
    el.dataset.status = status;
    el.dataset.snapshot = JSON.stringify(snap);
  }

  async function tick() {
    try {
      const r = await fetch('/health', { cache: 'no-store', credentials: 'same-origin' });
      if (!r.ok) { render(null); return; }
      render(await r.json());
    } catch (_) {
      render(null);
    }
  }

  function attachClick() {
    const el = dot();
    if (!el) return;
    el.style.cursor = 'help';
    el.addEventListener('click', () => {
      let snap;
      try { snap = JSON.parse(el.dataset.snapshot || 'null'); } catch (_) { snap = null; }
      if (!snap) { alert('No health data yet.'); return; }
      const lines = [
        'Status: ' + snap.status,
        'DB: ' + snap.db,
        'Uptime: ' + (snap.uptime_seconds || 0) + 's',
        'Workers:',
        ...Object.entries(snap.workers || {}).map(([k, v]) => '  ' + k + ': ' + v),
        'API keys:',
        ...Object.entries(snap.keys || {}).map(([k, v]) => '  ' + k + ': ' + (v.active || 0) + '/' + (v.total || 0) + ' active'),
      ];
      alert(lines.join('\n'));
    });
  }

  function start() {
    if (!dot()) return;       // not on this page; nothing to do
    attachClick();
    tick();
    setInterval(tick, POLL_MS);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', start);
  } else {
    start();
  }
})();