// System & Maintenance — the operations plane that mirrors the Hermes Agent
// dashboard's System page: a Status snapshot (version / gateway state / config /
// sessions + per-platform health), Host stats (OS, CPU, memory meter), Gateway
// lifecycle controls (restart / start / stop), one-shot Maintenance ops (doctor,
// security audit, dump, update check) with their raw JSON results, and the
// Curator schedule (run-now + pause/resume). Wired to the dashboard config plane
// via /dash/* (HERMES.dashStatus / systemStats / sessionsStats / curator + the
// gateway/ops/curator mutations), with a graceful empty state when offline.
const { useState, useEffect, useCallback } = React;

// ---- formatting helpers ----
// ISO-string -> short relative ("3m ago"). last_run_at / updated_at are ISO.
function relTime(iso) {
  if (!iso) return "never";
  const t = Date.parse(iso);
  if (isNaN(t)) return String(iso);
  const s = Math.max(0, (Date.now() - t) / 1000);
  if (s < 45) return "just now";
  if (s < 3600) return Math.floor(s / 60) + "m ago";
  if (s < 86400) return Math.floor(s / 3600) + "h ago";
  if (s < 2592000) return Math.floor(s / 86400) + "d ago";
  return Math.floor(s / 2592000) + "mo ago";
}
// bytes -> GB string (1 decimal). 1e9 base to match the dashboard's reporting.
function gb(bytes) {
  return ((Number(bytes) || 0) / 1e9).toFixed(1);
}
// Compact human label for a gateway/platform state -> status-dot class.
function stateClass(state) {
  const s = (state || "").toLowerCase();
  if (s === "running" || s === "healthy" || s === "ok" || s === "connected" || s === "up") return "running";
  if (s === "starting" || s === "provisioning" || s === "degraded" || s === "warn") return "warn";
  return "err";
}
// status-dot class -> .badge tone class (the badge dot reuses the same palette).
function badgeTone(state) {
  const c = stateClass(state);
  return c === "running" ? "ok" : c === "warn" ? "warn" : "bad";
}

function PageSystem({ toast }) {
  const [status, setStatus] = useState(null);    // dashStatus()
  const [sys, setSys] = useState(null);          // systemStats()
  const [sess, setSess] = useState(null);        // sessionsStats()
  const [cur, setCur] = useState(null);          // curator()
  const [live, setLive] = useState(null);        // null=loading, true=backend, false=offline
  const [busy, setBusy] = useState(false);       // gateway/curator mutation in flight
  const [results, setResults] = useState({});    // { doctor|audit|dump|update: <result> }
  const [running, setRunning] = useState("");     // which maintenance op is running

  const load = useCallback(async () => {
    let anyLive = false;
    try { setStatus(await HERMES.dashStatus()); anyLive = true; } catch { setStatus(null); }
    try { setSys(await HERMES.systemStats()); anyLive = true; } catch { setSys(null); }
    try { setSess(await HERMES.sessionsStats()); anyLive = true; } catch { setSess(null); }
    try { setCur(await HERMES.curator()); anyLive = true; } catch { setCur(null); }
    setLive(anyLive);
  }, []);

  useEffect(() => { load(); }, [load]);

  // Gateway lifecycle. `verb` confirms first (destructive ones), then runs the
  // matching HERMES method, toasts the outcome, and reloads the snapshot.
  const gatewayAction = useCallback(async (kind) => {
    if (kind !== "start" && !window.confirm(`${kind === "stop" ? "Stop" : "Restart"} the gateway? Active sessions may be interrupted.`)) return;
    const fn = kind === "restart" ? HERMES.gatewayRestart : kind === "start" ? HERMES.gatewayStart : HERMES.gatewayStop;
    setBusy(true);
    try {
      const r = await fn();
      if (r && r.ok === false) { toast(r.detail || r.error || `Gateway ${kind} failed`); }
      else { toast(`Gateway ${kind === "restart" ? "restarted" : kind === "start" ? "started" : "stopped"}`); }
      await load();
    } catch (e) { toast(e.message || `Gateway ${kind} failed`); }
    setBusy(false);
  }, [load, toast]);

  // One-shot maintenance op. Stores the returned payload (truncated) under `key`.
  const runOp = useCallback(async (key, fn, label) => {
    setRunning(key);
    try {
      const r = await fn();
      let text;
      try { text = JSON.stringify(r, null, 2); } catch { text = String(r); }
      if (text.length > 4000) text = text.slice(0, 4000) + "\n… (truncated)";
      setResults((prev) => ({ ...prev, [key]: text }));
      toast(`${label} complete`);
    } catch (e) {
      setResults((prev) => ({ ...prev, [key]: "Error: " + (e.message || "failed") }));
      toast(e.message || `${label} failed`);
    }
    setRunning("");
  }, [toast]);

  // Curator: run now (re-fetch after) and pause/resume toggle.
  const curatorRun = useCallback(async () => {
    setBusy(true);
    try { await HERMES.curatorRun(); toast("Curator run triggered"); await load(); }
    catch (e) { toast(e.message || "Curator run failed"); }
    setBusy(false);
  }, [load, toast]);

  const curatorToggle = useCallback(async (paused) => {
    setBusy(true);
    try { await HERMES.curatorPaused(paused); toast(paused ? "Curator paused" : "Curator resumed"); await load(); }
    catch (e) { toast(e.message || "Could not update curator"); }
    setBusy(false);
  }, [load, toast]);

  // ---- derived ----
  const version = (status && (status.version || status.hermes_version)) || (sys && sys.hermes_version) || "—";
  const gwRunning = !!(status && status.gateway_running);
  const gwState = (status && status.gateway_state) || (gwRunning ? "running" : "stopped");
  const gwPid = status && status.gateway_pid;
  const configVer = status && status.config_version;
  const latestConfigVer = status && status.latest_config_version;
  const configBehind = configVer != null && latestConfigVer != null && Number(latestConfigVer) > Number(configVer);
  const platforms = (status && status.gateway_platforms) || {};
  const platformIds = Object.keys(platforms);
  const sessTotal = sess && sess.total;
  const mem = (sys && sys.memory) || null;

  return (
    <div className="page">
      <PageHead eyebrow="Workspace" title="System" sub="Status, host stats, gateway controls, and maintenance for Hermes Agent.">
        {live === true && <span className="badge ok"><span className="d" />live</span>}
        {live === false && <span className="badge warn"><span className="d" />preview</span>}
        {live === null && <span className="badge"><span className="d" />loading…</span>}
        <button className="btn btn-ghost" onClick={load}><Icon name="refresh" size={16} />Refresh</button>
      </PageHead>

      {/* ---- Status ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Status</h2>
            <p>Hermes version, gateway state, config revision, and session totals.</p>
          </div>
        </div>

        <div className="grid cols-4" style={{ marginBottom: platformIds.length ? 16 : 0 }}>
          <div className="stat card" style={{ gap: 6 }}>
            <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Hermes version</div>
            <div className="mono" style={{ fontSize: 18, fontWeight: 700 }}>{version}</div>
            {status && status.release_date && <div className="faint mono" style={{ fontSize: 11.5 }}>released {status.release_date}</div>}
          </div>
          <div className="stat card" style={{ gap: 6 }}>
            <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Gateway</div>
            <div className="flex" style={{ gap: 8, alignItems: "center" }}>
              <span className={cls("status-dot", stateClass(gwState), gwRunning && "live")} />
              <span style={{ fontSize: 17, fontWeight: 650, textTransform: "capitalize" }}>{gwState}</span>
            </div>
            {gwPid ? <div className="faint mono" style={{ fontSize: 11.5 }}>pid {gwPid}</div> : null}
          </div>
          <div className="stat card" style={{ gap: 6 }}>
            <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Config version</div>
            <div className="mono" style={{ fontSize: 18, fontWeight: 700 }}>{configVer != null ? configVer : "—"}</div>
            {configBehind
              ? <span className="badge warn" style={{ alignSelf: "flex-start" }}><span className="d" />update available · v{latestConfigVer}</span>
              : (latestConfigVer != null ? <div className="faint mono" style={{ fontSize: 11.5 }}>up to date</div> : null)}
          </div>
          <div className="stat card" style={{ gap: 6 }}>
            <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Sessions</div>
            <div style={{ fontSize: 24, fontWeight: 700 }}>{sessTotal != null ? sessTotal : "—"}</div>
            {sess && (sess.active_store != null || sess.archived != null) &&
              <div className="faint mono" style={{ fontSize: 11.5 }}>{sess.active_store ?? 0} active · {sess.archived ?? 0} archived</div>}
          </div>
        </div>

        {platformIds.length > 0 && (
          <>
            <div className="flex between" style={{ marginBottom: 8 }}>
              <span className="section-title">Gateway platforms</span>
              <span className="faint mono" style={{ fontSize: 12 }}>{platformIds.length}</span>
            </div>
            <div className="rows">
              {platformIds.map((id) => {
                const p = platforms[id] || {};
                return (
                  <div className="row" key={id} style={{ cursor: "default" }}>
                    <span className="glyph"><span className={cls("status-dot", stateClass(p.state))} /></span>
                    <div className="row-main">
                      <b style={{ fontSize: 14, textTransform: "capitalize" }}>{id}</b>
                      <div className="row-sub mono">
                        <span>{p.error_message ? p.error_message : (p.updated_at ? `updated ${relTime(p.updated_at)}` : "—")}</span>
                      </div>
                    </div>
                    <span className={cls("badge", badgeTone(p.state))}><span className="d" />{p.state || "unknown"}</span>
                  </div>
                );
              })}
            </div>
          </>
        )}
      </div>

      {/* ---- Host ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Host</h2>
            <p>Operating system, runtime, and live memory utilization for the machine running Hermes.</p>
          </div>
        </div>
        {!sys ? (
          <div className="empty">System stats unavailable — the dashboard is offline.</div>
        ) : (
          <>
            <div className="rows" style={{ marginBottom: mem ? 16 : 0 }}>
              <div className="row" style={{ cursor: "default" }}>
                <span className="glyph"><Icon name="operations" size={15} /></span>
                <div className="row-main">
                  <b style={{ fontSize: 14 }}>Operating system</b>
                  <div className="row-sub mono"><span>{[sys.os, sys.os_release].filter(Boolean).join(" ") || "—"} · {sys.arch || "—"}</span></div>
                </div>
              </div>
              <div className="row" style={{ cursor: "default" }}>
                <span className="glyph"><Icon name="terminal" size={15} /></span>
                <div className="row-main">
                  <b style={{ fontSize: 14 }}>Hostname</b>
                  <div className="row-sub mono"><span>{sys.hostname || "—"}</span></div>
                </div>
              </div>
              <div className="row" style={{ cursor: "default" }}>
                <span className="glyph"><Icon name="rocket" size={15} /></span>
                <div className="row-main">
                  <b style={{ fontSize: 14 }}>Python</b>
                  <div className="row-sub mono"><span>{sys.python_version || "—"}</span></div>
                </div>
              </div>
              <div className="row" style={{ cursor: "default" }}>
                <span className="glyph"><Icon name="cpu" size={15} /></span>
                <div className="row-main">
                  <b style={{ fontSize: 14 }}>CPU</b>
                  <div className="row-sub mono"><span>{sys.cpu_count != null ? `${sys.cpu_count} core${sys.cpu_count === 1 ? "" : "s"}` : "—"}</span></div>
                </div>
              </div>
            </div>

            {mem && (
              <div style={{ padding: "14px 16px", border: "1px solid var(--line)", borderRadius: 10, background: "var(--surface-2)" }}>
                <div className="flex between" style={{ marginBottom: 10, alignItems: "baseline" }}>
                  <span className="flex" style={{ gap: 8, alignItems: "center" }}>
                    <Icon name="memory" size={15} />
                    <span className="section-title" style={{ margin: 0 }}>Memory</span>
                  </span>
                  <span className="faint mono" style={{ fontSize: 12 }}>
                    {gb(mem.used)} / {gb(mem.total)} GB · {Math.round(Number(mem.percent) || 0)}%
                  </span>
                </div>
                <Meter value={Math.max(0, Math.min(100, Number(mem.percent) || 0)) / 100} tone={(Number(mem.percent) || 0) > 90 ? "bad" : (Number(mem.percent) || 0) > 75 ? "warn" : ""} />
                {mem.available != null && <div className="faint mono" style={{ fontSize: 11.5, marginTop: 8 }}>{gb(mem.available)} GB available</div>}
              </div>
            )}
          </>
        )}
      </div>

      {/* ---- Gateway controls ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Gateway controls</h2>
            <p>Restart, start, or stop the Hermes gateway process. Stop and restart interrupt active sessions.</p>
          </div>
          <span className={cls("badge", gwRunning ? "ok" : "bad")}><span className="d" />{gwRunning ? "running" : "stopped"}</span>
        </div>
        <div className="flex" style={{ gap: 8, flexWrap: "wrap" }}>
          <button className="btn btn-primary" disabled={busy} onClick={() => gatewayAction("restart")}>
            <Icon name="refresh" size={15} />Restart
          </button>
          <button className="btn btn-subtle" disabled={busy || gwRunning} onClick={() => gatewayAction("start")}>
            <Icon name="play" size={15} />Start
          </button>
          <button className="btn btn-danger" disabled={busy || !gwRunning} onClick={() => gatewayAction("stop")}>
            <Icon name="x" size={15} />Stop
          </button>
          {busy && <span className="faint mono" style={{ fontSize: 12, alignSelf: "center" }}>working…</span>}
        </div>
      </div>

      {/* ---- Maintenance ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Maintenance</h2>
            <p>Run one-shot diagnostics and updates. Each shows its raw result below.</p>
          </div>
        </div>
        <div className="flex" style={{ gap: 8, flexWrap: "wrap", marginBottom: 4 }}>
          <button className="btn btn-subtle" disabled={!!running} onClick={() => runOp("doctor", HERMES.opsDoctor, "Doctor")}>
            <Icon name="activity" size={15} />{running === "doctor" ? "Running…" : "Run Doctor"}
          </button>
          <button className="btn btn-subtle" disabled={!!running} onClick={() => runOp("audit", HERMES.opsSecurityAudit, "Security audit")}>
            <Icon name="lock" size={15} />{running === "audit" ? "Running…" : "Security Audit"}
          </button>
          <button className="btn btn-subtle" disabled={!!running} onClick={() => runOp("dump", HERMES.opsDump, "Dump")}>
            <Icon name="file" size={15} />{running === "dump" ? "Running…" : "Dump"}
          </button>
          <button className="btn btn-subtle" disabled={!!running} onClick={() => runOp("update", HERMES.updateCheck, "Update check")}>
            <Icon name="rocket" size={15} />{running === "update" ? "Checking…" : "Check for updates"}
          </button>
        </div>

        {["doctor", "audit", "dump", "update"].map((key) => {
          const text = results[key];
          if (!text) return null;
          const label = key === "doctor" ? "Doctor" : key === "audit" ? "Security audit" : key === "dump" ? "Dump" : "Update check";
          return (
            <div key={key} style={{ marginTop: 12 }}>
              <div className="flex between" style={{ marginBottom: 6 }}>
                <span className="section-title">{label} result</span>
                <button className="icon-btn" title="Clear" onClick={() => setResults((p) => { const n = { ...p }; delete n[key]; return n; })}>
                  <Icon name="x" size={14} />
                </button>
              </div>
              <pre className="mono" style={{ margin: 0, padding: "12px 14px", border: "1px solid var(--line)", borderRadius: 10, background: "var(--surface-2)", fontSize: 12, lineHeight: 1.55, color: "var(--muted)", maxHeight: 320, overflow: "auto", whiteSpace: "pre-wrap", wordBreak: "break-word" }}>
                {text}
              </pre>
            </div>
          );
        })}
      </div>

      {/* ---- Curator ---- */}
      <div className="card">
        <div className="card-head">
          <div>
            <h2>Curator</h2>
            <p>Scheduled memory & skills maintenance — prunes stale items and archives idle sessions.</p>
          </div>
          {cur && (
            cur.paused
              ? <span className="badge warn"><span className="d" />paused</span>
              : cur.enabled
                ? <span className="badge ok"><span className="d" />enabled</span>
                : <span className="badge"><span className="d" />disabled</span>
          )}
        </div>
        {!cur ? (
          <div className="empty">Curator status unavailable — the dashboard is offline.</div>
        ) : (
          <>
            <div className="grid cols-3" style={{ marginBottom: 16 }}>
              <div className="stat card" style={{ gap: 6 }}>
                <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Last run</div>
                <div style={{ fontSize: 16, fontWeight: 650 }}>{relTime(cur.last_run_at)}</div>
              </div>
              <div className="stat card" style={{ gap: 6 }}>
                <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Interval</div>
                <div style={{ fontSize: 16, fontWeight: 650 }}>{cur.interval_hours != null ? `${cur.interval_hours}h` : "—"}</div>
              </div>
              <div className="stat card" style={{ gap: 6 }}>
                <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Thresholds</div>
                <div className="faint mono" style={{ fontSize: 11.5, lineHeight: 1.55 }}>
                  {cur.min_idle_hours != null ? <div>idle ≥ {cur.min_idle_hours}h</div> : null}
                  {cur.stale_after_days != null ? <div>stale ≥ {cur.stale_after_days}d</div> : null}
                  {cur.archive_after_days != null ? <div>archive ≥ {cur.archive_after_days}d</div> : null}
                  {(cur.min_idle_hours == null && cur.stale_after_days == null && cur.archive_after_days == null) ? "—" : null}
                </div>
              </div>
            </div>
            <div className="flex" style={{ gap: 8, flexWrap: "wrap" }}>
              <button className="btn btn-primary" disabled={busy} onClick={curatorRun}>
                <Icon name="play" size={15} />Run now
              </button>
              <button className="btn btn-ghost" disabled={busy} onClick={() => curatorToggle(!cur.paused)}>
                <Icon name={cur.paused ? "play" : "clock"} size={15} />{cur.paused ? "Resume" : "Pause"}
              </button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}
window.PageSystem = PageSystem;
