/* Eno.Health Console — Reference data: Terminologies (LOINC/UCUM) + Laboratories & test types */
const R = window.ENO;
const TAPI = window.EnoAdminAPI;

/* small helpers shared in this file */
function dbStatusPill(status) {
  if (status === "custom") return h(Pill, { tone: "purple", soft: true }, "custom");
  if (status === "deprecated") return h(Pill, { tone: "neutral", soft: true }, "deprecated");
  return h(Pill, { tone: "ok", soft: true }, "active");
}
function fmtRef(a) {
  if (a.refLow != null && a.refHigh != null) return a.refLow + "–" + a.refHigh;
  if (a.refHigh != null) return "< " + a.refHigh;
  if (a.refLow != null) return "> " + a.refLow;
  return "—";
}
function fallbackRanges(ranges) {
  const blank = { low: null, high: null };
  return {
    male: { ...blank, ...(ranges && ranges.male ? ranges.male : {}) },
    female: { ...blank, ...(ranges && ranges.female ? ranges.female : {}) },
    femaleMenopausal: { ...blank, ...(ranges && ranges.femaleMenopausal ? ranges.femaleMenopausal : {}) },
    femalePregnant: { ...blank, ...(ranges && ranges.femalePregnant ? ranges.femalePregnant : {}) },
  };
}
function bmDisplayName(biomarkers, id) {
  return (biomarkers.find((b) => b.id === id) || {}).name || R.bmName(id);
}
function liveAgo(date) {
  const seconds = Math.max(0, Math.round((Date.now() - date.getTime()) / 1000));
  if (seconds < 60) return seconds + "s ago";
  if (seconds < 3600) return Math.round(seconds / 60) + "m ago";
  if (seconds < 86400) return Math.round(seconds / 3600) + "h ago";
  return Math.round(seconds / 86400) + "d ago";
}
function syncDisplay(db) {
  const importedAt = db.importedAt ? new Date(db.importedAt) : null;
  if (importedAt && !Number.isNaN(importedAt.getTime())) {
    return {
      relative: liveAgo(importedAt),
      exact: fmtDate(importedAt) + " · " + fmtTime(importedAt),
    };
  }
  return {
    relative: db.lastSyncMin ? fmtAgo(R.ago(db.lastSyncMin * R.MIN)) : "not synced",
    exact: "last sync",
  };
}

/* ======================================================================== */
/* TERMINOLOGIES — LOINC · Biomarkers · UCUM                                 */
/* ======================================================================== */
function TerminologyView() {
  const [tab, setTab] = useState("loinc");
  // Biomarker ↔ LOINC links are editable from both terminology views, so the
  // live dictionary stays here and is shared down to both panels.
  const [biomarkers, setBiomarkers] = useState(() => R.BIOMARKERS.map((b) => ({ ...b, loinc: [...b.loinc], phenotypes: [...b.phenotypes], ranges: fallbackRanges(b.ranges) })));
  const [loincCodes, setLoincCodes] = useState(() => R.LOINC_CODES.map((c) => ({ ...c })));
  const [loincPage, setLoincPage] = useState({ total: R.LOINC_CODES.length, loadedAll: true });
  const [loincGroups, setLoincGroups] = useState([]);
  const [loincFacets, setLoincFacets] = useState({ units: [], classes: [], systems: [], statuses: [], biomarkers: [] });
  const [ucumUnits, setUcumUnits] = useState(() => R.UCUM_UNITS.map((u) => ({ ...u })));
  const [loincDB, setLoincDB] = useState(R.LOINC_DB);
  const [ucumDB, setUcumDB] = useState(R.UCUM_DB);
  const [reviews, setReviews] = useState({ items: [], total: 0, pending: 0, loading: false });
  const [live, setLive] = useState({ loading: true, error: "", status: "mock" });
  const toast = useToast();

  const loadSummary = async () => {
    const summary = await TAPI.terminologySummary();
    setLoincDB(summary.loincDB);
    setUcumDB(summary.ucumDB);
  };
  const loadLoinc = async (params = {}) => {
    const hasSearch = Boolean(params.query && String(params.query).trim());
    if (!hasSearch) {
      const browseParams = { sort: "code", direction: "asc", limit: 50, ...params };
      const page = await TAPI.loincTerms(browseParams);
      setLoincCodes(page.items.length ? page.items : []);
      setLoincPage({ total: page.total || page.items.length || 0, loadedAll: false });
      const hasFacetFilters = ["units", "classes", "systems", "statuses", "biomarkers"].some((key) => Array.isArray(params[key]) && params[key].length);
      if (!hasFacetFilters && (!params.class || params.class === "all") && (!params.group_id || params.group_id === "all") && (!params.status || params.status === "all")) {
        const mappedPage = await TAPI.loincTerms({ limit: 1, mapped_only: true });
        setLoincDB((db) => ({ ...db, mappedInUse: mappedPage.total || 0 }));
      }
      return page;
    }
    const limit = 200;
    let offset = 0;
    let total = 0;
    const items = [];
    do {
      const page = await TAPI.loincTerms({ ...params, limit, offset });
      items.push(...(page.items || []));
      total = page.total || items.length;
      offset += limit;
    } while (items.length < total);
    const page = { items, total, limit: items.length, offset: 0, status: "ok" };
    setLoincCodes(items);
    setLoincPage({ total: items.length, loadedAll: true });
    return page;
  };
  const loadLoincGroups = async (params = {}) => {
    const page = await TAPI.loincGroups({ limit: 500, ...params });
    setLoincGroups(page.items || []);
    return page;
  };
  const loadLoincFacets = async (params = {}) => {
    const facets = await TAPI.loincFacets(params);
    setLoincFacets(facets);
    return facets;
  };
  const loadUCUM = async (params = {}) => {
    const page = await TAPI.ucumUnits({ limit: 100, ...params });
    setUcumUnits(page.items.length ? page.items : []);
    return page;
  };
  const loadBiomarkers = async (params = {}) => {
    const page = await TAPI.biomarkers({ limit: 200, ...params });
    setBiomarkers((page.items || []).map((b) => ({ ...b, ranges: fallbackRanges(b.ranges), loinc: [...b.loinc], phenotypes: [...b.phenotypes] })));
    return page;
  };
  const loadReviews = async (params = {}) => {
    const page = await TAPI.biomarkerMappingReviews({ limit: 100, status: "pending", ...params });
    setReviews({ items: page.items || [], total: page.total || 0, pending: page.total || 0, loading: false });
    return page;
  };

  useEffect(() => {
    let cancelled = false;
    async function run() {
      setLive({ loading: true, error: "", status: "loading" });
      try {
        await Promise.all([loadSummary(), loadLoinc(), loadLoincGroups(), loadLoincFacets(), loadUCUM(), loadBiomarkers(), loadReviews()]);
        if (!cancelled) setLive({ loading: false, error: "", status: "live" });
      } catch (err) {
        if (!cancelled) setLive({ loading: false, error: err.message || "Unable to load terminology data", status: "mock" });
      }
    }
    run();
    return () => { cancelled = true; };
  }, []);

  useEffect(() => {
    if (live.status !== "live") return;
    const tick = () => {
      if (document.hidden) return;
      loadReviews().catch((err) => setReviews((cur) => ({ ...cur, loading: false, error: err.message })));
    };
    const timer = setInterval(tick, 15000);
    return () => clearInterval(timer);
  }, [live.status]);

  const replaceBiomarker = (bm) => setBiomarkers((xs) => xs.map((b) => b.id === bm.id ? { ...bm, ranges: fallbackRanges(bm.ranges), loinc: [...bm.loinc], phenotypes: [...bm.phenotypes] } : b));
  const bmApi = {
    linkLoinc: async (bmId, code) => {
      const bm = biomarkers.find((b) => b.id === bmId);
      try {
        replaceBiomarker(await TAPI.linkLoinc(bmId, code, bm && bm.specimen));
        toast("Linked " + code + " → " + bmDisplayName(biomarkers, bmId), "ok");
      } catch (err) { toast(err.message, "bad"); }
    },
    unlinkLoinc: async (bmId, code) => {
      try {
        replaceBiomarker(await TAPI.unlinkLoinc(bmId, code));
        toast("Unlinked " + code + " from " + bmDisplayName(biomarkers, bmId));
      } catch (err) { toast(err.message, "bad"); }
    },
    patch: async (bmId, patch) => {
      setBiomarkers((xs) => xs.map((b) => b.id === bmId ? { ...b, ...patch } : b));
      try { replaceBiomarker(await TAPI.patchBiomarker(bmId, patch)); } catch (err) { toast(err.message, "bad"); }
    },
    togglePhenotype: async (bmId, ph) => {
      const bm = biomarkers.find((b) => b.id === bmId);
      if (!bm) return;
      const phenotypes = bm.phenotypes.includes(ph) ? bm.phenotypes.filter((p) => p !== ph) : [...bm.phenotypes, ph];
      await bmApi.patch(bmId, { phenotypes });
    },
    setRange: async (bmId, demo, bound, val) => {
      const bm = biomarkers.find((b) => b.id === bmId);
      if (!bm) return;
      const ranges = { ...fallbackRanges(bm.ranges), [demo]: { ...fallbackRanges(bm.ranges)[demo], [bound]: val === "" || val == null ? null : Number(val) } };
      await bmApi.patch(bmId, { ranges });
    },
    addBiomarker: async (bm) => {
      try {
        const created = await TAPI.createBiomarker({ ...bm, ranges: fallbackRanges(bm.ranges) });
        setBiomarkers((xs) => [{ ...created, ranges: fallbackRanges(created.ranges), loinc: [...created.loinc], phenotypes: [...created.phenotypes] }, ...xs]);
        toast("Biomarker “" + created.name + "” created", "ok");
        return created;
      } catch (err) { toast(err.message, "bad"); return null; }
    },
    markReviewed: async (bmId) => {
      try {
        replaceBiomarker(await TAPI.patchBiomarker(bmId, { confidence: 100 }));
        toast("“" + bmDisplayName(biomarkers, bmId) + "” marked reviewed", "ok");
      } catch (err) { toast(err.message, "bad"); }
    },
    addLoinc: (code) => { setLoincCodes((xs) => [code, ...xs]); toast("Custom code " + code.code + " added", "ok"); },
    resolveReview: async (review, biomarkerId) => {
      try {
        await TAPI.resolveBiomarkerMappingReview(review.id, {
          biomarker_id: biomarkerId,
          loinc_code: review.candidate_loinc_code,
          specimen: review.specimen,
          curator_notes: "Approved from biomarker mapping review queue",
          reviewed_by: "admin-console",
        });
        toast("Linked " + review.candidate_loinc_code + " from review queue", "ok");
        await Promise.all([loadBiomarkers(), loadLoinc(), loadReviews()]);
      } catch (err) { toast(err.message, "bad"); }
    },
    rejectReview: async (review) => {
      try {
        await TAPI.rejectBiomarkerMappingReview(review.id, { curator_notes: "Rejected from admin console", reviewed_by: "admin-console" });
        toast("Review item rejected");
        await loadReviews();
      } catch (err) { toast(err.message, "bad"); }
    },
  };

  const tabs = [
    { key: "review", label: "Review", count: reviews.pending },
    { key: "loinc", label: "LOINC", count: loincDB.mappedInUse },
    { key: "biomarker", label: "Biomarkers", count: biomarkers.length },
    { key: "ucum", label: "UCUM", count: ucumDB.mappedInUse },
  ];
  return h("div", { className: "view" },
    h(PageHead, { title: "Terminologies",
      sub: "Versioned vocabularies and Eno's biomarker dictionary — what normalizes an extracted value into a result a practitioner can read" }),
    h("div", { className: "ref-banner" }, h(Icon, { name: "link", size: 16, className: "dim" }),
      h("div", null, "Extraction maps each observation to a ", h("strong", null, "LOINC"), " code; a ",
        h("strong", null, "Biomarker"), " groups the LOINC codes that mean the same thing and attaches the ",
        h("strong", null, "UCUM"), " unit, specimen and reference ranges used to interpret it.")),
    h(Tabs, { tabs, active: tab, onChange: setTab }),
    h("div", { className: "tabbody" },
      tab === "review" ? h(BiomarkerReviewPanel, { reviews, biomarkers, api: bmApi, onRefresh: loadReviews })
        : tab === "loinc" ? h(LoincPanel, { biomarkers, api: bmApi, loincCodes, loincPage, loincGroups, loincFacets, db: loincDB, live, onSearch: loadLoinc })
        : tab === "biomarker" ? h(BiomarkerPanel, { biomarkers, api: bmApi, loincCodes })
        : h(UcumPanel, { db: ucumDB, units: ucumUnits, live, onSearch: loadUCUM })));
}

function BiomarkerReviewPanel({ reviews, biomarkers, api, onRefresh }) {
  const [q, setQ] = useState("");
  const filtered = (reviews.items || []).filter((item) => !q ||
    (item.observed_name + " " + item.observed_unit + " " + item.candidate_loinc_code).toLowerCase().includes(q.toLowerCase()));
  const head = ["Observation", "Candidate", "Reason", "Seen", "Action"];
  return h("div", { className: "view" },
    h(Card, { pad: false, title: "Biomarker review queue",
      subtitle: "Document-derived observations that need administrator curation before future ingestion can auto-normalize them.",
      actions: h(Button, { variant: "ghost", size: "sm", icon: "refresh", onClick: () => onRefresh() }, "Refresh") },
      h("div", { className: "toolbar" },
        h("div", { className: "search" }, h(Icon, { name: "search", size: 16 }),
          h("input", { className: "search-input", placeholder: "Search observation, unit or LOINC…", value: q, onChange: (e) => setQ(e.target.value) })),
        h(Pill, { tone: reviews.pending ? "warn" : "ok", soft: true }, reviews.pending + " pending"),
        h("span", { className: "toolbar-count" }, "Auto-refreshes every 15s")),
      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,
            filtered.map((item) => h(BiomarkerReviewRow, { key: item.id, item, biomarkers, api })),
            !filtered.length && h("tr", null, h("td", { colSpan: 5 }, h(Empty, { icon: "check", title: "No pending biomarker reviews", sub: "New document observations will appear here automatically." }))))))));
}

function BiomarkerReviewRow({ item, biomarkers, api }) {
  const [pick, setPick] = useState(item.candidate_biomarker_id || "");
  const options = [{ value: "", label: "Select biomarker" }, ...biomarkers.map((b) => ({ value: b.id, label: b.name }))];
  const reasons = item.review_reasons || [];
  return h("tr", null,
    h("td", null,
      h("div", { className: "strong" }, item.observed_name),
      h("div", { className: "dim" }, [item.observed_value, item.observed_unit, item.specimen].filter(Boolean).join(" · ") || "No value context")),
    h("td", null,
      item.candidate_loinc_code ? h(Mono, { copy: true, className: "code-strong" }, item.candidate_loinc_code) : h("span", { className: "dim" }, "No candidate"),
      h("div", { className: "dim" }, Math.round((item.candidate_score || 0) * 100), "% confidence")),
    h("td", null,
      h("span", { className: "tags" }, reasons.slice(0, 2).map((reason) => h("span", { className: "tag", key: reason }, reason))),
      reasons.length > 2 && h("div", { className: "dim" }, "+", reasons.length - 2, " more")),
    h("td", null,
      h("div", null, fmtNum(item.occurrence_count || 1), " occurrence", (item.occurrence_count || 1) === 1 ? "" : "s"),
      h("div", { className: "dim" }, item.last_seen_at ? fmtAgo(new Date(item.last_seen_at)) : "recent")),
    h("td", null,
      h("div", { className: "toolbar", style: { padding: 0, gap: 8 } },
        h(Select, { value: pick, onChange: setPick, options }),
        h(Button, { variant: "primary", size: "sm", icon: "link", disabled: !pick || !item.candidate_loinc_code, onClick: () => api.resolveReview(item, pick) }, "Link"),
        h(Button, { variant: "ghost", size: "sm", icon: "x", onClick: () => api.rejectReview(item) }, "Reject"))));
}

function DbInfoCard({ db, kind }) {
  const toast = useToast();
  const sync = syncDisplay(db);
  return h(Card, { pad: false,
    title: db.name + " release " + db.version,
    subtitle: db.source + " · " + db.license,
    actions: h(React.Fragment, null,
      h(Button, { variant: "ghost", size: "sm", icon: "refresh", onClick: () => toast("Checked for updates · " + db.next, "ok") }, "Check for updates"),
      h(Button, { variant: "default", size: "sm", icon: "upload", disabled: true, title: "Imports run through terminology-importer for now" }, "Import release")) },
    h("div", { className: "td-stats" },
      h("div", { className: "td-stat" }, h("span", { className: "td-num mono" }, db.version), h("span", { className: "dim" }, "loaded version")),
      h("div", { className: "td-stat" }, h("span", { className: "td-num" }, fmtNum(kind === "loinc" ? db.totalCodes : db.totalUnits)), h("span", { className: "dim" }, kind === "loinc" ? "total codes" : "total units")),
      h("div", { className: "td-stat" }, h("span", { className: "td-num" }, fmtNum(db.mappedInUse)), h("span", { className: "dim" }, "mapped in use")),
      h("div", { className: "td-stat" }, h("span", { className: "td-num" }, db.custom), h("span", { className: "dim" }, "custom entries")),
      h("div", { className: "td-stat" }, h("span", { className: "td-num" }, sync.relative), h("span", { className: "dim" }, sync.exact))));
}

function TableHeader({ field, label, sort, onSort, facet, selected, activeFacet, setActiveFacet, onToggleFacet, onClearFacet }) {
  const active = sort.field === field;
  const filterOpen = activeFacet === field;
  const selectedSet = new Set(selected || []);
  return h("div", { className: "th-controls" },
    h("span", null, label),
    h("button", {
      type: "button",
      className: "th-icon" + (active ? " th-icon-on" : ""),
      onClick: () => onSort(field, active && sort.direction === "asc" ? "desc" : "asc"),
      title: "Sort " + label,
    }, h(Icon, { name: "sort", size: 14 })),
    facet && h("button", {
      type: "button",
      className: "th-icon" + (selectedSet.size ? " th-icon-on" : ""),
      onClick: () => setActiveFacet(filterOpen ? "" : field),
      title: "Group by " + label,
    }, h(Icon, { name: "filter", size: 13 })),
    facet && filterOpen && h("div", { className: "facet-menu", onClick: (e) => e.stopPropagation() },
      h("div", { className: "facet-menu-head" },
        h("span", null, label),
        h("button", { type: "button", onClick: () => onClearFacet(field) }, "Clear")),
      h("div", { className: "facet-list" },
        (facet.items || []).map((item) => h("label", { className: "facet-option", key: item.value },
          h("input", {
            type: "checkbox",
            checked: selectedSet.has(item.value),
            onChange: () => onToggleFacet(field, item.value),
          }),
          h("span", { className: "facet-value" }, item.value || "—"),
          h("span", { className: "facet-count" }, fmtNum(item.count || 0)))),
        !(facet.items || []).length && h("div", { className: "facet-empty" }, "No values"))));
}

function compareLoinc(a, b, sort, linkedTo) {
  const linkedCount = (term) => (linkedTo(term.code).length || term.linkedBiomarkers?.length || term.used || 0);
  const value = (term) => {
    if (sort.field === "code") return term.code;
    if (sort.field === "name") return term.name;
    if (sort.field === "system") return term.system;
    if (sort.field === "unit") return term.unit;
    if (sort.field === "class") return term.cls;
    if (sort.field === "status") return term.status;
    return linkedCount(term);
  };
  const av = value(a);
  const bv = value(b);
  const result = typeof av === "number" || typeof bv === "number"
    ? Number(av || 0) - Number(bv || 0)
    : String(av || "").localeCompare(String(bv || ""), undefined, { numeric: true, sensitivity: "base" });
  if (result !== 0) return sort.direction === "desc" ? -result : result;
  return String(a.code).localeCompare(String(b.code), undefined, { numeric: true });
}

function LoincPanel({ biomarkers, api, loincCodes, loincPage, loincGroups, loincFacets, db, live, onSearch }) {
  const toast = useToast();
  const [q, setQ] = useState("");
  const [group, setGroup] = useState("all");
  const [groupText, setGroupText] = useState("Any LOINC group");
  const [sort, setSort] = useState({ field: "code", direction: "asc" });
  const [facetFilters, setFacetFilters] = useState({ units: [], classes: [], systems: [], statuses: [], biomarkers: [] });
  const [activeFacet, setActiveFacet] = useState("");
  const [sel, setSel] = useState(null);
  const [adding, setAdding] = useState(false);
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState(50);
  const groupOptions = [{ value: "all", label: "Any LOINC group" }, ...(loincGroups || []).map((g) => ({
    value: g.id,
    label: (g.category && g.category !== "Other" ? g.category + " · " : "") + g.name + (g.memberCount ? " (" + fmtNum(g.memberCount) + ")" : ""),
  }))];
  const facetByField = {
    unit: { key: "units", items: loincFacets.units || [] },
    class: { key: "classes", items: loincFacets.classes || [] },
    biomarkers: { key: "biomarkers", items: loincFacets.biomarkers || [] },
    system: { key: "systems", items: loincFacets.systems || [] },
    status: { key: "statuses", items: loincFacets.statuses || [] },
  };
  const toggleFacet = (field, value) => {
    const key = facetByField[field].key;
    setFacetFilters((cur) => {
      const current = cur[key] || [];
      return { ...cur, [key]: current.includes(value) ? current.filter((item) => item !== value) : [...current, value] };
    });
  };
  const clearFacet = (field) => {
    const key = facetByField[field].key;
    setFacetFilters((cur) => ({ ...cur, [key]: [] }));
  };
  const applyGroupText = (text) => {
    setGroupText(text);
    const normalized = String(text || "").trim().toLowerCase();
    const match = groupOptions.find((g) => g.label.toLowerCase() === normalized || g.value.toLowerCase() === normalized);
    setGroup(match ? match.value : "all");
  };
  const commitGroupText = (text) => {
    const normalized = String(text || "").trim().toLowerCase();
    const match = groupOptions.find((g) => g.label.toLowerCase() === normalized || g.value.toLowerCase() === normalized);
    setGroup(match ? match.value : "all");
    setGroupText(match ? match.label : "Any LOINC group");
  };
  const linkedTo = (code) => biomarkers.filter((b) => b.loinc.includes(code));
  const clientFiltered = live.status === "live" ? loincCodes : loincCodes.filter((c) =>
    (!facetFilters.classes.length || facetFilters.classes.includes(c.cls)) &&
    (!facetFilters.systems.length || facetFilters.systems.includes(c.system)) &&
    (!facetFilters.units.length || facetFilters.units.includes(c.unit)) &&
    (!facetFilters.statuses.length || facetFilters.statuses.includes(c.status)) &&
    (!facetFilters.biomarkers.length || linkedTo(c.code).some((b) => facetFilters.biomarkers.includes(b.name)) || (c.linkedBiomarkers || []).some((b) => facetFilters.biomarkers.includes(b))) &&
    (!q || (c.code + " " + c.name + " " + c.component).toLowerCase().includes(q.toLowerCase())));
  const rows = live.status === "live" ? clientFiltered : [...clientFiltered].sort((a, b) => compareLoinc(a, b, sort, linkedTo));
  const usesServerPaging = live.status === "live" && !loincPage.loadedAll && !q;
  const totalRows = usesServerPaging ? loincPage.total : rows.length;
  const pageCount = Math.max(1, Math.ceil(totalRows / pageSize));
  const safePage = Math.min(page, pageCount);
  const pageStart = totalRows ? (safePage - 1) * pageSize : 0;
  const pageRows = usesServerPaging ? rows : rows.slice(pageStart, pageStart + pageSize);
  const pageSizeOptions = [25, 50, 100, 250, 500].map((n) => ({ value: String(n), label: String(n) }));
  const setSortField = (field, direction) => setSort({ field, direction });
  const queryFilters = { units: facetFilters.units, classes: facetFilters.classes, systems: facetFilters.systems, statuses: facetFilters.statuses, biomarkers: facetFilters.biomarkers };
  useEffect(() => { setPage(1); }, [q, group, pageSize, sort.field, sort.direction, facetFilters.units, facetFilters.classes, facetFilters.systems, facetFilters.statuses, facetFilters.biomarkers]);
  useEffect(() => { if (page > pageCount) setPage(pageCount); }, [page, pageCount]);
  useEffect(() => {
    if (live.status !== "live" || !q) return;
    const timer = setTimeout(() => onSearch({ query: q, group_id: group, sort: sort.field, direction: sort.direction, ...queryFilters }), 250);
    return () => clearTimeout(timer);
  }, [q, group, sort.field, sort.direction, live.status, facetFilters.units, facetFilters.classes, facetFilters.systems, facetFilters.statuses, facetFilters.biomarkers]);
  useEffect(() => {
    if (live.status !== "live" || q) return;
    onSearch({ group_id: group, sort: sort.field, direction: sort.direction, limit: pageSize, offset: (safePage - 1) * pageSize, ...queryFilters });
  }, [pageSize, safePage, q, group, sort.field, sort.direction, live.status, facetFilters.units, facetFilters.classes, facetFilters.systems, facetFilters.statuses, facetFilters.biomarkers]);
  const head = [
    ["code", "Code"], ["name", "Long common name"], ["system", "System"], ["unit", "Units"],
    ["class", "Class"], ["biomarkers", "Biomarkers"], ["status", "Status"],
  ];
  return h("div", { className: "view" },
    h(DbInfoCard, { db, kind: "loinc" }),
    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 code, name or component…", value: q, onChange: (e) => setQ(e.target.value) })),
        h("div", { className: "autocomplete-filter" },
          h("input", {
            className: "input",
            list: "loinc-group-options",
            value: groupText,
            placeholder: "Any LOINC group",
            onFocus: (e) => e.target.select(),
            onChange: (e) => applyGroupText(e.target.value),
            onBlur: (e) => commitGroupText(e.target.value),
          }),
          h("datalist", { id: "loinc-group-options" },
            groupOptions.map((g) => h("option", { key: g.value, value: g.label })))),
        h(Select, { value: String(pageSize), onChange: (value) => setPageSize(Number(value)), options: pageSizeOptions }),
        h("span", { className: "toolbar-count" }, totalRows ? pageStart + 1 : 0, "–", Math.min(pageStart + pageSize, totalRows), " of ", totalRows, usesServerPaging ? " codes" : " matches"),
        h(Button, { variant: "default", size: "sm", icon: "plus", disabled: true, title: "Custom LOINC persistence is not enabled yet" }, "Custom code")),
      h("div", { className: "table-wrap flush" },
        h("table", { className: "table" },
          h("thead", null, h("tr", null, head.map(([field, label]) => h("th", { key: field },
            h(TableHeader, {
              field, label, sort, onSort: setSortField,
              facet: facetByField[field],
              selected: facetByField[field] ? facetFilters[facetByField[field].key] : [],
              activeFacet,
              setActiveFacet,
              onToggleFacet: toggleFacet,
              onClearFacet: clearFacet,
            }))))),
          h("tbody", null,
            pageRows.map((c) => {
              const linked = linkedTo(c.code);
              return h("tr", { key: c.code, className: "row-click", onClick: () => setSel(c.code) },
                h("td", null, h(Mono, { copy: true, className: "code-strong" }, c.code)),
                h("td", null, c.name),
                h("td", null, h(Mono, { className: "dim" }, c.system)),
                h("td", null, c.unit === "—" ? h("span", { className: "dim" }, "—") : h("span", { className: "tag" }, c.unit)),
                h("td", null, h("span", { className: "tag" + (c.cls === "CUSTOM" ? " tag-accent" : "") }, c.cls)),
                h("td", null, linked.length || c.linkedBiomarkers?.length
                  ? h("span", { className: "tags" }, linked.length ? linked.map((b) => h("span", { className: "tag tag-accent", key: b.id }, b.name)) : c.linkedBiomarkers.map((name) => h("span", { className: "tag tag-accent", key: name }, name)))
                  : h("span", { className: "dim" }, "— unlinked —")),
                h("td", null, dbStatusPill(c.status)));
            }),
            !rows.length && h("tr", null, h("td", { colSpan: 7 }, h(Empty, { title: "No matching codes", sub: "Adjust your search or class filter." })))))),
      h("div", { className: "pager" },
        h(Button, { variant: "ghost", size: "sm", icon: "chevronL", disabled: safePage <= 1, onClick: () => setPage((p) => Math.max(1, p - 1)) }, "Previous"),
        h("span", { className: "pager-status" }, "Page ", safePage, " of ", pageCount),
        h(Button, { variant: "ghost", size: "sm", iconRight: "chevronR", disabled: safePage >= pageCount, onClick: () => setPage((p) => Math.min(pageCount, p + 1)) }, "Next"))),
    h(LoincDrawer, { code: sel, biomarkers, api, loincCodes, onClose: () => setSel(null) }),
    h(CustomLoincModal, { open: adding, existing: loincCodes, onClose: () => setAdding(false), onCreate: (c) => { api.addLoinc(c); setAdding(false); } }));
}

function LoincDrawer({ code, biomarkers, api, loincCodes, onClose }) {
  const [pick, setPick] = useState("");
  const [detail, setDetail] = useState(null);
  useEffect(() => {
    let cancelled = false;
    if (!code) {
      setDetail(null);
      return;
    }
    TAPI.localizedLoinc(code, "nl-BE").then((data) => {
      if (!cancelled) setDetail(data);
    }).catch(() => {
      if (!cancelled) setDetail(null);
    });
    return () => { cancelled = true; };
  }, [code]);
  if (!code) return h(Drawer, { open: false, onClose });
  const c = (loincCodes || []).find((x) => x.code === code) || R.loincByCode(code) || {};
  const linked = biomarkers.filter((b) => b.loinc.includes(code));
  const available = biomarkers.filter((b) => !b.loinc.includes(code));
  const groups = detail ? (detail.groups || []).map((g) => ({ code: g.group_id, name: g.name || g.description || g.group_id, members: [] })) : R.loincGroupsFor(code);
  const intl = detail ? (detail.linguistic_variants || []).map((v) => ({ locale: v.locale, lang: v.language || v.locale, name: v.display_name || v.long_common_name || v.short_name || v.component })) : R.loincIntl(code);
  return h(Drawer, { open: true, onClose, width: 600, title: c.name || code,
    sub: h(React.Fragment, null,
      h(Mono, { copy: true, className: "code-strong" }, code),
      h("span", { className: "dim" }, " · ", c.cls, " · ", c.system)) },
    h("div", { className: "refbox" },
      h("div", null, h("p", { className: "refsec-title" }, "LOINC attributes"),
        h("div", { className: "meta-grid" },
          h("div", { className: "meta-row" }, h("span", { className: "meta-k" }, "Component"), h("span", { className: "meta-v" }, c.component)),
          h("div", { className: "meta-row" }, h("span", { className: "meta-k" }, "Property"), h("span", { className: "meta-v mono" }, c.property)),
          h("div", { className: "meta-row" }, h("span", { className: "meta-k" }, "System"), h("span", { className: "meta-v mono" }, c.system)),
          h("div", { className: "meta-row" }, h("span", { className: "meta-k" }, "Example units"), h("span", { className: "meta-v" }, c.unit)))),

      h("div", { className: "refsec" },
        h("div", { className: "refsec-head" },
          h("p", { className: "refsec-title" }, "LOINC groups"),
          h("span", { className: "toolbar-count" }, groups.length, " group", groups.length === 1 ? "" : "s")),
        groups.length
          ? h("div", { className: "link-list" }, groups.map((g) => h("div", { className: "link-item", key: g.code },
              h("div", { className: "link-item-main" },
                h("span", { className: "link-t" }, g.name),
                h("span", { className: "link-s" }, h(Mono, { copy: true }, g.code), g.members.length ? " · " + g.members.length + " members" : "")),
              h("button", { className: "link-rm", title: "Group member browsing is not enabled yet", onClick: () => {} }, h(Icon, { name: "external", size: 14 })))))
          : h("p", { className: "dim", style: { fontSize: "12.5px", margin: 0 } }, "This term is not a member of any parent group.")),

      h("div", { className: "refsec" },
        h("div", { className: "refsec-head" },
          h("p", { className: "refsec-title" }, "Linguistic variants"),
          h("span", { className: "toolbar-count" }, intl.length, " language", intl.length === 1 ? "" : "s")),
        intl.length
          ? h("div", { className: "intl-list" },
              h("div", { className: "intl-item" },
                h("span", { className: "intl-flag" }, "🇬🇧"),
                h("div", { className: "intl-main" }, h("span", { className: "intl-name" }, c.name),
                  h("span", { className: "intl-lang" }, "English", h(Mono, { className: "dim" }, "en-US"), h("span", { className: "tag tag-accent" }, "primary")))),
              intl.map((t) => h("div", { className: "intl-item", key: t.locale },
                h("span", { className: "intl-flag" }, LOCALE_FLAG[t.locale] || "🌐"),
                h("div", { className: "intl-main" }, h("span", { className: "intl-name" }, t.name),
                  h("span", { className: "intl-lang" }, t.lang, h(Mono, { className: "dim" }, t.locale))))))
          : h("p", { className: "dim", style: { fontSize: "12.5px", margin: 0 } }, "No linguistic variants loaded for this code in the current release.")),

      h("div", { className: "refsec" },
        h("div", { className: "refsec-head" },
          h("p", { className: "refsec-title" }, "Linked biomarkers"),
          h("span", { className: "toolbar-count" }, linked.length, " linked")),
        linked.length
          ? h("div", { className: "link-list" }, linked.map((b) => h("div", { className: "link-item", key: b.id },
              h("div", { className: "link-item-main" },
                h("span", { className: "link-t" }, b.name, h("span", { className: "tag" }, b.unit)),
                h("span", { className: "link-s" }, b.specimen, " · ", b.loinc.length, " LOINC code", b.loinc.length === 1 ? "" : "s")),
              h("button", { className: "link-rm", title: "Unlink biomarker", onClick: () => api.unlinkLoinc(b.id, code) }, h(Icon, { name: "x", size: 15 })))))
          : h(Empty, { icon: "link", title: "No biomarker linked", sub: "Values for this code stay un-interpreted until linked to a biomarker." }),
        h("div", { className: "link-add" },
          h(Select, { value: pick, onChange: setPick, options: [{ value: "", label: available.length ? "Link a biomarker…" : "All biomarkers linked" }, ...available.map((b) => ({ value: b.id, label: b.name }))] }),
          h(Button, { variant: "primary", icon: "link", disabled: !pick, onClick: () => { if (pick) { api.linkLoinc(pick, code); setPick(""); } } }, "Link")))));
}

const LOCALE_FLAG = { "nl-NL": "🇳🇱", "fr-FR": "🇫🇷", "de-DE": "🇩🇪", "es-ES": "🇪🇸", "nl-BE": "🇧🇪", "fr-BE": "🇧🇪", "it-IT": "🇮🇹" };

/* ---- Biomarker dictionary ------------------------------------------------ */
function BiomarkerPanel({ biomarkers, api, loincCodes }) {
  const toast = useToast();
  const [q, setQ] = useState("");
  const [ph, setPh] = useState("all");
  const [sel, setSel] = useState(null);
  const [creating, setCreating] = useState(false);
  const [exporting, setExporting] = useState(false);
  const [reviewing, setReviewing] = useState(false);
  const rows = biomarkers.filter((b) =>
    (ph === "all" || b.phenotypes.includes(ph)) &&
    (!q || (b.name + " " + b.specimen + " " + b.unit).toLowerCase().includes(q.toLowerCase())));
  const selBm = biomarkers.find((b) => b.id === sel);
  const review = biomarkers.filter((b) => b.confidence < R.BM_REVIEW_THRESHOLD);
  const head = ["Biomarker", "Specimen", "Phenotypes", "Unit", "LOINC", "Status"];
  return h("div", { className: "view" },
    h("div", { className: "stat-grid stat-grid-4" },
      h(Card, { pad: false }, h(Stat, { label: "Biomarkers", value: biomarkers.length, icon: "database" })),
      h(Card, { pad: false }, h(Stat, { label: "Active", value: biomarkers.filter((b) => b.status === "active").length, tone: "ok", icon: "check" })),
      h(Card, { pad: false }, h(Stat, { label: "Draft", value: biomarkers.filter((b) => b.status === "draft").length, icon: "clock" })),
      h("button", { type: "button", className: "stat-clickable" + (review.length ? " stat-flag" : ""), onClick: () => setReviewing(true), title: "Review low-confidence mappings" },
        h(Card, { pad: false }, h(Stat, { label: "Requires review", value: review.length, tone: review.length ? "warn" : "ok", icon: review.length ? "alert" : "check" })))),
    h(Card, { pad: false, title: R.BIOMARKER_DB.name, subtitle: "Curated by " + R.BIOMARKER_DB.curatedBy + " · v" + R.BIOMARKER_DB.version,
      actions: h(React.Fragment, null,
        h(Select, { value: ph, onChange: setPh, options: [{ value: "all", label: "All phenotypes" }, ...R.FM_PHENOTYPES.map((p) => ({ value: p.id, label: p.label }))] }),
        h(Button, { variant: "default", size: "sm", icon: "download", onClick: () => setExporting(true) }, "Export"),
        h(Button, { variant: "primary", size: "sm", icon: "plus", onClick: () => setCreating(true) }, "New biomarker")) },
      h("div", { className: "toolbar" },
        h("div", { className: "search" }, h(Icon, { name: "search", size: 16 }),
          h("input", { className: "search-input", placeholder: "Search biomarker, specimen or unit…", value: q, onChange: (e) => setQ(e.target.value) })),
        h("span", { className: "toolbar-count" }, rows.length, " of ", biomarkers.length)),
      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,
            rows.map((b) => h("tr", { key: b.id, className: "row-click", onClick: () => setSel(b.id) },
              h("td", null, h("span", { style: { fontWeight: 600 } }, b.name)),
              h("td", { className: "dim" }, b.specimen),
              h("td", null, h("span", { className: "tags" },
                b.phenotypes.slice(0, 2).map((p) => h("span", { className: "tag", key: p }, R.phenoLabel(p))),
                b.phenotypes.length > 2 ? h("span", { className: "tag" }, "+" + (b.phenotypes.length - 2)) : null,
                !b.phenotypes.length ? h("span", { className: "dim" }, "—") : null)),
              h("td", null, h("span", { className: "tag" }, b.unit)),
              h("td", null, b.loinc.length
                ? h("span", { className: "mono" }, b.loinc.length)
                : h("span", { className: "warn-ink", style: { fontWeight: 600 } }, "0")),
              h("td", null, b.status === "active" ? h(Pill, { tone: "ok", soft: true }, "active") : h(Pill, { tone: "neutral", soft: true }, "draft")))),
            !rows.length && h("tr", null, h("td", { colSpan: 6 }, h(Empty, { icon: "database", title: "No biomarkers", sub: "Adjust search or phenotype filter." }))))))),
    h(BiomarkerDrawer, { bm: selBm, biomarkers, api, loincCodes, onClose: () => setSel(null) }),
    h(NewBiomarkerModal, { open: creating, existing: biomarkers, onClose: () => setCreating(false), onCreate: async (bm) => { const created = await api.addBiomarker(bm); if (created) { setCreating(false); setSel(created.id); } } }),
    h(ExportBiomarkersModal, { open: exporting, biomarkers, onClose: () => setExporting(false) }),
    h(ReviewQueueModal, { open: reviewing, biomarkers, loincCodes, api, onClose: () => setReviewing(false), onOpenBm: (id) => { setReviewing(false); setSel(id); } }));
}

const RANGE_DEMOS = [
  { key: "male", label: "Male", color: "var(--info)", group: 0 },
  { key: "female", label: "Female", color: "#d6589a", group: 0 },
  { key: "femaleMenopausal", label: "Menopausal", color: "var(--purple)", group: 1 },
  { key: "femalePregnant", label: "Pregnant", color: "var(--accent)", group: 1 },
];

function BiomarkerDrawer({ bm, biomarkers, api, loincCodes, onClose }) {
  const toast = useToast();
  const [pick, setPick] = useState("");
  if (!bm) return h(Drawer, { open: false, onClose });
  const codeList = loincCodes || R.LOINC_CODES;
  const linkedCodes = bm.loinc.map((code) => codeList.find((c) => c.code === code) || { code, name: "(not in loaded release)", system: "—" });
  const availCodes = codeList.filter((c) => !bm.loinc.includes(c.code) && c.status !== "deprecated");

  const rangeRow = (d) => {
    const r = bm.ranges[d.key] || { low: null, high: null };
    const numCell = (bound) => h("td", { className: "rng-num" }, h("span", { className: "rng-cell" },
      h("input", { type: "number", step: "any", className: "input rng-input", value: r[bound] == null ? "" : r[bound],
        placeholder: "—", onChange: (e) => api.setRange(bm.id, d.key, bound, e.target.value) })));
    return h("tr", { key: d.key },
      h("td", null, h("span", { className: "rng-demo" }, h("span", { className: "dot-sex", style: { background: d.color } }), d.label)),
      numCell("low"), numCell("high"),
      h("td", { className: "rng-unit" }, bm.unit));
  };

  return h(Drawer, { open: true, onClose, width: 720, title: bm.name,
    sub: h(React.Fragment, null,
      h(Pill, { tone: bm.status === "active" ? "ok" : "neutral", soft: true }, bm.status),
      h("span", { className: "dim" }, bm.specimen, " · ", bm.loinc.length, " LOINC · ", bm.phenotypes.length, " phenotype", bm.phenotypes.length === 1 ? "" : "s")),
    footer: h("div", { className: "drawer-actions" },
      h(Button, { variant: "primary", icon: "check", onClick: () => { toast("Biomarker saved", "ok"); onClose(); } }, "Save changes"),
      h(Button, { variant: "default", icon: "external", disabled: true, title: "Result drill-down will use the document/result search API once available" }, "View results")) },
    h("div", { className: "refbox" },
      h("div", { className: "td-stats", style: { border: "1px solid var(--line)", borderRadius: "var(--r)", overflow: "hidden" } },
        h("div", { className: "td-stat" }, h("span", { className: "td-num " + (bm.loinc.length ? "" : "warn-ink") }, bm.loinc.length), h("span", { className: "dim" }, "LOINC codes")),
        h("div", { className: "td-stat" }, h("span", { className: "td-num" }, bm.phenotypes.length), h("span", { className: "dim" }, "phenotypes")),
        h("div", { className: "td-stat" }, h("span", { className: "td-num mono" }, bm.unit), h("span", { className: "dim" }, "unit (UCUM)")),
        h("div", { className: "td-stat" }, h("span", { className: "td-num" }, fmtNum(bm.used)), h("span", { className: "dim" }, "results"))),

      !bm.loinc.length && h("div", { className: "ref-banner tone-warn" }, h(Icon, { name: "alert", size: 16 }),
        h("div", null, h("strong", null, "Not linked to any LOINC code."), " Extracted values can't be routed to this biomarker until at least one LOINC code is linked below.")),

      // specimen + unit
      h("div", { className: "form-grid", style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px" } },
        h(Field, { label: "Specimen type" },
          h(Select, { value: bm.specimen, onChange: (v) => api.patch(bm.id, { specimen: v }), options: R.SPECIMENS })),
        h(Field, { label: "Unit (UCUM)", hint: "Canonical unit results are normalized to" },
          h(Select, { value: bm.unit, onChange: (v) => api.patch(bm.id, { unit: v }), options: R.UCUM_UNITS.map((u) => ({ value: u.code, label: u.code + " — " + u.name })) }))),

      // phenotypes
      h("div", { className: "refsec" },
        h("p", { className: "refsec-title" }, "Functional Medicine phenotypes"),
        h("div", { className: "chip-set" },
          R.FM_PHENOTYPES.map((p) => {
            const on = bm.phenotypes.includes(p.id);
            return h("button", { key: p.id, type: "button", className: "chip-tog" + (on ? " on" : ""), onClick: () => api.togglePhenotype(bm.id, p.id) },
              h(Icon, { name: on ? "check" : "plus", size: 13 }), p.label);
          }))),

      // linked loinc
      h("div", { className: "refsec" },
        h("div", { className: "refsec-head" },
          h("p", { className: "refsec-title" }, "Linked LOINC codes"),
          h("span", { className: "toolbar-count" }, bm.loinc.length, " linked")),
        bm.loinc.length
          ? h("div", { className: "link-list" }, linkedCodes.map((c) => h("div", { className: "link-item", key: c.code },
              h("div", { className: "link-item-main" },
                h("span", { className: "link-t" }, h(Mono, { copy: true, className: "code-strong" }, c.code)),
                h("span", { className: "link-s" }, c.name)),
              h("button", { className: "link-rm", title: "Unlink LOINC code", onClick: () => api.unlinkLoinc(bm.id, c.code) }, h(Icon, { name: "x", size: 15 })))))
          : h(Empty, { icon: "link", title: "No LOINC codes linked" }),
        h("div", { className: "link-add" },
          h(Select, { value: pick, onChange: setPick, options: [{ value: "", label: "Link a LOINC code…" }, ...availCodes.map((c) => ({ value: c.code, label: c.code + " — " + c.name }))] }),
          h(Button, { variant: "primary", icon: "link", disabled: !pick, onClick: () => { if (pick) { api.linkLoinc(bm.id, pick); setPick(""); } } }, "Link"))),

      // reference ranges
      h("div", { className: "refsec" },
        h("p", { className: "refsec-title" }, "Reference ranges"),
        h("table", { className: "rng-table" },
          h("thead", null, h("tr", null,
            h("th", null, "Population"), h("th", { className: "rng-num" }, "Min"), h("th", { className: "rng-num" }, "Max"), h("th", null, "Unit"))),
          h("tbody", null,
            RANGE_DEMOS.filter((d) => d.group === 0).map(rangeRow),
            h("tr", { className: "rng-sub" }, h("td", { colSpan: 4, className: "rng-grouplbl" }, "Female-specific")),
            RANGE_DEMOS.filter((d) => d.group === 1).map(rangeRow))))));
}

function UcumPanel({ db, units, live, onSearch }) {
  const toast = useToast();
  const [q, setQ] = useState("");
  const rows = units.filter((u) => !q || (u.code + " " + u.name + " " + u.dim).toLowerCase().includes(q.toLowerCase()));
  useEffect(() => {
    if (live.status !== "live") return;
    const timer = setTimeout(() => onSearch({ query: q }), 250);
    return () => clearTimeout(timer);
  }, [q, live.status]);
  const head = ["Code", "Unit name", "Dimension", "Canonical", "Conversion factor", "In use", "Status"];
  return h("div", { className: "view" },
    h(DbInfoCard, { db, kind: "ucum" }),
    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 unit code, name or dimension…", value: q, onChange: (e) => setQ(e.target.value) })),
        h("span", { className: "toolbar-count" }, rows.length, " of ", units.length, " loaded"),
        h(Button, { variant: "default", size: "sm", icon: "plus", disabled: true, title: "Custom UCUM persistence is not enabled yet" }, "Custom unit")),
      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,
            rows.map((u) => h("tr", { key: u.code },
              h("td", null, h(Mono, { copy: true, className: "code-strong" }, u.code)),
              h("td", null, u.name),
              h("td", { className: "dim" }, u.dim),
              h("td", null, h("span", { className: "tag" }, u.canonical)),
              h("td", { className: "mono dim" }, u.factor),
              h("td", { className: "mono" }, u.used ? fmtNum(u.used) : h("span", { className: "dim" }, "0")),
              h("td", null, dbStatusPill(u.status)))),
            !rows.length && h("tr", null, h("td", { colSpan: 7 }, h(Empty, { title: "No matching units", sub: "Adjust your search." }))))))));
}

/* ======================================================================== */
/* LABORATORIES & TEST TYPES                                                 */
/* ======================================================================== */
function LaboratoriesView() {
  const [tab, setTab] = useState("labs");
  const tabs = [
    { key: "labs", label: "Laboratories", count: R.LABS.length },
    { key: "panels", label: "Test types", count: R.TEST_PANELS.length },
  ];
  return h("div", { className: "view" },
    h(PageHead, { title: "Laboratories & test types",
      sub: "Document authors the pipeline recognizes, and the panels their results map to — the basis of extraction confidence" }),
    h(Tabs, { tabs, active: tab, onChange: setTab }),
    h("div", { className: "tabbody" },
      tab === "labs" ? h(LabsPanel, null) : h(PanelsPanel, null)));
}

function confTone(status) { return R.LAB_STATUS[status].tone; }

function LabsPanel() {
  const [labs, setLabs] = useState(R.LABS);
  const [sel, setSel] = useState(null);
  const [filter, setFilter] = useState("all");
  const toast = useToast();
  const counts = {
    supported: labs.filter((l) => l.status === "supported").length,
    partial: labs.filter((l) => l.status === "partial").length,
    unsupported: labs.filter((l) => l.status === "unsupported").length,
  };
  const meanConf = (labs.reduce((a, l) => a + l.confidence, 0) / labs.length).toFixed(1);
  const rows = labs.filter((l) => filter === "all" || l.status === filter);
  const selLab = labs.find((l) => l.id === sel);

  const promote = (id) => {
    setLabs((x) => x.map((l) => l.id === id ? { ...l, status: "supported", confidence: Math.max(l.confidence, 95.0), profile: l.profile || (l.id.replace("lab_", "") + "-v1"), templates: Math.max(1, l.templates), unrecognized: 0 } : l));
    toast("Extraction profile created · author promoted to supported", "ok");
  };

  const head = ["Laboratory", "Jurisdiction", "Formats", "Profile", "Templates", "Extraction confidence", "Docs", "Status"];
  return h("div", { className: "view" },
    h("div", { className: "ref-banner" }, h(Icon, { name: "beaker", size: 16, className: "dim" }),
      h("div", null, "When a document's author has a tuned profile and a recognized template, observations are extracted ",
        h("strong", null, "structurally"), " with high confidence. ",
        "Unrecognized authors fall back to generic LLM extraction — lower confidence and a higher share of documents routed to manual review.")),
    h("div", { className: "stat-grid stat-grid-4" },
      h(Card, { pad: false }, h(Stat, { label: "Supported", value: counts.supported, tone: "ok", icon: "check" })),
      h(Card, { pad: false }, h(Stat, { label: "Partial", value: counts.partial, tone: "warn", icon: "alert" })),
      h(Card, { pad: false }, h(Stat, { label: "Unsupported", value: counts.unsupported, tone: "bad", icon: "x" })),
      h(Card, { pad: false }, h(Stat, { label: "Mean confidence", value: meanConf, unit: "%", icon: "activity" }))),
    h(Card, { pad: false, title: "Recognized laboratories", subtitle: "Document authors and their extraction profiles",
      actions: h(React.Fragment, null,
        h(Select, { value: filter, onChange: setFilter, options: [{ value: "all", label: "All statuses" }, { value: "supported", label: "Supported" }, { value: "partial", label: "Partial" }, { value: "unsupported", label: "Unsupported" }] }),
        h(Button, { variant: "primary", size: "sm", icon: "plus", onClick: () => toast("Add laboratory (mock)") }, "Add laboratory")) },
      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,
            rows.map((l) => {
              const m = R.LAB_STATUS[l.status];
              return h("tr", { key: l.id, className: "row-click", onClick: () => setSel(l.id) },
                h("td", null, h("span", { className: "ref-cell" }, h("span", { className: "ref-flag" }, l.flag),
                  h("span", null, l.name, h("div", { className: "ref-sub" }, l.country)))),
                h("td", null, h(Mono, { className: "dim" }, l.jurisdiction)),
                h("td", null, h("span", { className: "tags" }, l.formats.map((f) => h("span", { className: "tag", key: f }, f)))),
                h("td", null, l.profile ? h(Mono, null, l.profile) : h("span", { className: "dim" }, "— none —")),
                h("td", { className: "mono" }, l.templates, l.unrecognized ? h("span", { className: "warn-ink" }, " +" + l.unrecognized + " new") : null),
                h("td", null, h("div", { className: "conf-cell" },
                  h(Bar, { value: l.confidence, max: 100, tone: confTone(l.status), height: 6 }),
                  h("span", { className: "conf-pct" }, l.confidence.toFixed(1) + "%"))),
                h("td", { className: "mono" }, fmtNum(l.docs)),
                h("td", null, h(Pill, { tone: m.tone, soft: l.status !== "supported" }, m.label)));
            }),
            !rows.length && h("tr", null, h("td", { colSpan: 8 }, h(Empty, { icon: "beaker", title: "No laboratories", sub: "No authors match this filter." }))))))),
    h(LabDrawer, { lab: selLab, onClose: () => setSel(null), onPromote: promote }));
}

function LabDrawer({ lab, onClose, onPromote }) {
  const toast = useToast();
  if (!lab) return h(Drawer, { open: false, onClose });
  const m = R.LAB_STATUS[lab.status];
  return h(Drawer, { open: true, onClose, width: 640, title: lab.name,
    sub: h(React.Fragment, null,
      h(Pill, { tone: m.tone, soft: lab.status !== "supported" }, m.label),
      h("span", { className: "dim" }, lab.flag, " ", lab.country, " · ", h(Mono, null, lab.jurisdiction))),
    footer: h("div", { className: "drawer-actions" },
      lab.status === "unsupported" && h(Button, { variant: "primary", icon: "sparkles", onClick: () => { onPromote(lab.id); onClose(); } }, "Create extraction profile"),
      lab.status === "partial" && h(Button, { variant: "primary", icon: "upload", onClick: () => toast("Upload sample to extend profile (mock)") }, "Extend profile"),
      h(Button, { variant: "default", icon: "documents", onClick: () => toast("Open author documents (mock)") }, "View documents")) },
    h("div", { className: "refbox" },
      h("div", { className: "td-stats", style: { border: "1px solid var(--line)", borderRadius: "var(--r)", overflow: "hidden" } },
        h("div", { className: "td-stat" }, h("span", { className: "td-num " + (m.tone === "ok" ? "ok-ink" : m.tone === "bad" ? "bad-ink" : "") }, lab.confidence.toFixed(1) + "%"), h("span", { className: "dim" }, "confidence")),
        h("div", { className: "td-stat" }, h("span", { className: "td-num" }, fmtNum(lab.docs)), h("span", { className: "dim" }, "documents")),
        h("div", { className: "td-stat" }, h("span", { className: "td-num" }, lab.templates), h("span", { className: "dim" }, "templates")),
        h("div", { className: "td-stat" }, h("span", { className: "td-num " + (lab.reviewRate > 10 ? "bad-ink" : "") }, lab.reviewRate + "%"), h("span", { className: "dim" }, "manual review"))),

      lab.status === "unsupported" && h("div", { className: "ref-banner tone-bad" }, h(Icon, { name: "alert", size: 16 }),
        h("div", null, h("strong", null, "No extraction profile."), " Documents from this author use generic LLM extraction (~", lab.confidence.toFixed(0),
          "% confidence). Entity extraction may be incomplete, so ~", lab.reviewRate, "% of these documents are routed to manual review. Create a profile from sample documents to recognize their layout and lift confidence.")),
      lab.status === "partial" && h("div", { className: "ref-banner tone-warn" }, h(Icon, { name: "alert", size: 16 }),
        h("div", null, h("strong", null, lab.unrecognized + " new layout" + (lab.unrecognized === 1 ? "" : "s") + " unrecognized."),
          " Values from these templates fall back to generic extraction and are flagged for review. Add a sample to extend ", h(Mono, null, lab.profile), ".")),
      lab.status === "supported" && h("div", { className: "ref-banner tone-ok" }, h(Icon, { name: "check", size: 16 }),
        h("div", null, h("strong", null, "Structured extraction active."), " All known templates recognized — observations map directly to LOINC/UCUM.")),

      h("div", null, h("p", { className: "refsec-title" }, "Extraction profile"),
        h("div", { className: "meta-grid" },
          h("div", { className: "meta-row" }, h("span", { className: "meta-k" }, "Profile"), h("span", { className: "meta-v mono" }, lab.profile || "none")),
          h("div", { className: "meta-row" }, h("span", { className: "meta-k" }, "Formats"), h("span", { className: "meta-v" }, lab.formats.join(", "))),
          h("div", { className: "meta-row" }, h("span", { className: "meta-k" }, "Recognized templates"), h("span", { className: "meta-v mono" }, lab.templates)),
          h("div", { className: "meta-row" }, h("span", { className: "meta-k" }, "Last document"), h("span", { className: "meta-v" }, fmtAgo(R.ago(lab.lastMin * R.MIN)))))),

      h("div", null, h("p", { className: "refsec-title" }, "Test panels covered"),
        lab.panels.length
          ? h("span", { className: "tags" }, lab.panels.map((k) => h("span", { className: "tag tag-accent", key: k }, R.panelName(k))))
          : h("span", { className: "dim" }, "No panels mapped — extraction relies on generic field detection."))));
}

function PanelsPanel() {
  const [sel, setSel] = useState(null);
  const toast = useToast();
  const selPanel = R.TEST_PANELS.find((p) => p.key === sel);
  const head = ["Panel", "Category", "LOINC codes", "Key analytes", "Supported labs", "Status"];
  return h("div", { className: "view" },
    h("div", { className: "ref-banner" }, h(Icon, { name: "hash", size: 16, className: "dim" }),
      h("div", null, "Each panel pins its analytes to LOINC codes and UCUM units, with reference ranges. Extraction uses these maps to recognize and normalize results regardless of how a lab labels them.")),
    h(Card, { pad: false, title: "Supported test types", subtitle: R.TEST_PANELS.length + " panels mapped to LOINC / UCUM",
      actions: h(Button, { variant: "primary", size: "sm", icon: "plus", onClick: () => toast("New test panel (mock)") }, "New panel") },
      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,
            R.TEST_PANELS.map((p) => h("tr", { key: p.key, className: "row-click", onClick: () => setSel(p.key) },
              h("td", null, h("span", { style: { fontWeight: 600 } }, p.name)),
              h("td", { className: "dim" }, p.category),
              h("td", { className: "mono" }, p.analytes.length),
              h("td", null, h("span", { className: "tags" },
                p.analytes.slice(0, 3).map((a) => h("span", { className: "tag", key: a.loinc }, a.analyte)),
                p.analytes.length > 3 ? h("span", { className: "tag" }, "+" + (p.analytes.length - 3)) : null)),
              h("td", { className: "mono" }, p.labs),
              h("td", null, p.status === "active" ? h(Pill, { tone: "ok", soft: true }, "active") : h(Pill, { tone: "neutral", soft: true }, "draft")))))))),
    h(PanelDrawer, { panel: selPanel, onClose: () => setSel(null) }));
}

function PanelDrawer({ panel, onClose }) {
  const toast = useToast();
  if (!panel) return h(Drawer, { open: false, onClose });
  return h(Drawer, { open: true, onClose, width: 640, title: panel.name,
    sub: h(React.Fragment, null,
      h(Pill, { tone: panel.status === "active" ? "ok" : "neutral", soft: true }, panel.status),
      h("span", { className: "dim" }, panel.category, " · ", panel.analytes.length, " analytes · ", panel.labs, " labs")),
    footer: h("div", { className: "drawer-actions" },
      h(Button, { variant: "primary", icon: "plus", onClick: () => toast("Add analyte (mock)") }, "Add analyte"),
      h(Button, { variant: "default", icon: "external", onClick: () => toast("Edit panel (mock)") }, "Edit panel")) },
    h("div", { className: "refbox" },
      h("p", { className: "refsec-title" }, "Analyte → LOINC → UCUM mapping"),
      h("div", { className: "table-wrap" },
        h("table", { className: "table table-tight" },
          h("thead", null, h("tr", null, ["Analyte", "LOINC", "Unit (UCUM)", "Reference range"].map((c) => h("th", { key: c }, c)))),
          h("tbody", null,
            panel.analytes.map((a) => h("tr", { key: a.loinc },
              h("td", null, a.analyte),
              h("td", null, h(Mono, { copy: true, className: "code-strong" }, a.loinc)),
              h("td", null, h("span", { className: "tag" }, a.unit)),
              h("td", { className: "mono dim" }, fmtRef(a)))))))));
}

/* ======================================================================== */
/* MODALS — New biomarker · Custom LOINC code · Export                       */
/* ======================================================================== */
const LOINC_PROPERTIES = ["MCnc", "SCnc", "NCnc", "ACnc", "CCnc", "MFr", "VFr", "Type", "RelTime", "Nom"];
const LOINC_SYSTEMS = ["Ser/Plas", "Bld", "Plas", "Urine", "Saliva", "Stool", "CSF", "PPP"];

function NewBiomarkerModal({ open, existing, onClose, onCreate }) {
  const [name, setName] = useState("");
  const [specimen, setSpecimen] = useState(R.SPECIMENS[0]);
  const [unit, setUnit] = useState("mg/dL");
  const [status, setStatus] = useState("draft");
  const [phenotypes, setPhenotypes] = useState([]);
  useEffect(() => { if (open) { setName(""); setSpecimen(R.SPECIMENS[0]); setUnit("mg/dL"); setStatus("draft"); setPhenotypes([]); } }, [open]);
  const dup = existing.some((b) => b.name.trim().toLowerCase() === name.trim().toLowerCase());
  const valid = name.trim() && !dup;
  const submit = () => {
    if (!valid) return;
    const id = "bm_" + name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").slice(0, 24) + "_" + Math.random().toString(36).slice(2, 5);
    const blank = { low: null, high: null };
    onCreate({ id, name: name.trim(), specimen, unit, status, phenotypes: [...phenotypes], loinc: [], used: 0,
      ranges: { male: { ...blank }, female: { ...blank }, femaleMenopausal: { ...blank }, femalePregnant: { ...blank } } });
  };
  const toggle = (p) => setPhenotypes((xs) => xs.includes(p) ? xs.filter((x) => x !== p) : [...xs, p]);
  return h(Modal, { open, onClose, title: "New biomarker", width: 560,
    footer: h(React.Fragment, null,
      h(Button, { variant: "ghost", onClick: onClose }, "Cancel"),
      h(Button, { variant: "primary", icon: "plus", disabled: !valid, onClick: submit }, "Create biomarker")) },
    h("div", { className: "mform" },
      h(Field, { label: "Biomarker name", hint: dup ? "A biomarker with this name already exists." : "Clinical concept, e.g. “Vitamin B12, serum”" },
        h("input", { className: "input", autoFocus: true, value: name, placeholder: "e.g. Ferritin", onChange: (e) => setName(e.target.value) })),
      h("div", { className: "mform-2" },
        h(Field, { label: "Specimen type" }, h(Select, { value: specimen, onChange: setSpecimen, options: R.SPECIMENS })),
        h(Field, { label: "Unit (UCUM)" }, h(Select, { value: unit, onChange: setUnit, options: R.UCUM_UNITS.map((u) => ({ value: u.code, label: u.code + " — " + u.name })) }))),
      h(Field, { label: "Status" },
        h(Select, { value: status, onChange: setStatus, options: [{ value: "draft", label: "Draft — not yet used for interpretation" }, { value: "active", label: "Active — used in results" }] })),
      h(Field, { label: "Functional Medicine phenotypes" },
        h("div", { className: "chip-set" }, R.FM_PHENOTYPES.map((p) => {
          const on = phenotypes.includes(p.id);
          return h("button", { key: p.id, type: "button", className: "chip-tog" + (on ? " on" : ""), onClick: () => toggle(p.id) },
            h(Icon, { name: on ? "check" : "plus", size: 13 }), p.label);
        }))),
      h("p", { className: "mform-note" }, h(Icon, { name: "sparkles", size: 14 }),
        "Link LOINC codes and set reference ranges in the next step — the biomarker opens for editing right after you create it.")));
}

function CustomLoincModal({ open, existing, onClose, onCreate }) {
  const [code, setCode] = useState("ENO-");
  const [name, setName] = useState("");
  const [component, setComponent] = useState("");
  const [property, setProperty] = useState("MCnc");
  const [system, setSystem] = useState("Ser/Plas");
  const [unit, setUnit] = useState("mg/dL");
  useEffect(() => { if (open) { setCode("ENO-"); setName(""); setComponent(""); setProperty("MCnc"); setSystem("Ser/Plas"); setUnit("mg/dL"); } }, [open]);
  const dup = existing.some((c) => c.code.trim().toLowerCase() === code.trim().toLowerCase());
  const valid = code.trim() && code.trim() !== "ENO-" && name.trim() && !dup;
  const submit = () => {
    if (!valid) return;
    onCreate({ code: code.trim(), name: name.trim(), component: component.trim() || name.trim(), property, system, scale: "Qn", unit, cls: "CUSTOM", used: 0, status: "custom" });
  };
  return h(Modal, { open, onClose, title: "Add custom code", width: 560,
    footer: h(React.Fragment, null,
      h(Button, { variant: "ghost", onClick: onClose }, "Cancel"),
      h(Button, { variant: "primary", icon: "plus", disabled: !valid, onClick: submit }, "Add code")) },
    h("div", { className: "mform" },
      h("p", { className: "mform-note" }, h(Icon, { name: "alert", size: 14 }),
        "Custom codes are local to this tenant and won't sync with the Regenstrief release. Use an ", h("strong", null, "ENO-"), " prefix so they're easy to spot."),
      h("div", { className: "mform-2" },
        h(Field, { label: "Code", hint: dup ? "This code already exists." : "Local identifier" },
          h("input", { className: "input mono", value: code, onChange: (e) => setCode(e.target.value) })),
        h(Field, { label: "Class" }, h("input", { className: "input", value: "CUSTOM", disabled: true }))),
      h(Field, { label: "Long common name" },
        h("input", { className: "input", value: name, placeholder: "e.g. Omega-3 index [Mass fraction] in Blood", onChange: (e) => setName(e.target.value) })),
      h(Field, { label: "Component", hint: "What is measured (defaults to the name)" },
        h("input", { className: "input", value: component, placeholder: "e.g. Omega-3 index", onChange: (e) => setComponent(e.target.value) })),
      h("div", { className: "mform-2" },
        h(Field, { label: "Property" }, h(Select, { value: property, onChange: setProperty, options: LOINC_PROPERTIES })),
        h(Field, { label: "System (specimen)" }, h(Select, { value: system, onChange: setSystem, options: LOINC_SYSTEMS }))),
      h(Field, { label: "Example units (UCUM)" },
        h(Select, { value: unit, onChange: setUnit, options: R.UCUM_UNITS.map((u) => ({ value: u.code, label: u.code + " — " + u.name })) }))));
}

function bmRangeStr(r) { if (r.low != null && r.high != null) return r.low + "–" + r.high; if (r.high != null) return "<" + r.high; if (r.low != null) return ">" + r.low; return ""; }
const EXPORT_COLS = ["Biomarker", "Specimen", "Unit (UCUM)", "Phenotypes", "LOINC codes", "Status",
  "Male min", "Male max", "Female min", "Female max", "Menopausal min", "Menopausal max", "Pregnant min", "Pregnant max"];
function bmRow(b) {
  const r = b.ranges, n = (v) => (v == null ? "" : v);
  return [b.name, b.specimen, b.unit, b.phenotypes.map(R.phenoLabel).join("; "), b.loinc.join("; "), b.status,
    n(r.male.low), n(r.male.high), n(r.female.low), n(r.female.high),
    n(r.femaleMenopausal.low), n(r.femaleMenopausal.high), n(r.femalePregnant.low), n(r.femalePregnant.high)];
}
function downloadBlob(filename, mime, content) {
  const blob = new Blob([content], { type: mime });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url; a.download = filename;
  document.body.appendChild(a); a.click(); a.remove();
  setTimeout(() => URL.revokeObjectURL(url), 1500);
}
function exportCSV(biomarkers) {
  const esc = (v) => { const s = String(v); return /[",\n]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s; };
  const lines = [EXPORT_COLS.map(esc).join(","), ...biomarkers.map((b) => bmRow(b).map(esc).join(","))];
  downloadBlob("eno-biomarkers.csv", "text/csv;charset=utf-8", "\uFEFF" + lines.join("\r\n"));
}
function exportXLS(biomarkers) {
  const esc = (v) => String(v).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  const th = EXPORT_COLS.map((c) => "<th>" + esc(c) + "</th>").join("");
  const trs = biomarkers.map((b) => "<tr>" + bmRow(b).map((v) => "<td>" + esc(v) + "</td>").join("") + "</tr>").join("");
  const html = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel"><head><meta charset="utf-8"></head><body><table border="1"><thead><tr>' + th + "</tr></thead><tbody>" + trs + "</tbody></table></body></html>";
  downloadBlob("eno-biomarkers.xls", "application/vnd.ms-excel", html);
}

function ExportBiomarkersModal({ open, biomarkers, onClose }) {
  const toast = useToast();
  const [fmt, setFmt] = useState("csv");
  useEffect(() => { if (open) setFmt("csv"); }, [open]);
  const run = () => {
    if (fmt === "csv") exportCSV(biomarkers); else exportXLS(biomarkers);
    toast("Exported " + biomarkers.length + " biomarkers · " + fmt.toUpperCase(), "ok");
    onClose();
  };
  const opt = (key, icon, t, s) => h("button", { type: "button", className: "fmt-opt" + (fmt === key ? " on" : ""), onClick: () => setFmt(key) },
    h(Icon, { name: icon, size: 18 }), h("div", null, h("div", { className: "fmt-opt-t" }, t), h("div", { className: "fmt-opt-s" }, s)));
  return h(Modal, { open, onClose, title: "Export biomarkers", width: 500,
    footer: h(React.Fragment, null,
      h(Button, { variant: "ghost", onClick: onClose }, "Cancel"),
      h(Button, { variant: "primary", icon: "download", onClick: run }, "Download " + fmt.toUpperCase())) },
    h("div", { className: "mform" },
      h(Field, { label: "Format" },
        h("div", { className: "fmt-opts" },
          opt("csv", "sheet", "CSV", "Comma-separated · opens anywhere"),
          opt("xls", "sheet", "Excel", "Formatted .xls workbook"))),
      h(Field, { label: "Includes " + biomarkers.length + " biomarkers · " + EXPORT_COLS.length + " columns" },
        h("div", { className: "export-cols" }, EXPORT_COLS.map((c) => h("span", { className: "tag", key: c }, c))))));
}

function ReviewItem({ bm, loincCodes, api, onOpen }) {
  const [pick, setPick] = useState("");
  const codeList = loincCodes || R.LOINC_CODES;
  const avail = codeList.filter((c) => !bm.loinc.includes(c.code) && c.status !== "deprecated");
  const tone = bm.confidence < 60 ? "bad" : "warn";
  return h("div", { className: "rev-item" },
    h("div", { className: "rev-head" },
      h("div", { style: { minWidth: 0 } },
        h("span", { className: "rev-name" }, bm.name),
        h("div", { className: "rev-sub" }, bm.specimen, " · ", h("span", { className: "tag" }, bm.unit),
          bm.status === "draft" ? h(Pill, { tone: "neutral", soft: true }, "draft") : null)),
      h("div", { className: "conf-cell" },
        h(Bar, { value: bm.confidence, max: 100, tone, height: 6 }),
        h("span", { className: "conf-pct " + (tone === "bad" ? "bad-ink" : "warn-ink") }, bm.confidence.toFixed(1) + "%"))),
    bm.loinc.length
      ? h("div", { className: "rev-codes" }, h("span", { className: "dim", style: { fontSize: "11.5px" } }, "Linked:"),
          bm.loinc.map((code) => h("span", { className: "tag tag-accent rev-chip", key: code }, code,
            h("button", { className: "rev-chip-x", title: "Unlink", onClick: () => api.unlinkLoinc(bm.id, code) }, h(Icon, { name: "x", size: 11 })))))
      : h("span", { className: "rev-empty" }, "No LOINC code linked — extracted values can't be interpreted yet."),
    h("div", { className: "rev-actions" },
      h(Select, { value: pick, onChange: setPick, options: [{ value: "", label: "Link a LOINC code…" }, ...avail.map((c) => ({ value: c.code, label: c.code + " — " + c.name }))] }),
      h(Button, { variant: "default", icon: "link", disabled: !pick, onClick: () => { if (pick) { api.linkLoinc(bm.id, pick); setPick(""); } } }, "Link"),
      h(Button, { variant: "primary", icon: "check", disabled: !bm.loinc.length, title: bm.loinc.length ? "" : "Link at least one LOINC code first", onClick: () => api.markReviewed(bm.id) }, "Mark reviewed")));
}

function ReviewQueueModal({ open, biomarkers, loincCodes, api, onClose, onOpenBm }) {
  const flagged = biomarkers.filter((b) => b.confidence < R.BM_REVIEW_THRESHOLD)
    .sort((a, b) => a.confidence - b.confidence);
  return h(Modal, { open, onClose, title: "Biomarkers requiring review", width: 660,
    footer: h(React.Fragment, null,
      h("span", { className: "toolbar-count", style: { marginRight: "auto" } }, flagged.length, " below ", R.BM_REVIEW_THRESHOLD, "% confidence"),
      h(Button, { variant: "default", onClick: onClose }, "Close")) },
    h("div", { className: "mform" },
      h("p", { className: "mform-note" }, h(Icon, { name: "alert", size: 14 }),
        "These biomarkers were auto-mapped with confidence below ", h("strong", null, R.BM_REVIEW_THRESHOLD + "%"),
        ". Confirm or correct each LOINC mapping, then mark it reviewed to clear the flag."),
      flagged.length
        ? h("div", { className: "rev-list" }, flagged.map((b) => h(ReviewItem, { key: b.id, bm: b, loincCodes, api, onOpen: () => onOpenBm(b.id) })))
        : h(Empty, { icon: "check", title: "Review queue clear", sub: "Every biomarker is mapped above the confidence threshold." })));
}

Object.assign(window, { TerminologyView, LaboratoriesView });
