// ═══════════════════════════════════════════════════════════════════
// RAISABLE FOUNDATION — SHARED KIT (primitives + layer chrome)
// Exports to window for the layer screens. Stobox Compass language.
// ═══════════════════════════════════════════════════════════════════
const { useState: useStateK, useEffect: useEffectK } = React;

// Layer metadata — the stack, top (4) to bottom (1). Each layer is a stage of the
// platform's own control loop (Enterprise C&C blueprint): Sense → Comprehend → Decide → Act.
const LAYERS = {
  interfaces:   { n: "04", key: "interfaces",   name: "Interfaces",   stage: "Act → Control",     def: "Where the platform is used — surfaces per persona + connectors. The execution-regulation loop." },
  intelligence: { n: "03", key: "intelligence", name: "Intelligence", stage: "Decide → Command",  def: "How the platform judges — fit, routing and the learning loop. Humans authorize; agents assist." },
  ontology:     { n: "02", key: "ontology",     name: "Ontology",     stage: "Comprehend",        def: "What the platform knows — the digital twin: entities, aggregates and language." },
  capabilities: { n: "01", key: "capabilities", name: "Capabilities", stage: "Sense",             def: "What the platform can do — composable units that ingest and integrate signals into live state." },
};
const LAYER_ORDER = ["interfaces", "intelligence", "ontology", "capabilities"];

// Maturity / status → tone token. Each lifecycle is kind-specific (roadmap /
// modeling / partnership / integration / risk); tone is uniform across all:
// first state = info ○, mid = warn ◐, terminal = ok ●.
const TONE = {
  // roadmap (capabilities · models · goals · surfaces)
  proposed: "info", building: "warn", live: "ok",
  // modeling (ontology entities)
  partial: "warn", modeled: "ok",
  // partnership (commercial relationships)
  pending: "info", negotiating: "warn", established: "ok",
  // integration (technical rails)
  planned: "neutral", connected: "ok",
  // risk / gate
  open: "err", closed: "ok",
};
const TONE_VARS = {
  ok:   { fg: "var(--ok)",   bg: "var(--ok-bg)" },
  warn: { fg: "var(--warn)", bg: "var(--warn-bg)" },
  info: { fg: "var(--info)", bg: "var(--info-bg)" },
  err:  { fg: "var(--err)",  bg: "var(--err-bg)" },
  neutral: { fg: "var(--ink-3)", bg: "var(--bg-3)" },
  accent: { fg: "var(--accent-lo)", bg: "var(--accent-bg)" },
};

function MonoLabel({ children, style }) {
  return <div style={{ fontFamily: "var(--mono)", fontWeight: 600, fontSize: "9.5px", letterSpacing: "0.18em", textTransform: "uppercase", color: "var(--ink-4)", ...style }}>{children}</div>;
}

function Pill({ children, tone = "neutral", style }) {
  const t = TONE_VARS[tone] || TONE_VARS.neutral;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontFamily: "var(--mono)", fontWeight: 600, fontSize: "9.5px", letterSpacing: "0.1em", textTransform: "uppercase", color: t.fg, background: t.bg, padding: "3px 8px", borderRadius: "var(--r-1)", whiteSpace: "nowrap", ...style }}>{children}</span>
  );
}

// Display labels for status keys (data keys stay stable; only the rendered text changes)
const STATUS_LABEL = {};
const statusLabel = (v) => STATUS_LABEL[v] || v;

// Glyph per status — one source for both the display pill and the cycle pill.
const STATUS_DOT = {
  proposed: "○", building: "◐", live: "●",
  partial: "◐", modeled: "●",
  pending: "○", negotiating: "◐", established: "●",
  planned: "○", connected: "●",
  open: "△", closed: "●",
};

function MaturityPill({ value }) {
  const dot = STATUS_DOT[value] || "·";
  return <Pill tone={TONE[value] || "neutral"}><span style={{ fontSize: "8px" }}>{dot}</span>{statusLabel(value)}</Pill>;
}

const TIER_TONE = { Core: "accent", Supporting: "info", Generic: "neutral" };
function TierBadge({ tier }) {
  return <Pill tone={TIER_TONE[tier] || "neutral"}>{tier}</Pill>;
}

// Clickable cross-reference chip → navigates to the target layer with focus.
// DRV-ids resolve against the derived registry (B5): live value, navigates to its surface.
function XRef({ id, label }) {
  const [hover, setHover] = useStateK(false);
  const drv = id && String(id).indexOf("DRV-") === 0 && window.CONTROL && window.CONTROL.DERIVED ? window.CONTROL.DERIVED.find((d) => d.id === id) : null;
  let drvVal = null; if (drv) { try { drvVal = drv.get(window.CONTROL.store); } catch (e) { drvVal = null; } }
  const F = window.FOUNDATION; // C2 ontology — absent in the Intelligence portal (planes decoupled); XRef then degrades to a plain id chip
  const node = drv ? null : (F ? F.resolve(id) : null);
  const layer = drv ? drv.surface : (F ? F.layerForId(id) : null);
  const txt = label || (drv ? drv.label + (drvVal != null ? " = " + drvVal : "") : (node ? node.name : id));
  return (
    <button onClick={() => layer && window.navigateTo(layer, id)} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      title={drv ? "Derived figure — recomputed live from the twin" : (node ? node.name : id)}
      style={{ display: "inline-flex", alignItems: "center", gap: 6, border: "1px solid " + (hover ? "var(--accent-bd)" : "var(--rule-hard)"), background: hover ? "var(--accent-bg)" : "var(--bg)", color: hover ? "var(--accent-lo)" : "var(--ink-2)", padding: "3px 8px", borderRadius: "var(--r-1)", cursor: "pointer", whiteSpace: "nowrap", transition: "all var(--t-fast) var(--ease)", maxWidth: "100%" }}>
      <span style={{ fontFamily: "var(--mono)", fontSize: "9px", color: "var(--ink-4)", letterSpacing: "0.06em" }}>{id}</span>
      <span style={{ fontSize: "12px", overflow: "hidden", textOverflow: "ellipsis" }}>{txt}</span>
    </button>
  );
}

// Back-reference chip → an Objective or Constraint that references this node.
// The write-back side of the Objectives ⇄ Foundation relationship: clicking
// navigates to the Drive · Objectives surface and flashes the source card.
function BackRefChip({ rec, kind }) {
  const [hover, setHover] = useStateK(false);
  const isObj = kind === "obj";
  const tip = (isObj ? "Objective · " : "Constraint · ") + ((isObj ? rec.why : rec.note) || "");
  return (
    <button onClick={() => window.navigateTo("objectives", rec.id)} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      title={tip}
      style={{ display: "inline-flex", alignItems: "center", gap: 6, border: "1px solid " + (hover ? "var(--accent-bd)" : "var(--rule-hard)"), background: hover ? "var(--accent-bg)" : "var(--bg)", color: hover ? "var(--accent-lo)" : "var(--ink-2)", padding: "3px 8px", borderRadius: "var(--r-1)", cursor: "pointer", whiteSpace: "nowrap", transition: "all var(--t-fast) var(--ease)", maxWidth: "100%" }}>
      <span style={{ fontSize: "9px", lineHeight: 1, color: isObj ? "var(--accent)" : "var(--ink-4)", flex: "0 0 auto" }}>{isObj ? "◉" : "▍"}</span>
      <span style={{ fontFamily: "var(--mono)", fontSize: "9px", color: "var(--ink-4)", letterSpacing: "0.06em" }}>{rec.id}</span>
      <span style={{ fontSize: "12px", overflow: "hidden", textOverflow: "ellipsis" }}>{rec.name}</span>
    </button>
  );
}

// "Referenced by" — reverse lookup of the Objectives (needs[]) and Constraints
// (link) that point at this entity / capability. Renders nothing when unlinked.
function ReferencedBy({ id, gap = 6, labelGap = 8 }) {
  const store = window.useControl();
  const objs = store.objectives.filter((o) => (o.needs || []).includes(id));
  const cons = store.constraints.filter((c) => c.link === id);
  if (!objs.length && !cons.length) return null;
  return (
    <div>
      <MonoLabel style={{ marginBottom: labelGap }}>Referenced by</MonoLabel>
      <div style={{ display: "flex", flexWrap: "wrap", gap }}>
        {objs.map((o) => <BackRefChip key={o.id} rec={o} kind="obj" />)}
        {cons.map((c) => <BackRefChip key={c.id} rec={c} kind="con" />)}
      </div>
    </div>
  );
}

// Numbered layer header — makes the four screens read as one stack
function LayerHeader({ layer, count, children }) {
  const L = LAYERS[layer];
  return (
    <div style={{ marginBottom: "var(--s-7)" }}>
      <div style={{ display: "flex", alignItems: "baseline", gap: 16, flexWrap: "wrap" }}>
        <span style={{ fontFamily: "var(--display)", fontWeight: 700, fontSize: "64px", lineHeight: 0.8, color: "var(--accent)", letterSpacing: "-0.02em" }}>{L.n}</span>
        <div style={{ minWidth: 0 }}>
          <div className="sb-eyebrow" style={{ marginBottom: 6 }}>Layer {L.n} · {L.stage}{count != null ? " · " + count + " items" : ""}</div>
          <h1 style={{ fontFamily: "var(--ui-display)", fontWeight: 600, fontSize: "var(--fs-2xl)", letterSpacing: "var(--ls-title)", color: "var(--ink)", margin: 0 }}>{L.name}</h1>
          <p style={{ color: "var(--ink-3)", fontSize: "var(--fs-md)", margin: "8px 0 0", maxWidth: "70ch" }}>{L.def}</p>
        </div>
      </div>
      {children}
    </div>
  );
}

function SectionHead({ children, sub }) {
  return (
    <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 16, margin: "var(--s-8) 0 var(--s-4)", borderBottom: "1px solid var(--rule)", paddingBottom: "var(--s-3)" }}>
      <h2 style={{ fontFamily: "var(--ui-display)", fontWeight: 600, fontSize: "var(--fs-lg)", letterSpacing: "var(--ls-card)", color: "var(--ink)" }}>{children}</h2>
      {sub && <span style={{ fontFamily: "var(--mono)", fontSize: "10px", letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--ink-4)" }}>{sub}</span>}
    </div>
  );
}

// Flow arrow used in capability / loop diagrams
function Arrow({ vertical }) {
  return <span style={{ color: "var(--ink-4)", fontSize: "16px", alignSelf: "center", lineHeight: 1, transform: vertical ? "rotate(90deg)" : "none" }}>→</span>;
}

// Page header for non-layer screens (Command / Drive)
function PageHead({ eyebrow, title, sub, right }) {
  return (
    <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 20, marginBottom: "var(--s-6)", flexWrap: "wrap" }}>
      <div style={{ minWidth: 0 }}>
        <div className="sb-eyebrow" style={{ marginBottom: 10 }}>{eyebrow}</div>
        <h1 style={{ fontFamily: "var(--ui-display)", fontWeight: 600, fontSize: "var(--fs-2xl)", letterSpacing: "var(--ls-title)", color: "var(--ink)", margin: 0 }}>{title}</h1>
        {sub && <p style={{ color: "var(--ink-3)", fontSize: "var(--fs-md)", margin: "8px 0 0", maxWidth: "76ch" }}>{sub}</p>}
      </div>
      {right}
    </div>
  );
}

function fmtNum(v, fmt, unit) {
  if (fmt === "money") {
    if (window.CONTROL && window.CONTROL.usd) return window.CONTROL.usd(v);
    const a = Math.abs(v), f = (n, d) => n.toFixed(d).replace(/\.0$/, "");
    if (a >= 1e6) return "$" + f(v / 1e6, a < 1e7 ? 1 : 0) + "M";
    if (a >= 1e3) return "$" + f(v / 1e3, a < 1e4 ? 1 : 0) + "k";
    return "$" + Math.round(v);
  }
  return (unit || "") + v.toLocaleString();
}

// Click-to-cycle status control — the signature "drive" affordance.
// Advances through options on click; persisted by the caller.
function CyclePill({ value, options, toneMap, glyphs, onCycle }) {
  const [hover, setHover] = useStateK(false);
  const tone = (toneMap && toneMap[value]) || "neutral";
  const t = TONE_VARS[tone] || TONE_VARS.neutral;
  const next = () => { const i = options.indexOf(value); onCycle(options[(i + 1) % options.length]); };
  return (
    <button onClick={next} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} title="Click to change"
      style={{ display: "inline-flex", alignItems: "center", gap: 5, fontFamily: "var(--mono)", fontWeight: 600, fontSize: "9.5px", letterSpacing: "0.1em", textTransform: "uppercase", color: t.fg, background: t.bg, padding: "3px 8px", borderRadius: "var(--r-1)", whiteSpace: "nowrap", border: "1px solid " + (hover ? t.fg : "transparent"), cursor: "pointer", transition: "border-color var(--t-fast) var(--ease)" }}>
      {glyphs && glyphs[value] && <span style={{ fontSize: "8px" }}>{glyphs[value]}</span>}
      {statusLabel(value)}
      <span style={{ fontSize: "9px", opacity: hover ? 0.85 : 0.4 }}>↻</span>
    </button>
  );
}

// Inline-editable text — click to edit, commits on blur (Enter for single-line).
function EditableText({ value, onSave, multiline, placeholder, style }) {
  const [editing, setEditing] = useStateK(false);
  const [v, setV] = useStateK(value);
  useEffectK(() => setV(value), [value]);
  const commit = () => { setEditing(false); if (v !== value) onSave(v); };
  const shared = { fontFamily: "inherit", fontSize: "inherit", color: "inherit", lineHeight: "inherit", width: "100%", border: "1px solid var(--accent)", borderRadius: "var(--r-1)", padding: "2px 6px", background: "var(--bg)", outline: "none", ...style };
  if (editing) {
    return multiline
      ? <textarea autoFocus value={v} onChange={(e) => setV(e.target.value)} onBlur={commit} rows={2} style={{ ...shared, resize: "vertical" }} />
      : <input autoFocus value={v} onChange={(e) => setV(e.target.value)} onBlur={commit} onKeyDown={(e) => e.key === "Enter" && commit()} style={shared} />;
  }
  return (
    <span onClick={() => setEditing(true)} title="Click to edit"
      style={{ cursor: "text", borderBottom: "1px dashed transparent", transition: "border-color var(--t-fast) var(--ease)", ...style }}
      onMouseEnter={(e) => (e.currentTarget.style.borderBottomColor = "var(--rule-hard)")}
      onMouseLeave={(e) => (e.currentTarget.style.borderBottomColor = "transparent")}>
      {value || <span style={{ color: "var(--ink-4)" }}>{placeholder || "—"}</span>}
    </span>
  );
}

// Shared cycle vocabularies — one per entity kind, so each reads in its own terms.
// roadmap: what the platform is building · modeling: how mapped an entity is
// partnership: a commercial relationship · integration: a technical rail you connect
const STATUS_OPTS = ["proposed", "building", "live"];
const STATUS_TONE = { proposed: "info", building: "warn", live: "ok" };
const STATUS_GLYPH = { proposed: "○", building: "◐", live: "●" };
const PARTNERSHIP_OPTS = ["pending", "negotiating", "established"];
const PARTNERSHIP_TONE = { pending: "info", negotiating: "warn", established: "ok" };
const PARTNERSHIP_GLYPH = { pending: "○", negotiating: "◐", established: "●" };
const INTEGRATION_OPTS = ["planned", "pending", "building", "connected"];
const INTEGRATION_TONE = { planned: "neutral", pending: "info", building: "warn", connected: "ok" };
const INTEGRATION_GLYPH = { planned: "○", pending: "○", building: "◐", connected: "●" };
const RISK_OPTS = ["watch", "active", "critical"];
const RISK_TONE_MAP = { watch: "info", active: "warn", critical: "err" };
const RISK_GLYPH = { watch: "○", active: "◐", critical: "△" };
const OWNER_OPTS = ["CEO", "COO", "Product", "Legal", "GTM", "Ops", "Data", "AI"];
const ENT_STATUS_OPTS = ["proposed", "partial", "modeled"];
const ENT_STATUS_TONE = { proposed: "info", partial: "warn", modeled: "ok" };
const ENT_STATUS_GLYPH = { proposed: "○", partial: "◐", modeled: "●" };

// Editable status pill bound to the Foundation status-override drivers.
// vocab "build" → live/building/proposed (caps, models, surfaces);
// vocab "ent"   → modeled/partial/proposed (entities).
function StatusControl({ id, seed, vocab }) {
  const store = window.CONTROL.store;
  const cur = store.statusOf(id, seed);
  const isEnt = vocab === "ent";
  return (
    <CyclePill value={cur}
      options={isEnt ? ENT_STATUS_OPTS : STATUS_OPTS}
      toneMap={isEnt ? ENT_STATUS_TONE : STATUS_TONE}
      glyphs={isEnt ? ENT_STATUS_GLYPH : STATUS_GLYPH}
      onCycle={(v) => store.setStatus(id, v)} />
  );
}

// ── PageTabs — full-width stretch tab ribbon shared across all portal screens ──
// Usage: <window.PageTabs tabs={[{id,label,sub},...]} active={tab} onTab={setTab} />
function PageTabs({ tabs, active, onTab }) {
  const cur = tabs.find((t) => t.id === active) || tabs[0];
  return (
    <div style={{ marginBottom: 28 }}>
      <div style={{ display: "flex", borderBottom: "1px solid var(--rule-hard)", marginLeft: -40, marginRight: -40, paddingLeft: 40, paddingRight: 40 }}>
        {tabs.map((t) => {
          const on = t.id === (active || tabs[0].id);
          return (
            <button key={t.id} onClick={() => onTab(t.id)} style={{ flex: 1, background: "none", border: "none", borderBottom: on ? "2px solid var(--accent)" : "2px solid transparent", marginBottom: -1, padding: "10px 0 11px", cursor: "pointer", fontFamily: "var(--mono)", fontSize: "11px", letterSpacing: "0.07em", textTransform: "uppercase", fontWeight: on ? 700 : 400, color: on ? "var(--accent)" : "var(--ink-4)", transition: "color var(--t-base) var(--ease), border-color var(--t-base) var(--ease)", whiteSpace: "nowrap" }}>
              {t.label}
            </button>
          );
        })}
      </div>
      {cur && cur.sub && <div style={{ fontFamily: "var(--mono)", fontSize: "10px", color: "var(--ink-4)", letterSpacing: "0.06em", paddingTop: 14 }}>{cur.sub}</div>}
    </div>
  );
}

Object.assign(window, { LAYERS, LAYER_ORDER, TONE, TONE_VARS, MonoLabel, Pill, MaturityPill, TierBadge, XRef, BackRefChip, ReferencedBy, LayerHeader, SectionHead, Arrow, PageHead, PageTabs, fmtNum, CyclePill, EditableText, StatusControl, STATUS_OPTS, STATUS_TONE, STATUS_GLYPH, PARTNERSHIP_OPTS, PARTNERSHIP_TONE, PARTNERSHIP_GLYPH, INTEGRATION_OPTS, INTEGRATION_TONE, INTEGRATION_GLYPH, RISK_OPTS, RISK_TONE_MAP, RISK_GLYPH, OWNER_OPTS, ENT_STATUS_OPTS, ENT_STATUS_TONE, ENT_STATUS_GLYPH, STATUS_LABEL, statusLabel });
