/* Eno.Health Console — primary views: Overview, Documents, Runs, Upload */
const E = window.ENO;

/* ======================================================================== */
/* OVERVIEW                                                                  */
/* ======================================================================== */
function OverviewView({ cell, onOpenDoc, goto, onSelectCell, onOpenDevice }) {
  const k = E.kpis(cell.id);
  const tp = useMemo(() => E.series(3, 28, 60, 14), []);
  const stageCounts = useMemo(() => {
    const map = { quarantine: 9, scanning: 14, promotion: 7, redaction: 23, ingest: 41 };
    return map;
  }, []);
  const services = E.SERVICES[cell.id];
  const attention = E.DOCUMENTS.filter((d) => d.statusKey === "failed" || d.stuck)
    .sort((a, b) => a.createdMin - b.createdMin);

  const pipeline = [
    { key: "upload", label: "Upload", count: 1842, tone: "neutral", icon: "upload" },
    { key: "quarantine", label: "Quarantine", count: stageCounts.quarantine, tone: "warn", icon: "lock" },
    { key: "scan", label: "Malware scan", count: stageCounts.scanning, tone: "info", icon: "scan" },
    { key: "promote", label: "Validate · MIME / size", count: stageCounts.promotion, tone: "info", icon: "database" },
    { key: "redact", label: "PII scrub", count: stageCounts.redaction, tone: "purple", icon: "shield" },
    { key: "ingest", label: "Handoff", count: stageCounts.ingest, tone: "ok", icon: "runs" },
    { key: "extract", label: "Extraction", future: true, tone: "neutral", icon: "database" },
  ];
  const [flow, setFlow] = useState("documents");
  const activeFlow = flow === "signals" ? E.SIGNAL_STAGES : pipeline;
  const flowMeta = flow === "signals"
    ? { title: "Signal pre-processing pipeline", sub: "Decode → unit normalization → range / plausibility checks → de-identification → time-series store. Continuous telemetry from wearables & smart devices.", foot: "Readings · per min · last 28 min" }
    : { title: "Pre-processing pipeline", sub: "Sanity & validation, malware scan, MIME / size gating, and PII scrubbing — before structured extraction. Later stages plug in here as they ship.", foot: "Throughput · docs/min · last 28 min" };

  return h("div", { className: "view" },
    h(PageHead, {
      title: "Pipeline overview",
      sub: `Document ingestion across cell ${cell.id} · ${cell.name}`,
      right: h(Pill, { tone: cell.status === "healthy" ? "ok" : cell.status === "degraded" ? "warn" : "bad" },
        cell.status === "healthy" ? "All systems operational" : cell.status === "degraded" ? "Degraded" : "Cell offline"),
    }),

    /* KPI row */
    h("div", { className: "stat-grid" },
      h(Card, { pad: false }, h(Stat, { label: "Ingested today", value: E.fmt ? "" : fmtNum(k.ingestedToday), spark: E.series(1, 16, 40, 10), tone: "ok", icon: "runs" })),
      h(Card, { pad: false }, h(Stat, { label: "In-flight now", value: fmtNum(k.inFlight), spark: E.series(5, 16, 30, 8), tone: "info", icon: "clock" })),
      h(Card, { pad: false }, h(Stat, { label: "Failed · 24h", value: fmtNum(k.failed24h), tone: "bad", delta: "needs triage", icon: "alert" })),
      h(Card, { pad: false }, h(Stat, { label: "Dead-letters", value: fmtNum(k.deadLetters), tone: k.deadLetters ? "bad" : "muted", delta: k.deadLetters ? "in outbox" : "clear", icon: "webhooks" })),
      h(Card, { pad: false }, h(Stat, { label: "End-to-end p95", value: k.p95, unit: "s", tone: "ok", icon: "activity" })),
      h(Card, { pad: false }, h(Stat, { label: "Redaction success", value: k.redactionRate, unit: "%", tone: "ok", icon: "shield" })),
    ),

    /* Pipeline flow */
    h(Card, { title: flowMeta.title, subtitle: flowMeta.sub,
      actions: h("div", { className: "flow-toggle" },
        h("button", { className: "flow-btn" + (flow === "documents" ? " on" : ""), onClick: () => setFlow("documents") }, "Documents"),
        h("button", { className: "flow-btn" + (flow === "signals" ? " on" : ""), onClick: () => setFlow("signals") }, "Signals")) },
      h("div", { className: "pipeflow" },
        activeFlow.map((p, i) => h(React.Fragment, { key: p.key },
          h("div", { className: "pipenode" + (p.future ? " future" : "") },
            h("div", { className: `pipeicon tone-${p.tone}` }, h(Icon, { name: p.icon, size: 18 })),
            p.future ? h("div", { className: "pipesoon" }, "soon") : h("div", { className: "pipecount" }, fmtNum(p.count)),
            h("div", { className: "pipelabel" }, p.label)),
          i < activeFlow.length - 1 && h("div", { className: "pipearrow" + (activeFlow[i + 1].future ? " future" : "") }, h(Icon, { name: "arrowRight", size: 16 }))))),
      h("div", { className: "pipefoot" },
        h(MiniBars, { data: tp, tone: "accent", height: 40 }),
        h("span", { className: "pipefoot-label" }, flowMeta.foot))),

    /* Cell network map */
    h(Card, { title: "Cell network", subtitle: "Regional cells and live status across jurisdictions",
      actions: h("div", { className: "cm-legend" },
        h("span", { className: "cm-leg" }, h("span", { className: "svc-dot svc-up" }), "Healthy"),
        h("span", { className: "cm-leg" }, h("span", { className: "svc-dot svc-stale" }), "Degraded"),
        h("span", { className: "cm-leg" }, h("span", { className: "svc-dot svc-down" }), "Down")) },
      h("div", { className: "cm-split" },
        h(CellMap, { active: cell.id, onSelect: onSelectCell }),
        h("div", { className: "cm-aside" },
          E.CELLS.map((c) => {
            const svcs = E.SERVICES[c.id];
            const up = svcs.filter((s) => s.up).length;
            const sd = c.status === "healthy" ? "up" : c.status === "degraded" ? "stale" : "down";
            const tone = c.status === "healthy" ? "ok" : c.status === "degraded" ? "warn" : "bad";
            const label = c.status === "healthy" ? "Operational" : c.status === "degraded" ? "Degraded" : "Offline";
            return h("button", { key: c.id, className: "cm-row" + (c.id === cell.id ? " on" : ""), onClick: () => onSelectCell(c.id) },
              h("span", { className: "cm-flag" }, c.flag),
              h("div", { className: "cm-row-main" },
                h("div", { className: "cm-row-id" }, h(Mono, null, c.id), c.id === cell.id && h("span", { className: "cm-active-tag" }, "viewing")),
                h("div", { className: "dim small" }, c.name, " · ", c.region, " · ", c.jurisdiction.toUpperCase())),
              h("span", { className: "cm-row-svc dim" }, up, "/", svcs.length),
              h(Pill, { tone, soft: true }, label));
          })))),

    h(FleetHealth, { onOpenDevice, goto }),

    h("div", { className: "split-2" },
      /* Cell health */
      h(Card, { title: "Cell health", subtitle: `${services.filter((s) => s.up).length}/${services.length} services reporting`,
        actions: h(Button, { variant: "ghost", size: "sm", icon: "refresh" }, "Refresh") },
        h("div", { className: "svc-list" },
          services.map((s) => h("div", { className: "svc-row", key: s.name },
            h("span", { className: `svc-dot svc-${s.status}` }),
            h("span", { className: "svc-name mono" }, s.name),
            h("span", { className: "svc-meta" }, s.up ? `${s.p95}ms p95` : s.status === "stale" ? "stale scrape" : "no scrape"),
            h("span", { className: "svc-meta dim" }, s.up ? `${s.freshness}s` : "—"),
            h(Pill, { tone: s.status === "up" ? "ok" : s.status === "stale" ? "warn" : "bad", soft: true },
              s.status === "up" ? "up" : s.status))))),

      /* Needs attention */
      h(Card, { title: "Needs attention", subtitle: "Failed or stuck documents in this cell",
        actions: h(Button, { variant: "ghost", size: "sm", onClick: () => goto("documents") }, "All documents") },
        attention.length ? h("div", { className: "attn-list" },
          attention.map((d) => h("button", { className: "attn-row", key: d.id, onClick: () => onOpenDoc(d) },
            h("div", { className: `attn-icon tone-${d.status.tone}` }, h(Icon, { name: d.stuck ? "clock" : "alert", size: 15 })),
            h("div", { className: "attn-main" },
              h("div", { className: "attn-file" }, d.file),
              h("div", { className: "attn-sub" }, E.tenantName(d.tenant), " · ", d.failReason ? d.failReason.slice(0, 46) + "…" : "awaiting redaction worker")),
            h(StatusPill, { status: d.status }),
            h("span", { className: "attn-age" }, fmtAgo(d.createdAt)))))
          : h(Empty, { icon: "check", title: "No failures", sub: "Everything is flowing cleanly." }))));
}

/* ======================================================================== */
/* DOCUMENTS                                                                 */
/* ======================================================================== */
const STATUS_FILTERS = [
  { value: "all", label: "All statuses" },
  { value: "scanning", label: "Scanning" },
  { value: "redacting", label: "Redacting" },
  { value: "redaction_pending", label: "Redaction queued" },
  { value: "validated", label: "Validated" },
  { value: "redacted", label: "Redacted" },
  { value: "ingested", label: "Ingested" },
  { value: "failed", label: "Failed" },
  { value: "expired", label: "Expired" },
];

function DocumentsView({ cell, onOpenDoc }) {
  const [status, setStatus] = useState("all");
  const [tenant, setTenant] = useState("all");
  const [q, setQ] = useState("");

  const rows = E.DOCUMENTS.filter((d) => {
    if (status !== "all" && d.statusKey !== status) return false;
    if (tenant !== "all" && d.tenant !== tenant) return false;
    if (q && !(d.id + d.file + d.patient + d.correlationId).toLowerCase().includes(q.toLowerCase())) return false;
    return true;
  });

  return h("div", { className: "view" },
    h(PageHead, { title: "Documents", sub: "Search, inspect, and debug any document in the pipeline" }),
    h(Card, { pad: false },
      h("div", { className: "toolbar" },
        h("div", { className: "search" },
          h(Icon, { name: "search", size: 16 }),
          h("input", { className: "search-input", placeholder: "Search document ID, file, patient, correlation…", value: q, onChange: (e) => setQ(e.target.value) })),
        h(Select, { value: status, onChange: setStatus, options: STATUS_FILTERS }),
        h(Select, { value: tenant, onChange: setTenant, options: [{ value: "all", label: "All tenants" }, ...E.TENANTS.map((t) => ({ value: t.id, label: t.name }))] }),
        h("span", { className: "toolbar-count" }, rows.length, " of ", E.DOCUMENTS.length)),
      h("div", { className: "table-wrap" },
        h("table", { className: "table" },
          h("thead", null, h("tr", null,
            ["Document", "Tenant", "Status", "Lifecycle", "Cell", "Size", "Age", ""].map((c, i) =>
              h("th", { key: i, className: i >= 5 && i <= 6 ? "ta-r" : "" }, c)))),
          h("tbody", null,
            rows.map((d) => h(DocRow, { key: d.id, d, onClick: () => onOpenDoc(d) })),
            !rows.length && h("tr", null, h("td", { colSpan: 8 }, h(Empty, { title: "No documents match", sub: "Try clearing filters." }))))
        )
      )
    )
  );
}

function DocRow({ d, onClick }) {
  const reached = E.stageIndex(d.stage);
  const failed = !!d.failedAt;
  return h("tr", { className: "row-click", onClick },
    h("td", null,
      h("div", { className: "cell-doc" },
        h("span", { className: "cell-file" }, d.file),
        h(Mono, { className: "cell-id" }, d.id))),
    h("td", null, h("span", { className: "cell-tenant" }, E.tenantName(d.tenant))),
    h("td", null, h(StatusPill, { status: d.status })),
    h("td", null, h(LifecycleBar, { reached, failed, total: E.STAGES_LEN })),
    h("td", null, h(Mono, null, d.tenant && E.tenantCell(d.tenant))),
    h("td", { className: "ta-r mono" }, fmtBytes(d.size)),
    h("td", { className: "ta-r dim" }, fmtAgo(d.createdAt)),
    h("td", null, h(Icon, { name: "chevronR", size: 15, className: "row-arrow" })));
}

function LifecycleBar({ reached, failed, total }) {
  const pct = Math.round(((reached + 1) / total) * 100);
  return h("div", { className: "lifebar", title: `${reached + 1}/${total} stages` },
    h("div", { className: "lifebar-track" },
      h("div", { className: "lifebar-fill", style: { width: pct + "%", background: failed ? "var(--bad)" : pct === 100 ? "var(--ok)" : "var(--info)" } })),
    h("span", { className: "lifebar-pct" }, failed ? "halted" : pct + "%"));
}

/* ---- Document drill-down drawer ----------------------------------------- */
function DocumentDrawer({ doc, onClose }) {
  const [tab, setTab] = useState("timeline");
  const toast = useToast();
  const [holds, setHolds] = useState({});
  useEffect(() => { setTab("timeline"); }, [doc && doc.id]);
  if (!doc) return null;
  const legalHold = holds[doc.id] != null ? holds[doc.id] : doc.retention.legalHold;

  const act = (msg) => toast(msg);
  const footer = h("div", { className: "drawer-actions" },
    h(Button, { variant: "ghost", size: "sm", icon: "copy", onClick: () => { navigator.clipboard?.writeText(doc.id); act("Document ID copied"); } }, "Copy ID"),
    doc.outbox.some((e) => e.status === "dead_letter") &&
      h(Button, { variant: "default", size: "sm", icon: "refresh", onClick: () => act("Replay queued for dead-letter event") }, "Replay outbox"),
    h(Button, { variant: legalHold ? "danger-ghost" : "ghost", size: "sm", icon: "lock",
      onClick: () => { setHolds((x) => ({ ...x, [doc.id]: !legalHold })); act(legalHold ? "Legal hold released" : "Legal hold placed"); } },
      legalHold ? "Release hold" : "Place legal hold"),
    h(Button, { variant: "danger", size: "sm", icon: "trash", onClick: () => act("Erasure request recorded (GDPR Art. 17)") }, "Request erasure"));

  const tabs = [
    { key: "timeline", label: "Lifecycle" },
    { key: "audit", label: "Audit", count: doc.timeline.length },
    { key: "redaction", label: "Redaction", count: doc.redaction ? doc.redaction.spans : null },
    { key: "outbox", label: "Outbox / Kafka", count: doc.outbox.length },
    { key: "meta", label: "Metadata" },
  ];

  return h(Drawer, {
    open: true, onClose, width: 760, footer,
    title: doc.file,
    sub: h("div", { className: "drawer-subline" },
      h(Mono, { copy: true }, doc.id), h(StatusPill, { status: doc.status }),
      legalHold && h(Pill, { tone: "warn" }, "Legal hold")),
  },
    h(Tabs, { tabs, active: tab, onChange: setTab }),
    h("div", { className: "drawer-tabbody" },
      tab === "timeline" && h(TimelineTab, { doc }),
      tab === "audit" && h(AuditTab, { doc }),
      tab === "redaction" && h(RedactionTab, { doc }),
      tab === "outbox" && h(OutboxTab, { doc, act }),
      tab === "meta" && h(MetaTab, { doc })));
}

function TimelineTab({ doc }) {
  return h("div", { className: "timeline" },
    doc.timeline.map((t, i) => h("div", { className: "tl-row", key: i },
      h("div", { className: `tl-marker tl-${t.state}` },
        h(Icon, { name: t.state === "failed" ? "x" : t.state === "active" ? "dot" : "check", size: 13 })),
      h("div", { className: "tl-main" },
        h("div", { className: "tl-label" }, t.label,
          h("span", { className: "tl-service mono" }, t.service)),
        h("div", { className: "tl-time" }, fmtTime(t.at), " · ", fmtAgo(t.at)),
        t.note && h("div", { className: "tl-note" }, h(Icon, { name: "alert", size: 13 }), t.note)),
      i < doc.timeline.length - 1 && h("div", { className: "tl-line" }))),
    doc.stuck && h("div", { className: "tl-hint" }, h(Icon, { name: "clock", size: 14 }), "Document has been awaiting the redaction worker longer than expected — check ", h(Mono, null, "redaction-worker"), " health."));
}

function AuditTab({ doc }) {
  const head = ["Event", "Stage", "Producer", "Status", "Occurred"];
  const rows = doc.timeline.map((t, i) => h("tr", { key: i },
    h("td", null, h(Mono, null, "document." + t.key)),
    h("td", null, t.label),
    h("td", null, h(Mono, { className: "dim" }, t.service)),
    h("td", null, h(Pill, { tone: t.state === "failed" ? "bad" : "ok", soft: true }, t.state === "failed" ? "error" : "ok")),
    h("td", { className: "dim" }, fmtTime(t.at))));
  return h("div", null,
    h("div", { className: "audit-banner" }, h(Icon, { name: "shield", size: 14 }), "Append-only · immutable · 10-year retention (MDR + GDPR Art. 30)"),
    h("div", { className: "table-wrap flush" },
      h("table", { className: "table table-tight" },
        h("thead", null, h("tr", null, head.map((c) => h("th", { key: c }, c)))),
        h("tbody", null, rows))));
}

function RedactionTab({ doc }) {
  const r = doc.redaction;
  if (!r) return h(Empty, { icon: "shield", title: "No redaction job", sub: "This document has not reached the PHI/PII gate yet." });
  return h("div", { className: "redaction" },
    h("div", { className: "rdx-head" },
      h("div", null, h("div", { className: "rdx-job mono" }, r.jobId),
        h("div", { className: "rdx-policy" }, "Policy ", h(Mono, null, r.policyVersion), " · consumer ", h(Mono, null, r.consumer), " · strategy ", h(Mono, null, r.strategy))),
      h(Pill, { tone: r.status === "completed" ? "ok" : r.status === "failed" ? "bad" : "purple" }, r.status)),
    h("div", { className: "engine-grid" },
      r.requiredEngines.map((e) => {
        const ok = r.completedEngines.includes(e);
        const failed = r.failedEngines.includes(e);
        return h("div", { className: "engine", key: e },
          h("span", { className: `svc-dot svc-${failed ? "down" : ok ? "up" : "stale"}` }),
          h("span", { className: "engine-name mono" }, e),
          h("span", { className: "engine-state" }, failed ? "failed" : ok ? "passed" : "pending"));
      })),
    r.status === "failed"
      ? h("div", { className: "rdx-fail" }, h(Icon, { name: "alert", size: 15 }), "Fail-closed: ", doc.failReason)
      : h("div", null,
          h("div", { className: "rdx-spans" }, h("strong", null, r.spans), " PHI/PII spans detected and ", r.strategy, "d"),
          h("div", { className: "entity-grid" },
            Object.entries(r.entityCounts).filter(([, v]) => v > 0).map(([k, v]) =>
              h("div", { className: "entity", key: k },
                h("span", { className: "entity-type mono" }, k),
                h("span", { className: "entity-count" }, v))))));
}

function OutboxTab({ doc, act }) {
  const head = ["Event type", "Topic / target", "Status", "Attempts", "At", ""];
  const rows = doc.outbox.map((e, i) => h("tr", { key: i },
    h("td", null, h(Mono, null, e.type)),
    h("td", null, h(Mono, { className: "dim" }, e.topic)),
    h("td", null, h(Pill, { tone: e.status === "published" ? "ok" : e.status === "dead_letter" ? "bad" : "warn", soft: true }, e.status.replace("_", "-"))),
    h("td", { className: "ta-c mono" }, e.attempts),
    h("td", { className: "dim" }, fmtTime(e.at)),
    h("td", null, (e.status === "dead_letter" || e.status === "retrying") &&
      h(Button, { variant: "ghost", size: "sm", onClick: () => act("Replay requested for " + e.type) }, "Replay"))));
  return h("div", null,
    h("div", { className: "table-wrap flush" },
      h("table", { className: "table table-tight" },
        h("thead", null, h("tr", null, head.map((c) => h("th", { key: c }, c)))),
        h("tbody", null, rows))),
    h("div", { className: "sql-hint" },
      h("span", null, "Document-scoped triage SQL"),
      h(Mono, { copy: true, className: "sql" }, `SELECT * FROM outbox_events WHERE payload_document_id = '${doc.id}' ORDER BY created_at;`)));
}

function MetaTab({ doc }) {
  const rows = [
    ["Document ID", doc.id, true], ["Correlation ID", doc.correlationId, true],
    ["Tenant", E.tenantName(doc.tenant) + " (" + doc.tenant + ")"], ["Patient", doc.patient + " (anonymized)"],
    ["Initiated by", doc.user], ["Cell", E.tenantCell(doc.tenant)],
    ["Declared type", doc.mime], ["Size", fmtBytes(doc.size)],
    ["SHA-256", doc.sha256 + "…", true], ["Object state", doc.objectState],
    ["Retention policy", doc.retention.policy], ["Retention basis", doc.retention.basis],
    ["Legal hold", doc.retention.legalHold ? "Yes" : "No"],
    ["Created", fmtTime(doc.createdAt) + " · " + fmtDate(doc.createdAt)],
  ];
  return h("div", { className: "meta-grid" },
    rows.map(([k, v, mono], i) => h("div", { className: "meta-row", key: i },
      h("span", { className: "meta-k" }, k),
      h("span", { className: "meta-v" }, mono ? h(Mono, { copy: true }, v) : v))));
}

/* ======================================================================== */
/* INGESTION RUNS (live / SSE simulation)                                    */
/* ======================================================================== */
function RunsView({ cell, onOpenDoc }) {
  const [feed, setFeed] = useState([]);
  const [paused, setPaused] = useState(false);
  const liveRun = E.RUNS.find((r) => r.status === "live");

  useEffect(() => {
    if (paused) return;
    const samples = [
      ["doc_8f3ac21b", "ingest.start.v1", "ok"], ["doc_5c0d77e9", "document.redacting", "purple"],
      ["doc_1a99be40", "document.status.v1", "info"], ["doc_e7710b54", "document.redacting", "purple"],
      ["doc_3d2e6a55", "document.redacted", "ok"], ["doc_4f8a1c63", "redact.document.v1 retry", "warn"],
      ["doc_b401ff7c", "scan_clean", "info"], ["doc_9c34d771", "document.validated", "info"],
    ];
    const id = setInterval(() => {
      const s = samples[Math.floor(Math.random() * samples.length)];
      setFeed((f) => [{ id: Math.random().toString(36).slice(2), doc: s[0], ev: s[1], tone: s[2], at: new Date() }, ...f].slice(0, 14));
    }, 1400);
    return () => clearInterval(id);
  }, [paused]);

  return h("div", { className: "view" },
    h(PageHead, { title: "Ingestion runs", sub: "Batch and streaming ingestion runs with live event streams" }),
    h("div", { className: "split-runs" },
      h("div", { className: "runs-col" },
        E.RUNS.map((r) => h(RunCard, { key: r.id, run: r, onOpenDoc }))),
      h(Card, { className: "live-card", title: "Live event stream",
        subtitle: liveRun ? `SSE · /v1/ingestion-runs/${liveRun.id}/events` : "no live run",
        actions: h(Button, { variant: "ghost", size: "sm", icon: paused ? "play" : "pause", onClick: () => setPaused((p) => !p) }, paused ? "Resume" : "Pause") },
        h("div", { className: "sse-feed" },
          feed.length === 0 && h("div", { className: "sse-wait" }, h(Icon, { name: "spinner", size: 16, className: "spin" }), "Waiting for events…"),
          feed.map((f) => h("div", { className: "sse-row", key: f.id },
            h("span", { className: "sse-time mono" }, fmtTime(f.at)),
            h("span", { className: `sse-tone tone-${f.tone}` }),
            h(Mono, { className: "sse-ev" }, f.ev),
            h(Mono, { className: "sse-doc dim" }, f.doc)))))));
}

function RunCard({ run, onOpenDoc }) {
  const [open, setOpen] = useState(run.status === "live");
  const a = run.agg;
  const docs = E.DOCUMENTS.filter((d) => d.run === run.id);
  return h(Card, { pad: false, className: "run-card" },
    h("button", { className: "run-head", onClick: () => setOpen((o) => !o) },
      h(Icon, { name: open ? "chevron" : "chevronR", size: 15, className: "run-chev" }),
      h("div", { className: "run-id" },
        h("span", { className: "run-label" }, run.label),
        h(Mono, { className: "dim" }, run.id, " · ", E.tenantName(run.tenant))),
      h("div", { className: "run-stats" },
        h("span", { className: "run-stat" }, h("strong", null, a.done), " done"),
        a.inFlight > 0 && h("span", { className: "run-stat info" }, h("strong", null, a.inFlight), " in-flight"),
        a.failed > 0 && h("span", { className: "run-stat bad" }, h("strong", null, a.failed), " failed")),
      run.status === "live" ? h(Pill, { tone: "info" }, "live") : h(Pill, { tone: "ok", soft: true }, "completed")),
    h("div", { className: "run-progress" },
      h(Bar, { height: 6, segments: [
        { value: a.done, tone: "ok", label: "done" },
        { value: a.inFlight, tone: "info", label: "in-flight" },
        { value: a.failed, tone: "bad", label: "failed" },
      ] })),
    open && h("div", { className: "run-docs" },
      docs.map((d) => h("button", { className: "run-doc", key: d.id, onClick: () => onOpenDoc(d) },
        h("span", { className: "run-doc-file" }, d.file),
        h(StatusPill, { status: d.status }),
        h("span", { className: "run-doc-age dim" }, fmtAgo(d.createdAt)))),
      !docs.length && h("div", { className: "run-empty dim" }, "No documents recorded for this run in mock data.")));
}

/* ======================================================================== */
/* UPLOAD                                                                     */
/* ======================================================================== */
function UploadView({ cell }) {
  const toast = useToast();
  const [tenant, setTenant] = useState(E.TENANTS[0].id);
  const users = E.USERS.filter((u) => u.tenant === tenant);
  const [user, setUser] = useState(users[0] ? users[0].id : "");
  const [patient, setPatient] = useState("");
  const [file, setFile] = useState(null);
  const [drag, setDrag] = useState(false);
  const [jobs, setJobs] = useState([]);
  const fileRef = useRef();

  useEffect(() => { const u = E.USERS.filter((x) => x.tenant === tenant); setUser(u[0] ? u[0].id : ""); }, [tenant]);

  const pick = (f) => { if (!f) return; setFile({ name: f.name, size: f.size || Math.round(200000 + Math.random() * 4000000), type: f.type || "application/pdf" }); };

  const STEPS = ["Initiate", "Presigned PUT", "Quarantine", "Scan", "Promote", "Redact", "Ingest"];
  const submit = () => {
    if (!file) { toast("Choose a file first", "bad"); return; }
    const jid = "doc_" + Math.random().toString(16).slice(2, 10);
    const job = { id: jid, file: file.name, tenant, user, patient: patient || "pt_" + Math.random().toString(16).slice(2, 6), step: 0, done: false, failed: false };
    setJobs((j) => [job, ...j]);
    toast("Upload initiated · " + jid);
    let step = 0;
    const adv = () => {
      step++;
      setJobs((js) => js.map((x) => x.id === jid ? { ...x, step, done: step >= STEPS.length } : x));
      if (step < STEPS.length) setTimeout(adv, 750 + Math.random() * 700);
      else toast("Document ingested · " + jid, "ok");
    };
    setTimeout(adv, 700);
    setFile(null); setPatient("");
  };

  return h("div", { className: "view" },
    h(PageHead, { title: "Upload documents", sub: "Initiate an ingestion on behalf of a tenant user — the same path the public API drives" }),
    h("div", { className: "split-upload" },
      h(Card, { title: "New upload" },
        h("div", { className: "upload-form" },
          h(Field, { label: "Tenant" }, h(Select, { value: tenant, onChange: setTenant, options: E.TENANTS.map((t) => ({ value: t.id, label: t.name })) })),
          h(Field, { label: "On behalf of user" }, h(Select, { value: user, onChange: setUser, options: users.map((u) => ({ value: u.id, label: u.name + " · " + u.role })) })),
          h(Field, { label: "Patient reference", hint: "Pseudonymous — never a real identifier" },
            h("input", { className: "input", placeholder: "pt_… (blank to auto-generate)", value: patient, onChange: (e) => setPatient(e.target.value) })),
          h("div", {
            className: "dropzone" + (drag ? " drag" : "") + (file ? " filled" : ""),
            onDragOver: (e) => { e.preventDefault(); setDrag(true); },
            onDragLeave: () => setDrag(false),
            onDrop: (e) => { e.preventDefault(); setDrag(false); pick(e.dataTransfer.files[0]); },
            onClick: () => fileRef.current.click(),
          },
            h("input", { ref: fileRef, type: "file", hidden: true, onChange: (e) => pick(e.target.files[0]) }),
            file
              ? h("div", { className: "dz-file" }, h(Icon, { name: "documents", size: 20 }),
                  h("div", null, h("div", { className: "dz-name" }, file.name), h("div", { className: "dz-size dim" }, fmtBytes(file.size), " · ", file.type)))
              : h("div", { className: "dz-empty" }, h(Icon, { name: "upload", size: 22 }),
                  h("div", null, h("strong", null, "Drop a file"), " or click to browse"),
                  h("div", { className: "dim" }, "PDF, PNG, JPEG, HEIC, TIFF, TXT, JSON, DOCX"))),
          h(Button, { variant: "primary", icon: "upload", onClick: submit }, "Initiate ingestion"),
          h("div", { className: "upload-note" }, h(Icon, { name: "shield", size: 13 }), "Bytes upload directly to the cell-local quarantine bucket via presigned URL — never proxied through the API tier.")),
      ),
      h(Card, { title: "Recent uploads", subtitle: "Live progress through the DIP-1 pipeline" },
        jobs.length === 0
          ? h(Empty, { icon: "upload", title: "No uploads yet", sub: "Submitted uploads will stream their progress here." })
          : h("div", { className: "job-list" }, jobs.map((j) => h(UploadJob, { key: j.id, job: j, steps: STEPS }))))));
}

function UploadJob({ job, steps }) {
  return h("div", { className: "job" },
    h("div", { className: "job-head" },
      h("span", { className: "job-file" }, job.file),
      h(Mono, { className: "dim" }, job.id),
      job.done ? h(Pill, { tone: "ok" }, "ingested") : h(Pill, { tone: "info" }, steps[Math.min(job.step, steps.length - 1)])),
    h("div", { className: "job-steps" },
      steps.map((s, i) => h("div", { className: "job-step" + (i < job.step ? " done" : i === job.step ? " active" : ""), key: s },
        h("span", { className: "job-dot" }, i < job.step ? h(Icon, { name: "check", size: 11 }) : i === job.step ? h(Icon, { name: "spinner", size: 11, className: "spin" }) : null),
        h("span", { className: "job-step-label" }, s)))));
}

/* ---- Geographic cell map ------------------------------------------------- */
function CellMap({ active, onSelect }) {
  const box = { lonMin: -12, lonMax: 62, latMin: 18, latMax: 58 };
  const proj = (c) => ({
    x: ((c.lon - box.lonMin) / (box.lonMax - box.lonMin)) * 100,
    y: ((box.latMax - c.lat) / (box.latMax - box.latMin)) * 100,
  });
  const dir = { "eu-be": "sw", "eu-nl": "ne", "eu-de": "ne", "ae-du": "nw" };
  return h("div", { className: "cellmap" },
    h("div", { className: "cm-grid" }),
    h("span", { className: "cm-region", style: { left: "21%", top: "5%" } }, "EU West"),
    h("span", { className: "cm-region", style: { left: "40%", top: "4%" } }, "EU Central"),
    h("span", { className: "cm-region", style: { left: "80%", top: "92%" } }, "Middle East"),
    E.CELLS.map((c) => {
      const p = proj(c);
      const st = c.status === "healthy" ? "up" : c.status === "degraded" ? "stale" : "down";
      return h("button", {
        key: c.id, className: "cm-marker cm-" + st + (c.id === active ? " on" : ""),
        style: { left: p.x + "%", top: p.y + "%" }, onClick: () => onSelect(c.id), title: c.name,
      },
        h("span", { className: "cm-pulse" }),
        h("span", { className: "cm-pin" }),
        h("span", { className: "cm-label cm-" + dir[c.id] }, c.flag, " ", h(Mono, null, c.id)));
    }));
}

/* ---- Device fleet health (overview widget) ------------------------------ */
function FleetHealth({ onOpenDevice, goto }) {
  const k = E.streamKpis();
  const byStatus = {};
  E.DEVICES.forEach((d) => (byStatus[d.status] = (byStatus[d.status] || 0) + 1));
  const segs = [
    { key: "connected", tone: "ok", label: "Connected" },
    { key: "syncing", tone: "info", label: "Syncing" },
    { key: "stale", tone: "warn", label: "Stale" },
    { key: "token_expired", tone: "warn", label: "Token expired" },
    { key: "disconnected", tone: "bad", label: "Disconnected" },
  ].map((s) => ({ ...s, value: byStatus[s.key] || 0 })).filter((s) => s.value > 0);
  const attention = E.DEVICES.filter((d) => ["stale", "token_expired", "disconnected"].includes(d.status));
  return h(Card, { title: "Device fleet health", subtitle: `${k.activeDevices} of ${k.totalDevices} devices streaming`,
    actions: h(Button, { variant: "ghost", size: "sm", icon: "external", onClick: () => goto("streams") }, "Streams") },
    h("div", { className: "fleet-split" },
      h("div", { className: "fleet-left" },
        h("div", { className: "fleet-readings" },
          h("div", null, h("div", { className: "fleet-big" }, fmtNum(k.readingsPerMin)), h("div", { className: "dim small" }, "readings / min")),
          h(Sparkline, { data: E.series(4, 18, 30, 9), tone: "info", height: 42 })),
        h("div", { className: "fleet-dist" },
          h(Bar, { height: 9, segments: segs }),
          h("div", { className: "fleet-legend" },
            segs.map((s) => h("span", { className: "fleet-leg", key: s.key },
              h("span", { className: "fleet-dot", style: { background: `var(--${s.tone})` } }),
              s.label, h("strong", null, s.value)))))),
      h("div", { className: "fleet-attn" },
        h("div", { className: "fleet-attn-head" }, "Needs attention", h("span", { className: "fleet-attn-count" }, attention.length)),
        attention.length
          ? h("div", { className: "fleet-attn-list" }, attention.map((d) => {
              const st = E.DEVICE_STATUS[d.status];
              return h("button", { className: "fleet-row", key: d.id, onClick: () => onOpenDevice(d) },
                h("span", { className: `svc-dot svc-${st.dot}` }),
                h("div", { className: "fleet-row-main" },
                  h("div", { className: "fleet-row-model" }, d.model),
                  h("div", { className: "dim small" }, E.sourceName(d.source), " · ", E.tenantName(d.tenant))),
                h(Pill, { tone: st.tone, soft: true }, st.label),
                h("span", { className: "dim small fleet-row-age" }, fmtAgo(d.lastSync)));
            }))
          : h(Empty, { icon: "check", title: "All devices healthy", sub: "Every connected device is streaming cleanly." }))));
}

/* ---- shared page header -------------------------------------------------- */
function PageHead({ title, sub, right }) {
  return h("div", { className: "pagehead" },
    h("div", null, h("h1", { className: "page-title" }, title), sub && h("p", { className: "page-sub" }, sub)),
    right && h("div", { className: "pagehead-right" }, right));
}

Object.assign(window, { OverviewView, DocumentsView, RunsView, UploadView, PageHead, DocumentDrawer });
