/* Eno.Health Console — governance views: Policies, Retention, Webhooks, Tenants */
const G = window.ENO;

/* ======================================================================== */
/* POLICIES                                                                  */
/* ======================================================================== */
function PoliciesView() {
  const [tab, setTab] = useState("doctype");
  const tabs = [
    { key: "doctype", label: "Document types", count: G.DOC_TYPE_POLICIES.length },
    { key: "quotas", label: "Tenant quotas", count: G.QUOTA_POLICIES.length },
    { key: "redaction", label: "Redaction", count: G.REDACTION_POLICIES.length },
  ];
  return h("div", { className: "view" },
    h(PageHead, { title: "Policies", sub: "Govern what the pipeline accepts, how much, and how it scrubs PHI/PII" }),
    h(Tabs, { tabs, active: tab, onChange: setTab }),
    h("div", { className: "tabbody" },
      tab === "doctype" && h(DocTypePolicies, null),
      tab === "quotas" && h(QuotaPolicies, null),
      tab === "redaction" && h(RedactionPolicies, null)));
}

function DocTypePolicies() {
  const toast = useToast();
  const [rows, setRows] = useState(G.DOC_TYPE_POLICIES);
  const toggle = (mime) => {
    setRows((r) => r.map((p) => p.mime === mime ? { ...p, enabled: !p.enabled } : p));
    toast("Policy updated · " + mime);
  };
  const head = ["MIME type", "Extensions", "Max size", "Sniff", "Profile", "Scope", "Enabled"];
  const body = rows.map((p) => h("tr", { key: p.mime },
    h("td", null, h(Mono, null, p.mime)),
    h("td", null, h("span", { className: "tags" }, p.ext.split(", ").map((e) => h("span", { className: "tag", key: e }, "." + e)))),
    h("td", { className: "mono" }, p.maxMB, " MB"),
    h("td", null, p.sniff ? h(Pill, { tone: "ok", soft: true }, "strict") : h(Pill, { tone: "neutral", soft: true }, "off")),
    h("td", null, h(Mono, { className: "dim" }, p.profile)),
    h("td", null, p.tenant ? h(Mono, null, G.tenantName(p.tenant)) : h("span", { className: "dim" }, "global")),
    h("td", null, h(Toggle, { on: p.enabled, onChange: () => toggle(p.mime) }))));
  return h(Card, { pad: false, title: "Document type policies",
    subtitle: "MIME allow-list, size caps and content-sniff enforcement",
    actions: h(Button, { variant: "primary", size: "sm", icon: "plus", onClick: () => toast("New policy form (mock)") }, "New policy") },
    h("div", { className: "table-wrap flush" },
      h("table", { className: "table" },
        h("thead", null, h("tr", null, head.map((c) => h("th", { key: c }, c)))),
        h("tbody", null, body))));
}

function QuotaPolicies() {
  const toast = useToast();
  return h("div", { className: "quota-grid" },
    G.QUOTA_POLICIES.map((q) => h(Card, { key: q.scope + q.key, className: "quota-card",
      title: q.scope === "tier" ? "Tier · " + q.tier : G.tenantName(q.key),
      subtitle: q.scope === "tier" ? "Applies to all " + q.tier + " tenants" : "Tenant override · " + q.tier + " tier",
      actions: h(Button, { variant: "ghost", size: "sm", icon: "external", onClick: () => toast("Edit quota (mock)") }, "Edit") },
      h("div", { className: "quota-rows" },
        h(QuotaRow, { label: "Daily documents", used: q.used.dailyDocs, limit: q.dailyDocs, unit: "" }),
        h(QuotaRow, { label: "Monthly volume", used: q.used.monthlyGB, limit: q.monthlyGB, unit: " GB" }),
        h(QuotaRow, { label: "Concurrent uploads", used: q.used.concurrent, limit: q.concurrent, unit: "" })),
      h("div", { className: "quota-foot dim" }, "Per-user daily cap · ", h("strong", null, q.perUserDaily)))));
}
function QuotaRow({ label, used, limit, unit }) {
  const pct = Math.min(100, (used / limit) * 100);
  const tone = pct > 90 ? "bad" : pct > 70 ? "warn" : "ok";
  return h("div", { className: "qrow" },
    h("div", { className: "qrow-top" },
      h("span", null, label),
      h("span", { className: "mono" }, fmtNum(used) + unit, h("span", { className: "dim" }, " / " + fmtNum(limit) + unit))),
    h(Bar, { value: used, max: limit, tone, height: 6 }));
}

function RedactionPolicies() {
  const toast = useToast();
  const [rows, setRows] = useState(G.REDACTION_POLICIES);
  const activate = (i) => {
    setRows((r) => r.map((p, j) => j === i ? { ...p, active: !p.active } : (p.tenant === r[i].tenant && p.consumer === r[i].consumer ? { ...p, active: false } : p)));
    toast("Redaction policy activation updated");
  };
  const head = ["Tenant", "Consumer", "Version", "Engines", "Strategy", "Fail-closed", "Active"];
  const body = rows.map((p, i) => h("tr", { key: i },
    h("td", null, G.tenantName(p.tenant)),
    h("td", null, h(Mono, { className: "dim" }, p.consumer)),
    h("td", null, h(Mono, null, p.version)),
    h("td", null, h("span", { className: "tags" }, p.engines.map((e) => h("span", { className: "tag", key: e }, e)),
      p.extra.length ? h("span", { className: "tag tag-accent" }, "+" + p.extra.length + " PHI") : null)),
    h("td", null, h(Mono, { className: "dim" }, p.strategy)),
    h("td", null, p.failClosed ? h(Pill, { tone: "ok", soft: true }, "yes") : h(Pill, { tone: "bad", soft: true }, "no")),
    h("td", null, h(Toggle, { on: p.active, onChange: () => activate(i) }))));
  return h(Card, { pad: false, title: "Redaction policies",
    subtitle: "Per-tenant PHI/PII engines, strategies and fail-closed posture",
    actions: h(Button, { variant: "primary", size: "sm", icon: "plus", onClick: () => toast("New redaction policy (mock)") }, "New policy") },
    h("div", { className: "table-wrap flush" },
      h("table", { className: "table" },
        h("thead", null, h("tr", null, head.map((c) => h("th", { key: c }, c)))),
        h("tbody", null, body))));
}

/* ======================================================================== */
/* RETENTION & COMPLIANCE                                                    */
/* ======================================================================== */
function RetentionView() {
  const toast = useToast();
  const [queue, setQueue] = useState(G.RETENTION_QUEUE);
  const [mode, setMode] = useState("observe");
  const counts = {
    erasure: queue.filter((r) => r.type === "erasure").length,
    hold: queue.filter((r) => r.type === "legal_hold").length,
    review: queue.filter((r) => r.type === "review_due").length,
  };
  const resolve = (id, action) => {
    setQueue((q) => q.filter((r) => r.id !== id));
    toast(action + " · " + id);
  };
  const TYPE_META = {
    erasure: { tone: "bad", icon: "trash", label: "Erasure request" },
    legal_hold: { tone: "warn", icon: "lock", label: "Legal hold" },
    review_due: { tone: "info", icon: "clock", label: "Review due" },
  };
  const head = ["Type", "Document", "Tenant", "Basis", "Requested by", "Age", "Action"];
  const body = queue.map((r) => {
    const m = TYPE_META[r.type];
    return h("tr", { key: r.id },
      h("td", null, h("span", { className: "rtype" }, h("span", { className: `attn-icon tone-${m.tone}` }, h(Icon, { name: m.icon, size: 13 })), m.label)),
      h("td", null, h(Mono, null, r.id)),
      h("td", null, G.tenantName(r.tenant)),
      h("td", { className: "dim" }, r.basis),
      h("td", null, h(Mono, { className: "dim" }, r.actor)),
      h("td", { className: "dim" }, fmtAgo(r.requestedAt)),
      h("td", null, h("div", { className: "row-actions" },
        r.type === "erasure" && h(Button, { variant: "danger", size: "sm", onClick: () => resolve(r.id, "Erasure executed") }, "Erase"),
        r.type === "legal_hold" && h(Button, { variant: "ghost", size: "sm", onClick: () => resolve(r.id, "Hold released") }, "Release"),
        r.type === "review_due" && h(Button, { variant: "default", size: "sm", onClick: () => resolve(r.id, "Retention extended") }, "Extend"),
        h(Button, { variant: "ghost", size: "sm", icon: "external", onClick: () => resolve(r.id, "Marked reviewed") }, "Review"))));
  });
  return h("div", { className: "view" },
    h(PageHead, { title: "Retention & compliance", sub: "Erasure requests, legal holds, and due retention reviews",
      right: h("div", { className: "mode-switch" },
        h("span", { className: "dim" }, "retention-worker"),
        ["observe", "review", "erase"].map((m) => h("button", {
          key: m, className: "mode-btn" + (mode === m ? " on" : "") + (m === "erase" ? " danger" : ""),
          onClick: () => { setMode(m); toast("retention-worker mode → " + m, m === "erase" ? "bad" : "ok"); },
        }, m))) }),
    h("div", { className: "stat-grid stat-grid-3" },
      h(Card, { pad: false }, h(Stat, { label: "Pending erasure", value: counts.erasure, tone: "bad", icon: "trash" })),
      h(Card, { pad: false }, h(Stat, { label: "Active legal holds", value: counts.hold, tone: "warn", icon: "lock" })),
      h(Card, { pad: false }, h(Stat, { label: "Reviews due", value: counts.review, tone: "info", icon: "clock" }))),
    mode === "erase" && h("div", { className: "warn-banner" }, h(Icon, { name: "alert", size: 15 }),
      "Erase mode is destructive — the worker will delete object-storage copies for erasure-requested documents that are not under legal hold."),
    h(Card, { pad: false, title: "Disposition queue", subtitle: "Derived from document retention metadata · excludes legal-hold records from erasure" },
      h("div", { className: "table-wrap flush" },
        h("table", { className: "table" },
          h("thead", null, h("tr", null, head.map((c) => h("th", { key: c }, c)))),
          h("tbody", null, body,
            !queue.length && h("tr", null, h("td", { colSpan: 7 }, h(Empty, { icon: "check", title: "Queue clear", sub: "No pending dispositions." }))))))));
}

/* ======================================================================== */
/* WEBHOOKS                                                                  */
/* ======================================================================== */
function WebhooksView() {
  const toast = useToast();
  const [hooks, setHooks] = useState(G.WEBHOOKS);
  const [modal, setModal] = useState(false);
  const [nu, setNu] = useState({ tenant: G.TENANTS[0].id, url: "", events: "document.redacted" });
  const add = () => {
    if (!nu.url) { toast("Endpoint URL required", "bad"); return; }
    setHooks((x) => [{ id: "whk_" + Math.random().toString(16).slice(2, 6), tenant: nu.tenant, url: nu.url, events: [nu.events], active: true, deliveries: { ok: 0, failed: 0 }, lastDelivery: new Date(G.NOW) }, ...x]);
    setModal(false); setNu({ tenant: G.TENANTS[0].id, url: "", events: "document.redacted" }); toast("Webhook registered");
  };
  const del = (id) => { setHooks((x) => x.filter((w) => w.id !== id)); toast("Webhook removed"); };
  const EVENTS = ["document.status.v1", "document.redacted", "document.redaction_failed", "ingest.start.v1", "ingest.failed.v1"];
  return h("div", { className: "view" },
    h(PageHead, { title: "Webhooks", sub: "Tenant status-event delivery endpoints and their delivery health",
      right: h(Button, { variant: "primary", icon: "plus", onClick: () => setModal(true) }, "Register endpoint") }),
    h("div", { className: "hook-grid" },
      hooks.map((w) => {
        const rate = w.deliveries.ok + w.deliveries.failed > 0 ? (100 * w.deliveries.ok / (w.deliveries.ok + w.deliveries.failed)) : 100;
        return h(Card, { key: w.id, className: "hook-card" },
          h("div", { className: "hook-head" },
            h("div", null,
              h("div", { className: "hook-url mono" }, w.url),
              h("div", { className: "hook-tenant dim" }, G.tenantName(w.tenant), " · ", h(Mono, null, w.id))),
            w.active ? h(Pill, { tone: "ok" }, "active") : h(Pill, { tone: "neutral", soft: true }, "paused")),
          h("div", { className: "hook-events" }, w.events.map((e) => h("span", { className: "tag", key: e }, e))),
          h("div", { className: "hook-stats" },
            h("div", { className: "hook-stat" }, h("span", { className: "hook-num ok-ink" }, fmtNum(w.deliveries.ok)), h("span", { className: "dim" }, "delivered")),
            h("div", { className: "hook-stat" }, h("span", { className: `hook-num ${w.deliveries.failed ? "bad-ink" : "dim"}` }, fmtNum(w.deliveries.failed)), h("span", { className: "dim" }, "failed")),
            h("div", { className: "hook-stat" }, h("span", { className: "hook-num" }, rate.toFixed(1) + "%"), h("span", { className: "dim" }, "success")),
            h("div", { className: "hook-stat" }, h("span", { className: "hook-num" }, fmtAgo(w.lastDelivery)), h("span", { className: "dim" }, "last"))),
          h("div", { className: "hook-foot" },
            h(Button, { variant: "ghost", size: "sm", icon: "external", onClick: () => toast("Delivery history (mock)") }, "Deliveries"),
            h(Button, { variant: "danger-ghost", size: "sm", icon: "trash", onClick: () => del(w.id) }, "Remove")));
      })),
    h(Modal, { open: modal, onClose: () => setModal(false), title: "Register webhook endpoint",
      footer: h(React.Fragment, null,
        h(Button, { variant: "ghost", onClick: () => setModal(false) }, "Cancel"),
        h(Button, { variant: "primary", onClick: add }, "Register")) },
      h("div", { className: "form-stack" },
        h(Field, { label: "Tenant" }, h(Select, { value: nu.tenant, onChange: (v) => setNu({ ...nu, tenant: v }), options: G.TENANTS.map((t) => ({ value: t.id, label: t.name })) })),
        h(Field, { label: "Endpoint URL" }, h("input", { className: "input", placeholder: "https://…", value: nu.url, onChange: (e) => setNu({ ...nu, url: e.target.value }) })),
        h(Field, { label: "Event" }, h(Select, { value: nu.events, onChange: (v) => setNu({ ...nu, events: v }), options: EVENTS })))));
}

/* ======================================================================== */
/* TENANTS & USERS (scaffold for future identity/RBAC)                       */
/* ======================================================================== */
function TenantsView({ onOpenDoc }) {
  const [sel, setSel] = useState(null);
  return h("div", { className: "view" },
    h(PageHead, { title: "Tenants & users", sub: "Organizations on the platform and the users who upload on their behalf" }),
    h("div", { className: "rbac-banner" },
      h(Icon, { name: "shield", size: 15 }),
      h("div", null, h("strong", null, "Identity & RBAC module — in design."),
        " Today tenants and users are derived from ", h(Mono, null, "tenant_id"), " and ", h(Mono, null, "initiated_by_user_id"),
        " on documents. This surface is the home for first-class tenant onboarding, user roles, and SSO when the identity layer lands.")),
    h("div", { className: "split-tenants" },
      h(Card, { pad: false, title: "Tenants", subtitle: G.TENANTS.length + " organizations" },
        h("div", { className: "tenant-list" },
          G.TENANTS.map((t) => h("button", { key: t.id, className: "tenant-row" + (sel === t.id ? " on" : ""), onClick: () => setSel(t.id) },
            h(Avatar, { initials: t.name.split(" ").map((w) => w[0]).slice(0, 2).join(""), tone: t.status === "suspended" ? "bad" : "accent" }),
            h("div", { className: "tenant-main" },
              h("div", { className: "tenant-name" }, t.name),
              h("div", { className: "tenant-sub dim" }, h(Mono, null, t.id), " · ", t.cell)),
            h("div", { className: "tenant-meta" },
              h(Pill, { tone: t.tier === "genomics" ? "purple" : t.tier === "starter" ? "neutral" : "info", soft: true }, t.tier),
              t.status === "active" ? h(Pill, { tone: "ok", soft: true }, "active") : t.status === "trial" ? h(Pill, { tone: "warn", soft: true }, "trial") : h(Pill, { tone: "bad", soft: true }, "suspended")),
            h(Icon, { name: "chevronR", size: 15, className: "row-arrow" })))),
      ),
      h(TenantDetail, { tenantId: sel })));
}

function TenantDetail({ tenantId }) {
  const toast = useToast();
  if (!tenantId) return h(Card, { className: "tenant-detail" }, h(Empty, { icon: "tenants", title: "Select a tenant", sub: "Choose an organization to see its users and usage." }));
  const t = G.TENANTS.find((x) => x.id === tenantId);
  const users = G.USERS.filter((u) => u.tenant === tenantId);
  const docs = G.DOCUMENTS.filter((d) => d.tenant === tenantId);
  return h(Card, { className: "tenant-detail", pad: false,
    title: t.name, subtitle: t.contact + " · " + t.region,
    actions: h(Button, { variant: "ghost", size: "sm", icon: "external", onClick: () => toast("Tenant settings (mock)") }, "Settings") },
    h("div", { className: "td-stats" },
      h("div", { className: "td-stat" }, h("span", { className: "td-num" }, t.users), h("span", { className: "dim" }, "users")),
      h("div", { className: "td-stat" }, h("span", { className: "td-num" }, docs.length), h("span", { className: "dim" }, "docs (mock)")),
      h("div", { className: "td-stat" }, h("span", { className: "td-num" }, t.tier), h("span", { className: "dim" }, "tier")),
      h("div", { className: "td-stat" }, h("span", { className: "td-num mono" }, t.cell), h("span", { className: "dim" }, "cell"))),
    h("div", { className: "td-section" },
      h("div", { className: "td-section-head" }, "Users",
        h(Button, { variant: "ghost", size: "sm", icon: "plus", onClick: () => toast("Invite user (mock)") }, "Invite")),
      h("div", { className: "table-wrap flush" },
        h("table", { className: "table table-tight" },
          h("thead", null, h("tr", null, ["User", "Role", "MFA", "Last active"].map((c) => h("th", { key: c }, c)))),
          h("tbody", null,
            users.map((u) => h("tr", { key: u.id },
              h("td", null, h("div", { className: "user-cell" }, h(Avatar, { initials: u.name.split(" ").map((w) => w[0]).join(""), size: 26 }),
                h("div", null, h("div", null, u.name), h("div", { className: "dim mono small" }, u.email)))),
              h("td", null, h(Pill, { tone: u.role === "Owner" || u.role === "Admin" ? "accent" : "neutral", soft: true }, u.role)),
              h("td", null, u.mfa ? h(Pill, { tone: "ok", soft: true }, "on") : h(Pill, { tone: "warn", soft: true }, "off")),
              h("td", { className: "dim" }, fmtAgo(G.ago(u.lastActive))))),
            !users.length && h("tr", null, h("td", { colSpan: 4 }, h("span", { className: "dim" }, "No users recorded."))))))));
}

Object.assign(window, { PoliciesView, RetentionView, WebhooksView, TenantsView });
