// ═══════════════════════════════════════════════════════════════════
// INSTANCE KNOWLEDGE BASE (per tenant-project)
// The INSTANTIATED datapoints — only the facts actually extracted from
// THIS project's parsed & uploaded artifacts, each with its value and
// the artifact it was sourced from. (The canonical 268-datapoint
// register lives under Platform · Datapoint Register.)
// ═══════════════════════════════════════════════════════════════════
(function () {
  const { useState } = React;
  const S = window.ONTOLOGY;
  const I = window.INTEL;
  const R = window.RAISABLE;

  const ikbMono = (s, extra) => <span style={{ fontFamily: "var(--mono)", fontSize: "8.5px", letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--ink-4)", ...extra }}>{s}</span>;
  const ST_TONE = { verified: "ok", captured: "info" };

  // confidence dot (live project)
  function Conf({ n }) {
    const t = n >= 75 ? "ok" : n >= 45 ? "warn" : "err";
    const v = { ok: "var(--ok)", warn: "var(--warn)", err: "var(--err)" }[t];
    return (
      <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
        <span style={{ width: 8, height: 8, borderRadius: 999, background: v }}></span>
        <span style={{ fontFamily: "var(--mono)", fontSize: "10px", fontWeight: 600, color: "var(--ink-2)" }}>{n}</span>
      </span>
    );
  }

  // ── store-backed project: render the real instantiated facts ──────
  function LiveKB({ proj, tenant, store }) {
    const [q, setQ] = useState("");
    const [stF, setStF] = useState("all");
    const [groupF, setGroupF] = useState("all");
    const allGroups = [...new Set(store.KB.map((f) => f.group))];
    const ql = q.trim().toLowerCase();
    // capture state derived from the fact's class: V = verified, P/A/H =
    // captured (extracted, unverified), Q/U = gap (questionable / unknown).
    const statusOf = (cls) => (cls === "V" ? "verified" : (cls === "Q" || cls === "U") ? "gap" : "captured");
    const counts = store.KB.reduce((a, f) => { const s = statusOf(f.cls); a[s] = (a[s] || 0) + 1; return a; }, {});
    const rows = store.KB.filter((f) => (stF === "all" || statusOf(f.cls) === stF) && (groupF === "all" || f.group === groupF) && (!ql || f.key.toLowerCase().includes(ql) || String(f.value).toLowerCase().includes(ql) || f.group.toLowerCase().includes(ql)));
    // group rows
    const order = []; const byG = {};
    rows.forEach((f) => { if (!byG[f.group]) { byG[f.group] = []; order.push(f.group); } byG[f.group].push(f); });
    const verified = counts.verified || 0;
    // a gap is also a REQUIRED schema datapoint with no captured value —
    // join the project's facts to the canonical register via coverage.
    const S = window.ONTOLOGY;
    let reqMissing = [];
    try { const cov = S && S.coverage ? S.coverage(proj.id, proj.kbFill || 0, window.AssetClass ? window.AssetClass.of(proj) : null) : null; if (cov && cov.perCode) reqMissing = S.DP.filter((d) => d.req === "Required" && cov.perCode[d.code] === "gap"); } catch (e) {}
    const gapCount = (counts.gap || 0) + reqMissing.length;

    return (
      <div>
        <window.PageHead eyebrow={tenant.name + " · " + proj.name} title="Knowledge Base"
          sub="The instantiated knowledge base for this project — every fact extracted from a parsed or uploaded artifact, with its value, single source, capture timestamp and verification class. This is concrete instance data, not the schema.">
        </window.PageHead>

        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14, flexWrap: "wrap" }}>
          <div style={{ display: "inline-flex", gap: 4 }}>
            {[["all", "All", store.KB.length, null], ["verified", "Verified", counts.verified || 0, "var(--ok)"], ["captured", "Captured", counts.captured || 0, "var(--accent)"], ["gap", "Gap", gapCount, "transparent"]].map(([id, lbl, n, c]) => {
              const on = stF === id;
              return (
                <button key={id} onClick={() => setStF(id)} title={"Filter to " + lbl.toLowerCase() + " facts"} style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--mono)", fontSize: "9.5px", letterSpacing: "0.06em", textTransform: "uppercase", fontWeight: 600, cursor: "pointer", color: on ? "var(--accent-lo)" : "var(--ink-3)", border: "1px solid " + (on ? "var(--accent-bd)" : "var(--rule-hard)"), background: on ? "var(--accent-bg)" : "var(--bg)", borderRadius: "var(--r-2)", padding: "7px 11px" }}>
                  {c !== null && <span style={{ width: 8, height: 8, borderRadius: 999, background: c, border: c === "transparent" ? "1.5px solid var(--rule-hard)" : "none" }}></span>}
                  {lbl} <span style={{ opacity: 0.6 }}>{n}</span>
                </button>
              );
            })}
          </div>
          <select value={groupF} onChange={(e) => setGroupF(e.target.value)} title="Filter to a knowledge group" style={{ border: "1px solid var(--rule-hard)", borderRadius: "var(--r-2)", background: "var(--bg)", color: "var(--ink-2)", fontFamily: "var(--mono)", fontSize: "10px", padding: "7px 9px", cursor: "pointer", maxWidth: 200 }}>
            <option value="all">All groups ({allGroups.length})</option>
            {allGroups.map((g) => <option key={g} value={g}>{g} · {store.KB.filter((f) => f.group === g).length}</option>)}
          </select>
          <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search facts…" style={{ flex: 1, minWidth: 160, border: "1px solid var(--rule-hard)", borderRadius: "var(--r-2)", background: "var(--bg)", color: "var(--ink)", fontFamily: "var(--ui)", fontSize: "12.5px", padding: "7px 11px" }} />
          <span style={{ fontFamily: "var(--mono)", fontSize: "9px", letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--ink-4)" }}>{rows.length} of {store.KB.length} facts · {verified} verified · {Object.keys(store.SRC).length} sources · {order.length} groups</span>
        </div>
        {stF === "gap" && <div style={{ fontFamily: "var(--mono)", fontSize: "8.5px", letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--ink-4)", marginBottom: 12 }}>Gap = questionable / unknown facts ({counts.gap || 0}) + required datapoints with no captured value ({reqMissing.length})</div>}

        {order.map((g) => (
          <div key={g} style={{ marginBottom: 14 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}>
              <window.MonoLabel style={{ color: "var(--ink-2)" }}>{g}</window.MonoLabel>
              <span style={{ fontFamily: "var(--mono)", fontSize: "9px", color: "var(--ink-4)" }}>{byG[g].length}</span>
              <span style={{ flex: 1, height: 1, background: "var(--rule)" }}></span>
            </div>
            <div style={{ border: "1px solid var(--rule-hard)", borderRadius: "var(--r-3)", overflow: "hidden" }}>
              <div style={{ display: "grid", gridTemplateColumns: "max-content 1.5fr 150px 128px 70px", gap: 1, background: "var(--rule)" }}>
                {["Memory key", "Value", "Source artifact", "Class", "Conf"].map((h) => (
                  <div key={h} style={{ background: "var(--bg-2)", padding: "7px 12px" }}><window.MonoLabel>{h}</window.MonoLabel></div>
                ))}
                {byG[g].map((f) => {
                  const cls = store.CLASS[f.cls] || {};
                  const src = store.SRC[f.source] || {};
                  return (
                    <React.Fragment key={f.key}>
                      <div style={{ background: "var(--bg)", padding: "8px 12px", fontFamily: "var(--mono)", fontSize: "10px", color: "var(--ink-3)", whiteSpace: "nowrap" }}>{f.key}</div>
                      <div style={{ background: "var(--bg)", padding: "8px 12px", fontSize: "var(--fs-sm)", color: "var(--ink)", lineHeight: 1.45 }}>{f.value}</div>
                      <div style={{ background: "var(--bg)", padding: "8px 12px", fontFamily: "var(--mono)", fontSize: "9px", lineHeight: 1.45 }} title={src.name || src.file}>
                        {src.url ? <a href={src.url} target="_blank" rel="noreferrer" style={{ color: "var(--accent-lo)", textDecoration: "none" }}>{f.source} ↗</a> : <span style={{ color: "var(--ink-4)" }}>{f.source}</span>}
                        {(src.parsed || src.uploaded) && <span style={{ display: "block", color: "var(--ink-4)", marginTop: 2 }} title={src.kind === "web" ? "retrieved & searched" : "parsed & extracted"}>captured {src.parsed || src.uploaded}</span>}
                      </div>
                      <div style={{ background: "var(--bg)", padding: "8px 12px" }}><window.Pill tone={cls.tone || "neutral"} title={cls.note}>{cls.label || f.cls}</window.Pill></div>
                      <div style={{ background: "var(--bg)", padding: "8px 12px" }}><Conf n={f.conf}></Conf></div>
                    </React.Fragment>
                  );
                })}
              </div>
            </div>
          </div>
        ))}

        {stF === "gap" && reqMissing.length > 0 && (
          <div style={{ marginBottom: 14 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}>
              <window.MonoLabel style={{ color: "var(--ink-2)" }}>Required · not yet captured</window.MonoLabel>
              <span style={{ fontFamily: "var(--mono)", fontSize: "9px", color: "var(--ink-4)" }}>{reqMissing.length}</span>
              <span style={{ flex: 1, height: 1, background: "var(--rule)" }}></span>
            </div>
            <div style={{ border: "1px dashed var(--rule-hard)", borderRadius: "var(--r-3)", overflow: "hidden" }}>
              <div style={{ display: "grid", gridTemplateColumns: "62px 1.4fr 1fr 96px 70px", gap: 1, background: "var(--rule)" }}>
                {["Code", "Required datapoint", "Group", "Tier", "Status"].map((h) => (
                  <div key={h} style={{ background: "var(--bg-2)", padding: "7px 12px" }}><window.MonoLabel>{h}</window.MonoLabel></div>
                ))}
                {reqMissing.map((d) => (
                  <React.Fragment key={d.code}>
                    <div style={{ background: "var(--bg-2)", padding: "8px 12px", fontFamily: "var(--mono)", fontSize: "10px", color: "var(--ink-3)" }}>{d.code}</div>
                    <div style={{ background: "var(--bg-2)", padding: "8px 12px", fontSize: "var(--fs-sm)", fontWeight: 500, color: "var(--ink)" }}>{d.name}</div>
                    <div style={{ background: "var(--bg-2)", padding: "8px 12px", fontSize: "var(--fs-xs)", color: "var(--ink-3)" }}>{d.group}</div>
                    <div style={{ background: "var(--bg-2)", padding: "8px 12px", fontFamily: "var(--mono)", fontSize: "9px", color: "var(--ink-4)" }}>{d.tier}</div>
                    <div style={{ background: "var(--bg-2)", padding: "8px 12px" }}><window.Pill tone="neutral">gap</window.Pill></div>
                  </React.Fragment>
                ))}
              </div>
            </div>
          </div>
        )}

        <p style={{ margin: "14px 0 0", fontFamily: "var(--mono)", fontSize: "9px", letterSpacing: "0.06em", color: "var(--ink-4)", lineHeight: 1.7 }}>
          Each fact cites exactly one artifact in the Registry. The canonical schema these map to is under Platform · Datapoint Register.
        </p>
      </div>
    );
  }

  // ── OTHER projects: instance rows derived from coverage + artifact provenance
  function DerivedKB({ proj, tenant, go }) {
    const arts = I.artifactsFor(proj).filter((a) => a.status === "parsed");
    // instantiation requires the extract step to have actually run — otherwise
    // nothing has been pulled from the artifacts yet, regardless of kbFill.
    const ready = !!(proj.run && proj.run.steps && proj.run.steps.extract === "done");
    const cov = ready ? S.coverage(proj.id, proj.kbFill || 0, window.AssetClass ? window.AssetClass.of(proj) : null) : null;
    const captured = ready ? S.DP.filter((d) => cov.perCode[d.code] === "verified" || cov.perCode[d.code] === "captured")
      .map((d, i) => ({ d, st: cov.perCode[d.code], src: arts.length ? arts[i % arts.length] : null })) : [];
    const order = []; const byT = {};
    captured.forEach((r) => { if (!byT[r.d.tier]) { byT[r.d.tier] = []; order.push(r.d.tier); } byT[r.d.tier].push(r); });

    return (
      <div>
        <window.PageHead eyebrow={tenant.name + " · " + proj.name} title="Knowledge Base"
          sub="The datapoints instantiated so far for this project — extracted from its parsed artifacts and attributed to source. Values are written into the project record; the canonical schema is under Platform · Datapoint Register."
          right={
            <div style={{ textAlign: "right" }}>
              {ikbMono(captured.length + " instantiated · " + S.DP.length + " in schema", { display: "block", marginBottom: 4, color: "var(--accent-lo)" })}
              {ikbMono(arts.length + " parsed artifacts")}
            </div>
          }>
        </window.PageHead>

        {captured.length === 0 ? (
          <div style={{ border: "1px dashed var(--rule-hard)", borderRadius: "var(--r-3)", background: "var(--bg)", padding: "34px 24px", textAlign: "center" }}>
            <div style={{ fontFamily: "var(--ui-display)", fontWeight: 600, fontSize: "var(--fs-md)", color: "var(--ink)", marginBottom: 6 }}>No datapoints instantiated yet</div>
            <p style={{ margin: "0 auto 14px", maxWidth: 460, fontSize: "var(--fs-sm)", color: "var(--ink-3)", lineHeight: 1.6 }}>The knowledge base fills once datapoint extraction runs in Workflow · 01. This project is at the <b style={{ color: "var(--ink)" }}>{proj.stage}</b> stage{arts.length ? " — " + arts.length + " artifact" + (arts.length > 1 ? "s" : "") + " parsed, extraction pending" : ""}.</p>
            <button onClick={() => go("workflow")} style={{ border: "1px solid var(--accent-bd)", background: "var(--accent-bg)", color: "var(--accent-lo)", borderRadius: "var(--r-2)", padding: "8px 16px", cursor: "pointer", fontFamily: "var(--mono)", fontSize: "9.5px", fontWeight: 600, letterSpacing: "0.08em", textTransform: "uppercase" }}>open workflow ↗</button>
          </div>
        ) : (
          <React.Fragment>
            <div style={{ display: "flex", gap: 16, flexWrap: "wrap", marginBottom: 12 }}>
              {[["verified", "var(--ok)"], ["captured", "var(--accent)"]].map(([k, c]) => (
                <span key={k} style={{ display: "inline-flex", alignItems: "center", gap: 7 }}>
                  <span style={{ width: 9, height: 9, borderRadius: 999, background: c }}></span>
                  <span style={{ fontFamily: "var(--mono)", fontSize: "9px", letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--ink-3)" }}>{k}</span>
                </span>
              ))}
            </div>
            {order.map((t) => (
              <div key={t} style={{ marginBottom: 14 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}>
                  <span style={{ fontFamily: "var(--mono)", fontSize: "12px", color: "var(--ink-4)" }}>{S.tierMeta(t).glyph}</span>
                  <window.MonoLabel style={{ color: "var(--ink-2)" }}>{t}</window.MonoLabel>
                  <span style={{ fontFamily: "var(--mono)", fontSize: "9px", color: "var(--ink-4)" }}>{byT[t].length}</span>
                  <span style={{ flex: 1, height: 1, background: "var(--rule)" }}></span>
                </div>
                <div style={{ border: "1px solid var(--rule-hard)", borderRadius: "var(--r-3)", overflow: "hidden" }}>
                  <div style={{ display: "grid", gridTemplateColumns: "62px 1.4fr 1fr 150px 92px", gap: 1, background: "var(--rule)" }}>
                    {["Code", "Datapoint", "Group", "Source artifact", "Status"].map((h) => (
                      <div key={h} style={{ background: "var(--bg-2)", padding: "7px 12px" }}><window.MonoLabel>{h}</window.MonoLabel></div>
                    ))}
                    {byT[t].map((r) => (
                      <React.Fragment key={r.d.code}>
                        <div style={{ background: "var(--bg)", padding: "8px 12px", fontFamily: "var(--mono)", fontSize: "10px", color: "var(--ink-3)" }}>{r.d.code}</div>
                        <div style={{ background: "var(--bg)", padding: "8px 12px", fontSize: "var(--fs-sm)", fontWeight: 500, color: "var(--ink)" }}>{r.d.name}</div>
                        <div style={{ background: "var(--bg)", padding: "8px 12px", fontSize: "var(--fs-xs)", color: "var(--ink-3)" }}>{r.d.group}</div>
                        <div style={{ background: "var(--bg)", padding: "8px 12px", fontFamily: "var(--mono)", fontSize: "9px", color: "var(--ink-4)" }} title={r.src && r.src.file}>{r.src ? r.src.id : "—"}</div>
                        <div style={{ background: "var(--bg)", padding: "8px 12px" }}><window.Pill tone={ST_TONE[r.st]}>{r.st}</window.Pill></div>
                      </React.Fragment>
                    ))}
                  </div>
                </div>
              </div>
            ))}
          </React.Fragment>
        )}
      </div>
    );
  }

  function InstanceKB({ proj, tenant, go }) {
    const store = (proj.kbRef && window[proj.kbRef]) || (proj.live ? R : null);
    return store ? <LiveKB proj={proj} tenant={tenant} store={store}></LiveKB> : <DerivedKB proj={proj} tenant={tenant} go={go}></DerivedKB>;
  }

  window.InstanceKB = InstanceKB;
})();
