/* Eno.Health Console — user management.
   Model: identity (type) + tenant membership (role) + practitioner profile +
   patient↔practitioner assignments. Sub-tabs: All / Practitioners / Patients /
   Invitations. System accounts are auto-provisioned, owner, and read-only in UI.
   Mutates window.ENO.USERS in place. */
const U = window.ENO;

const USER_TYPES = [
  { value: "practitioner", label: "Practitioner" },
  { value: "patient", label: "Patient" },
  { value: "system", label: "System" },
];
const CREATE_TYPES = USER_TYPES.filter((t) => t.value !== "system");
const TENANT_ROLES = [
  { value: "owner", label: "Owner" },
  { value: "regular", label: "Regular" },
  { value: "billing", label: "Billing" },
  { value: "read_only", label: "Read-only" },
];
const RELATIONSHIPS = ["Primary", "Physician", "Nutrition", "Coach"];
const LANGUAGES = ["Dutch", "French", "English", "German", "Italian", "Spanish", "Portuguese", "Polish", "Arabic"];
const COUNTRIES = ["Belgium", "Netherlands", "Germany", "France", "Italy", "Spain", "Portugal", "United Kingdom", "Ireland", "United Arab Emirates"];
const GENDERS = ["Female", "Male", "Non-binary", "Prefer not to say"];
const BLOOD_TYPES = ["O+", "O-", "A+", "A-", "B+", "B-", "AB+", "AB-", "Unknown"];
const SMOKER_OPTS = ["Never", "Former", "Yes"];

const uName = (u) => (u.firstname || u.lastname) ? ((u.firstname || "") + " " + (u.lastname || "")).trim() : (u.name || "—");
const uInitials = (u) => uName(u).split(" ").filter(Boolean).map((w) => w[0]).slice(0, 2).join("").toUpperCase() || "?";
const typeLabel = (t) => (USER_TYPES.find((x) => x.value === t) || {}).label || "—";
const typeTone = (t) => (t === "patient" ? "purple" : t === "system" ? "neutral" : "accent");
const roleLabel = (r) => (TENANT_ROLES.find((x) => x.value === r) || {}).label || r;
const STATUS_TONE = { active: "ok", disabled: "neutral", invited: "warn", pending: "info" };
const STATUS_LABEL = { active: "active", disabled: "disabled", invited: "invited", pending: "pending" };
const practitionersIn = (tenantId) => U.USERS.filter((u) => u.tenant === tenantId && u.type === "practitioner" && u.status !== "invited");
function ageFromDob(dob) {
  if (!dob) return null;
  const d = new Date(dob); if (isNaN(d)) return null;
  const now = new Date(U.NOW);
  let a = now.getUTCFullYear() - d.getUTCFullYear();
  const m = now.getUTCMonth() - d.getUTCMonth();
  if (m < 0 || (m === 0 && now.getUTCDate() < d.getUTCDate())) a--;
  return a;
}
let _uidc = 0;
const newUserId = () => "usr_" + Date.now().toString(36) + (_uidc++);

const SOCIALS = [
  { key: "instagram", label: "Instagram", ph: "@handle" },
  { key: "linkedin", label: "LinkedIn", ph: "linkedin.com/in/…" },
  { key: "facebook", label: "Facebook", ph: "facebook.com/…" },
  { key: "tiktok", label: "TikTok", ph: "@handle" },
  { key: "x", label: "X", ph: "@handle" },
  { key: "website", label: "Website", ph: "https://…" },
];
const verifyMethodLabel = (m) => (m === "itsme" ? "itsme" : m === "idnow" ? "IDnow" : m || "");
const docsForUser = (userId) => U.docsForPatient ? U.docsForPatient(userId) : U.DOCUMENTS.filter((d) => d.patient === userId || d.patientId === userId || d.initiatedByUserId === userId);
const interviewsForUser = (userId) => U.interviewsForPatient ? U.interviewsForPatient(userId) : [];
const userAPI = () => window.EnoAdminAPI || null;
const fullNameFrom = (u) => ((u.firstname || u.firstName || "") + " " + (u.lastname || u.lastName || "")).trim();
const normalizeUIUser = (u) => {
  const first = u.firstname || u.firstName || (u.raw && u.raw.first_name) || "";
  const last = u.lastname || u.lastName || (u.raw && u.raw.last_name) || "";
  const tenant = u.tenant || u.tenantId || (u.raw && u.raw.tenant_id) || "";
  return {
    ...u,
    tenant,
    type: u.type || "practitioner",
    status: u.status || "active",
    role: u.role || "regular",
    firstname: first,
    lastname: last,
    name: u.name || (first || last ? (first + " " + last).trim() : u.email || "—"),
    dob: u.dob || u.dateOfBirth || (u.raw && u.raw.date_of_birth) || "",
    linkedin: u.linkedin || u.linkedInUrl || (u.raw && u.raw.linkedin_url) || "",
    social: u.social || u.socialProfiles || (u.raw && u.raw.social_profiles) || {},
    avatar: u.avatar || u.avatarMediaId || (u.raw && u.raw.avatar_media_id) || "",
    assignments: (u.assignments || []).map((a) => ({
      practitionerId: a.practitionerId || a.practitioner_user_id || "",
      practitioner_user_id: a.practitioner_user_id || a.practitionerId || "",
      relationship: a.relationship || "Primary",
    })),
  };
};
const upsertUserCache = (user) => {
  const u = normalizeUIUser(user);
  const i = U.USERS.findIndex((x) => x.id === u.id);
  if (i >= 0) U.USERS[i] = { ...U.USERS[i], ...u };
  else U.USERS.push(u);
  return u;
};
const syncUserCache = (users, scope) => {
  const incoming = (users || []).map(normalizeUIUser);
  const ids = new Set(incoming.map((u) => u.id));
  if (scope && scope.tenant) {
    for (let i = U.USERS.length - 1; i >= 0; i--) if (U.USERS[i].tenant === scope.tenant && !ids.has(U.USERS[i].id)) U.USERS.splice(i, 1);
  } else if (scope && scope.cell) {
    const tenantIds = new Set(U.TENANTS.filter((t) => t.cell === scope.cell).map((t) => t.id));
    for (let i = U.USERS.length - 1; i >= 0; i--) if (tenantIds.has(U.USERS[i].tenant) && !ids.has(U.USERS[i].id)) U.USERS.splice(i, 1);
  }
  incoming.forEach(upsertUserCache);
  return incoming;
};
const userPayload = (u) => ({
  role: u.role,
  status: u.status,
  first_name: u.firstname || u.firstName || "",
  last_name: u.lastname || u.lastName || "",
  email: u.email || "",
  phone_cell: u.phoneCell || "",
  phone_office: u.phoneOffice || "",
  language: u.language || "",
  languages: u.languages || [],
  gender: u.gender || "",
  date_of_birth: u.dob || "",
  address: u.address || {},
  mfa: !!u.mfa,
  avatar_media_id: u.avatar || "",
  specialization: u.specialization || "",
  linkedin_url: u.linkedin || "",
  bio: u.bio || "",
  degrees: u.degrees || [],
  health: u.health || {},
  social_profiles: u.social || {},
  assignments: (u.assignments || []).map((a) => ({ practitioner_user_id: a.practitionerId || a.practitioner_user_id, relationship: a.relationship || "Primary" })).filter((a) => a.practitioner_user_id),
});
const createPayload = (u) => ({
  ...userPayload(u),
  type: u.type,
  role: u.type === "patient" ? "regular" : (u.role || "regular"),
});
const invitePayload = (u) => ({
  type: u.type,
  role: u.type === "patient" ? "regular" : (u.role || "regular"),
  email: u.email || "",
  first_name: u.firstname || "",
  last_name: u.lastname || "",
  specialization: u.specialization || "",
  assignments: (u.assignments || []).map((a) => ({ practitioner_user_id: a.practitionerId || a.practitioner_user_id, relationship: a.relationship || "Primary" })).filter((a) => a.practitioner_user_id),
  note: u.note || "",
});

function AvatarImg({ user, size = 28 }) {
  if (user.avatar) return h("img", { className: "avatar-img", src: user.avatar, alt: "", style: { width: size, height: size } });
  return h(Avatar, { initials: uInitials(user), size, tone: user.status === "disabled" ? "bad" : typeTone(user.type) });
}
function VerifiedTick({ verification, size = 14 }) {
  if (!verification || verification.status !== "verified") return null;
  return h("span", { className: "vtick", title: "Verified via " + verifyMethodLabel(verification.method) }, h(Icon, { name: "verified", size }));
}
function AvatarUploader({ value, onChange }) {
  const ref = useRef();
  const pick = (file) => { if (!file) return; const r = new FileReader(); r.onload = () => onChange(r.result); r.readAsDataURL(file); };
  return h("div", { className: "avatar-up" },
    h("div", { className: "avatar-up-thumb", onClick: () => ref.current.click() },
      value ? h("img", { src: value, alt: "" }) : h(Icon, { name: "camera", size: 24 })),
    h("input", { ref, type: "file", accept: "image/*", hidden: true, onChange: (e) => pick(e.target.files[0]) }),
    h("div", { className: "avatar-up-actions" },
      h(Button, { variant: "default", size: "sm", icon: "upload", onClick: () => ref.current.click() }, value ? "Change photo" : "Upload photo"),
      value && h(Button, { variant: "ghost", size: "sm", icon: "trash", onClick: () => onChange("") }, "Remove")));
}
function VerificationBlock({ value, onChange, toast }) {
  const v = value || { status: "unverified" };
  const verify = (method) => { onChange({ status: "verified", method, verifiedAt: U.NOW }); toast && toast("Identity verified via " + verifyMethodLabel(method), "ok"); };
  if (v.status === "verified") return h("div", { className: "verify-card ok" },
    h(Icon, { name: "verified", size: 20 }),
    h("div", { className: "verify-main" },
      h("div", { className: "verify-title" }, "Verified identity"),
      h("div", { className: "dim small" }, "Confirmed via ", h("strong", null, verifyMethodLabel(v.method)))),
    h(Button, { variant: "ghost", size: "sm", icon: "x", onClick: () => onChange({ status: "unverified" }) }, "Revoke"));
  if (v.status === "pending") return h("div", { className: "verify-card pend" },
    h(Icon, { name: "clock", size: 18 }),
    h("div", { className: "verify-main" }, h("div", { className: "verify-title" }, "Verification pending"), h("div", { className: "dim small" }, "Awaiting ", verifyMethodLabel(v.method))),
    h(Button, { variant: "ghost", size: "sm", icon: "x", onClick: () => onChange({ status: "unverified" }) }, "Cancel"));
  return h("div", { className: "verify-card" },
    h(Icon, { name: "shield", size: 18 }),
    h("div", { className: "verify-main" }, h("div", { className: "verify-title" }, "Not verified"), h("div", { className: "dim small" }, "Confirm this user's identity")),
    h("div", { className: "verify-btns" },
      h(Button, { variant: "default", size: "sm", onClick: () => verify("itsme") }, "Verify with itsme"),
      h(Button, { variant: "default", size: "sm", onClick: () => verify("idnow") }, "Verify with IDnow")));
}
/* Practitioner degrees — repeatable list */
function DegreesEditor({ value, onChange }) {
  const list = value || [];
  const setItem = (i, k, v) => onChange(list.map((d, j) => (j === i ? { ...d, [k]: v } : d)));
  const add = () => onChange([...list, { title: "", university: "", year: "" }]);
  return h("div", { className: "field field-span" },
    h("div", { className: "degrees-list" },
      list.map((d, i) => h("div", { className: "degree-row", key: i },
        h("div", { className: "degree-grid" },
          h(TRow, { label: i === 0 ? "Degree" : null, value: d.title, onChange: (v) => setItem(i, "title", v), ph: "e.g. MD, Clinical Pathology", span: true }),
          h(TRow, { label: i === 0 ? "University" : null, value: d.university, onChange: (v) => setItem(i, "university", v), ph: "Institution" }),
          h(TRow, { label: i === 0 ? "Year" : null, value: d.year, onChange: (v) => setItem(i, "year", v), ph: "Year" })),
        h("button", { className: "degree-rm", title: "Remove degree", onClick: () => onChange(list.filter((_, j) => j !== i)) }, h(Icon, { name: "trash", size: 15 })))),
      !list.length && h("div", { className: "dim small", style: { padding: "2px" } }, "No degrees added yet.")),
    h("div", { style: { marginTop: "10px" } }, h(Button, { variant: "default", size: "sm", icon: "plus", onClick: add }, "Add degree")));
}

function SocialEditor({ value, onChange }) {
  const s = value || {};
  return h("div", { className: "uform-grid c2" },
    SOCIALS.map((sm) => h(TRow, { key: sm.key, label: sm.label, value: s[sm.key], ph: sm.ph, onChange: (val) => onChange({ ...s, [sm.key]: val }) })));
}

/* Languages — autocomplete multi-select with chips */
function LangAutocomplete({ value, onChange }) {
  const list = value || [];
  const [q, setQ] = useState("");
  const [open, setOpen] = useState(false);
  const [hl, setHl] = useState(0);
  const ref = useRef();
  useEffect(() => {
    const f = (e) => ref.current && !ref.current.contains(e.target) && setOpen(false);
    document.addEventListener("pointerdown", f, true);
    return () => document.removeEventListener("pointerdown", f, true);
  }, []);
  const avail = LANGUAGES.filter((l) => !list.includes(l));
  const matches = avail.filter((l) => l.toLowerCase().includes(q.trim().toLowerCase()));
  const add = (l) => { if (!l) return; onChange([...list, l]); setQ(""); setHl(0); };
  const custom = q.trim() && !LANGUAGES.some((l) => l.toLowerCase() === q.trim().toLowerCase()) && !list.some((l) => l.toLowerCase() === q.trim().toLowerCase());
  return h("div", { className: "field field-span", ref },
    h("span", { className: "field-label" }, "Languages spoken"),
    h("div", { className: "lang-box" + (open ? " open" : "") },
      list.map((l) => h("span", { className: "list-chip", key: l }, h("span", null, l),
        h("button", { className: "list-chip-x", onClick: () => onChange(list.filter((x) => x !== l)), title: "Remove" }, h(Icon, { name: "x", size: 13 })))),
      h("input", { className: "lang-input", placeholder: list.length ? "Add another…" : "Search languages…",
        value: q, onFocus: () => setOpen(true), onChange: (e) => { setQ(e.target.value); setOpen(true); setHl(0); },
        onKeyDown: (e) => {
          if (e.key === "ArrowDown") { e.preventDefault(); setHl((i) => Math.min(i + 1, matches.length - 1)); }
          else if (e.key === "ArrowUp") { e.preventDefault(); setHl((i) => Math.max(i - 1, 0)); }
          else if (e.key === "Enter") { e.preventDefault(); if (matches[hl]) add(matches[hl]); else if (custom) add(q.trim()); }
          else if (e.key === "Backspace" && !q && list.length) onChange(list.slice(0, -1));
        } })),
    open && (matches.length > 0 || custom) && h("div", { className: "lang-menu" },
      matches.map((l, i) => h("button", { key: l, className: "lang-opt" + (i === hl ? " hl" : ""), onMouseEnter: () => setHl(i), onClick: () => add(l) }, l)),
      custom && h("button", { className: "lang-opt lang-opt-add", onClick: () => add(q.trim()) }, h(Icon, { name: "plus", size: 13 }), "Add “", q.trim(), "”")));
}

/* Patient → Documents tab */
function PatientDocsTab({ user, toast, onBump }) {
  const docs = docsForUser(user.id);
  const act = (label, d, tone) => { toast(label + " · " + d.file, tone); };
  const del = (d) => { const i = U.DOCUMENTS.findIndex((x) => x.id === d.id); if (i >= 0) U.DOCUMENTS.splice(i, 1); toast("Deleted " + d.file, "bad"); onBump(); };
  const ban = (d) => { d.banned = true; toast("Banned " + d.file, "bad"); onBump(); };
  const reprocess = (d) => { toast("Re-processing " + d.file, "ok"); onBump(); };
  if (!docs.length) return h(Empty, { icon: "documents", title: "No documents", sub: "No documents are linked to this patient yet." });
  return h("div", { className: "ptab" },
    h("div", { className: "ptab-head" }, docs.length, " document", docs.length === 1 ? "" : "s", " linked to this patient"),
    h("div", { className: "doc-cards" }, docs.map((d) => h("div", { className: "doc-card" + (d.banned ? " banned" : ""), key: d.id },
      h("div", { className: "doc-card-ic" }, h(Icon, { name: "documents", size: 18 })),
      h("div", { className: "doc-card-main" },
        h("div", { className: "doc-card-name" }, d.file, d.banned && h("span", { className: "ban-tag" }, "Banned")),
        h("div", { className: "doc-card-meta" }, h(StatusPill, { status: d.status }),
          h("span", { className: "dim mono small" }, fmtBytes(d.size)),
          h("span", { className: "dim small" }, "· ", fmtAgo(U.ago(d.createdMin * U.MIN))))),
      h("div", { className: "doc-card-actions" },
        h("button", { className: "mini-btn", title: "Download", onClick: () => act("Downloading", d) }, h(Icon, { name: "download", size: 15 })),
        h("button", { className: "mini-btn", title: "Re-process", onClick: () => reprocess(d) }, h(Icon, { name: "refresh", size: 15 })),
        h("button", { className: "mini-btn warn", title: d.banned ? "Banned" : "Ban document", disabled: d.banned, onClick: () => ban(d) }, h(Icon, { name: "lock", size: 15 })),
        h("button", { className: "mini-btn danger", title: "Delete", onClick: () => del(d) }, h(Icon, { name: "trash", size: 15 })))))));
}

/* Patient → Interviews tab */
function fmtDur(sec) { const m = Math.floor(sec / 60), s = sec % 60; return m + ":" + String(s).padStart(2, "0"); }
function PatientInterviewsTab({ user, toast }) {
  const items = interviewsForUser(user.id);
  if (!items.length) return h(Empty, { icon: "activity", title: "No interviews", sub: "No voice recordings stored for this patient yet." });
  return h("div", { className: "ptab" },
    h("div", { className: "ptab-head" }, items.length, " stored voice recording", items.length === 1 ? "" : "s"),
    h("div", { className: "doc-cards" }, items.map((it) => h("div", { className: "doc-card", key: it.id },
      h("div", { className: "doc-card-ic audio" }, h(Icon, { name: "activity", size: 18 })),
      h("div", { className: "doc-card-main" },
        h("div", { className: "doc-card-name" }, it.title, h("span", { className: "dim small", style: { fontWeight: 400 } }, " · ", it.topic)),
        h("div", { className: "doc-card-meta" },
          it.status === "transcribed" ? h(Pill, { tone: "ok", soft: true }, "transcribed") : h(Pill, { tone: "info", soft: true }, "processing"),
          h("span", { className: "dim small" }, fmtDur(it.durationSec)),
          h("span", { className: "dim small" }, "· ", it.lang),
          h("span", { className: "dim mono small" }, "· ", fmtBytes(it.sizeBytes)),
          h("span", { className: "dim small" }, "· ", fmtAgo(U.ago(it.recordedMin * U.MIN))))),
      h("div", { className: "doc-card-actions" },
        h(Button, { variant: "default", size: "sm", icon: "download", onClick: () => toast("Downloading recording · " + it.title) }, "Recording"),
        h(Button, { variant: "ghost", size: "sm", icon: "documents", disabled: it.status !== "transcribed", onClick: () => toast("Downloading transcription · " + it.title) }, "Transcript"))))));
}

/* ======================================================================== */
/* CONTEXT MENU                                                              */
/* ======================================================================== */
function ContextMenu({ pos, items, onClose }) {
  const ref = useRef();
  useEffect(() => {
    const close = () => onClose();
    window.addEventListener("click", close);
    window.addEventListener("scroll", close, true);
    window.addEventListener("resize", close);
    const esc = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", esc);
    return () => {
      window.removeEventListener("click", close);
      window.removeEventListener("scroll", close, true);
      window.removeEventListener("resize", close);
      window.removeEventListener("keydown", esc);
    };
  }, []);
  if (!pos) return null;
  const x = Math.min(pos.x, window.innerWidth - 220);
  const y = Math.min(pos.y, window.innerHeight - (items.length * 38 + 16));
  return h("div", { className: "ctxmenu", ref, style: { left: x, top: y }, onClick: (e) => e.stopPropagation(), onContextMenu: (e) => e.preventDefault() },
    items.map((it, i) => it.sep
      ? h("div", { className: "ctxmenu-sep", key: "sep" + i })
      : h("button", { key: it.label, className: "ctxmenu-item" + (it.danger ? " danger" : ""), disabled: it.disabled, onClick: () => { onClose(); it.onClick && it.onClick(); } },
          h(Icon, { name: it.icon, size: 15 }), h("span", null, it.label))));
}

/* ======================================================================== */
/* FORM HELPERS                                                              */
/* ======================================================================== */
function USection({ title, sub, children }) {
  return h("div", { className: "uform-sec" },
    h("div", { className: "uform-sec-head" }, h("div", { className: "uform-sec-title" }, title), sub && h("div", { className: "uform-sec-sub" }, sub)),
    children);
}
function TRow({ label, value, onChange, ph, hint, type, span, disabled }) {
  return h("label", { className: "field" + (span ? " field-span" : "") },
    label && h("span", { className: "field-label" }, label),
    h("input", { className: "input", type: type || "text", placeholder: ph || "", value: value == null ? "" : value, disabled, onChange: (e) => onChange(e.target.value) }),
    hint && h("span", { className: "field-hint" }, hint));
}
function SRow({ label, value, onChange, options, span, disabled }) {
  return h("label", { className: "field" + (span ? " field-span" : "") },
    label && h("span", { className: "field-label" }, label),
    h(Select, { value: value || "", onChange, disabled, options: [{ value: "", label: "—" }].concat(options.map((o) => (typeof o === "string" ? { value: o, label: o } : o))) }));
}
function ListEditor({ label, items, onChange, ph }) {
  const [draft, setDraft] = useState("");
  const list = items || [];
  const add = () => { if (!draft.trim()) return; onChange([...list, draft.trim()]); setDraft(""); };
  return h("div", { className: "field field-span" },
    h("span", { className: "field-label" }, label),
    h("div", { className: "list-editor" },
      list.map((it, i) => h("div", { className: "list-chip", key: i },
        h("span", null, it),
        h("button", { className: "list-chip-x", onClick: () => onChange(list.filter((_, j) => j !== i)), title: "Remove" }, h(Icon, { name: "x", size: 13 })))),
      !list.length && h("span", { className: "dim small" }, "None recorded")),
    h("div", { className: "list-add" },
      h("input", { className: "input", placeholder: ph, value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: (e) => e.key === "Enter" && (e.preventDefault(), add()) }),
      h(Button, { variant: "default", size: "sm", icon: "plus", onClick: add }, "Add")));
}

/* Patient → practitioner assignment editor */
function AssignmentEditor({ value, onChange, tenantId }) {
  const list = value || [];
  const roster = practitionersIn(tenantId);
  const aid = (a) => a.practitionerId || a.practitioner_user_id || "";
  const avail = roster.filter((p) => !list.some((a) => aid(a) === p.id));
  const [pid, setPid] = useState("");
  const [rel, setRel] = useState("Primary");
  const add = () => { if (!pid) return; onChange([...list, { practitionerId: pid, practitioner_user_id: pid, relationship: rel }]); setPid(""); setRel("Primary"); };
  const pracName = (id) => { const p = U.USERS.find((x) => x.id === id); return p ? uName(p) : id; };
  return h("div", { className: "field field-span" },
    h("span", { className: "field-label" }, "Assigned practitioners"),
    h("div", { className: "assign-list" },
      list.map((a, i) => h("div", { className: "assign-row", key: aid(a) },
        h(Avatar, { initials: uInitials(U.USERS.find((x) => x.id === aid(a)) || { name: "?" }), size: 26 }),
        h("div", { className: "assign-main" },
          h("div", { className: "assign-name" }, pracName(aid(a))),
          h("div", { className: "dim small" }, (U.USERS.find((x) => x.id === aid(a)) || {}).specialization || "Practitioner")),
        h(Pill, { tone: a.relationship === "Primary" ? "accent" : "neutral", soft: true }, a.relationship),
        h("button", { className: "list-chip-x", title: "Remove", onClick: () => onChange(list.filter((_, j) => j !== i)) }, h(Icon, { name: "x", size: 14 })))),
      !list.length && h("div", { className: "dim small", style: { padding: "4px 2px" } }, "No practitioners assigned yet.")),
    avail.length > 0 && h("div", { className: "assign-add" },
      h(Select, { value: pid, onChange: setPid, options: [{ value: "", label: "Select practitioner…" }].concat(avail.map((p) => ({ value: p.id, label: uName(p) + (p.specialization ? " · " + p.specialization : "") }))) }),
      h(Select, { value: rel, onChange: setRel, options: RELATIONSHIPS }),
      h(Button, { variant: "default", size: "sm", icon: "plus", onClick: add, disabled: !pid }, "Assign")));
}

/* ======================================================================== */
/* SYSTEM ACCOUNT DRAWER (read-only)                                         */
/* ======================================================================== */
function SystemDrawer({ user, onClose }) {
  return h(Drawer, {
    open: true, onClose, width: 560,
    title: "System Account",
    sub: h("div", { className: "drawer-subline" }, h(Pill, { tone: "neutral" }, "System"), h(Pill, { tone: "ok" }, "active"), h("span", { className: "dim" }, U.tenantName(user.tenant))),
    footer: h("div", { className: "drawer-actions", style: { width: "100%", justifyContent: "flex-end" } }, h(Button, { variant: "ghost", onClick: onClose }, "Close")),
  },
    h("div", { className: "syscard" },
      h(Icon, { name: "lock", size: 18 }),
      h("div", null,
        h("strong", null, "System-managed account."),
        " Auto-provisioned when the tenant was created. It owns automated ingestion jobs and default tenant actions for the audit trail. It cannot be edited, disabled, invited, deleted, or assigned as a practitioner.")),
    h("div", { className: "meta-grid", style: { marginTop: "16px" } },
      mRow2("Type", h(Pill, { tone: "neutral", soft: true }, "System")),
      mRow2("Tenant role", h(Pill, { tone: "accent", soft: true }, "Owner")),
      mRow2("Status", h(Pill, { tone: "ok", soft: true }, "active")),
      mRow2("Managed by", "System"),
      mRow2("Email", h(Mono, null, user.email)),
      mRow2("User ID", h(Mono, { copy: true }, user.id))));
}
function mRow2(k, v) { return h("div", { className: "meta-row" }, h("span", { className: "meta-k" }, k), h("span", { className: "meta-v" }, v)); }

/* ======================================================================== */
/* MFA SETUP MODAL                                                           */
/* ======================================================================== */
function mulberry32(a) { return function () { a |= 0; a = (a + 0x6D2B79F5) | 0; let t = Math.imul(a ^ (a >>> 15), 1 | a); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; }
function seedFrom(str) { let hsh = 2166136261; for (let i = 0; i < str.length; i++) { hsh ^= str.charCodeAt(i); hsh = Math.imul(hsh, 16777619); } return hsh >>> 0; }
const fmtSecret = (s) => s.match(/.{1,4}/g).join(" ");

function FakeQR({ seed, size = 168 }) {
  const N = 25;
  const rng = mulberry32(seedFrom(seed));
  const cells = [];
  const isFinder = (r, c) => {
    const inBox = (br, bc) => r >= br && r < br + 7 && c >= bc && c < bc + 7;
    return inBox(0, 0) || inBox(0, N - 7) || inBox(N - 7, 0);
  };
  for (let r = 0; r < N; r++) for (let c = 0; c < N; c++) {
    if (isFinder(r, c)) continue;
    if (rng() > 0.52) cells.push(h("rect", { key: r + "_" + c, x: c, y: r, width: 1.02, height: 1.02, fill: "#1a1a22" }));
  }
  const finder = (x, y) => h("g", { key: x + "_" + y },
    h("rect", { x, y, width: 7, height: 7, fill: "#1a1a22" }),
    h("rect", { x: x + 1, y: y + 1, width: 5, height: 5, fill: "#fff" }),
    h("rect", { x: x + 2, y: y + 2, width: 3, height: 3, fill: "#1a1a22" }));
  return h("svg", { className: "qr-svg", width: size, height: size, viewBox: "0 0 " + N + " " + N, shapeRendering: "crispEdges" },
    h("rect", { x: 0, y: 0, width: N, height: N, fill: "#fff" }),
    cells, finder(0, 0), finder(0, N - 7), finder(N - 7, 0));
}

function CodeInput({ length = 6, value, onChange }) {
  const refs = useRef([]);
  const chars = value.padEnd(length).slice(0, length).split("");
  const setAt = (i, ch) => {
    const arr = value.padEnd(length).split("");
    arr[i] = ch; const next = arr.join("").replace(/\s+$/g, "");
    onChange(next.slice(0, length));
    if (ch && i < length - 1) refs.current[i + 1] && refs.current[i + 1].focus();
  };
  return h("div", { className: "code-input" },
    Array.from({ length }).map((_, i) => h("input", {
      key: i, ref: (el) => (refs.current[i] = el), className: "code-box", inputMode: "numeric", maxLength: 1,
      value: chars[i] && chars[i].trim() ? chars[i] : "",
      onChange: (e) => { const d = e.target.value.replace(/\D/g, "").slice(-1); setAt(i, d); },
      onKeyDown: (e) => { if (e.key === "Backspace" && !(chars[i] && chars[i].trim()) && i > 0) refs.current[i - 1] && refs.current[i - 1].focus(); },
      onPaste: (e) => { e.preventDefault(); const txt = (e.clipboardData.getData("text") || "").replace(/\D/g, "").slice(0, length); if (txt) onChange(txt); },
    })));
}

function MfaModal({ open, user, onClose, onConfirm, toast }) {
  const [step, setStep] = useState("scan");
  const [code, setCode] = useState("");
  const [showSecret, setShowSecret] = useState(false);
  const secret = useMemo(() => {
    const rng = mulberry32(seedFrom((user && user.id || "x") + "|mfa"));
    const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; let s = "";
    for (let i = 0; i < 32; i++) s += chars[Math.floor(rng() * chars.length)];
    return s;
  }, [user && user.id]);
  const recovery = useMemo(() => {
    const rng = mulberry32(seedFrom((user && user.id || "x") + "|rec"));
    const block = () => Array.from({ length: 5 }).map(() => "0123456789abcdefghjkmnpqrstuvwxyz"[Math.floor(rng() * 33)]).join("");
    return Array.from({ length: 10 }).map(() => block() + "-" + block());
  }, [user && user.id]);
  useEffect(() => { if (open) { setStep("scan"); setCode(""); setShowSecret(false); } }, [open, user && user.id]);
  if (!open || !user) return null;

  const otpauth = "otpauth://totp/Eno.Health:" + encodeURIComponent(user.email || uName(user)) + "?secret=" + secret + "&issuer=Eno.Health";
  const verify = () => {
    if (code.length < 6) { toast && toast("Enter the 6-digit code", "bad"); return; }
    setStep("recovery"); toast && toast("Authenticator verified", "ok");
  };
  const copy = (text, label) => { try { navigator.clipboard && navigator.clipboard.writeText(text); } catch (e) {} toast && toast(label + " copied"); };
  const finish = () => { onConfirm(); onClose(); };

  const scanStep = h("div", { className: "mfa-body" },
    h("div", { className: "mfa-steps" },
      h("span", { className: "mfa-stepdot on" }, "1"), h("span", { className: "mfa-stepline" }),
      h("span", { className: "mfa-stepdot" }, "2")),
    h("p", { className: "mfa-lead" }, "Protect ", h("strong", null, uName(user)), "'s account with an authenticator app (Google Authenticator, 1Password, Authy…)."),
    h("div", { className: "mfa-scan" },
      h("div", { className: "mfa-qr" }, h(FakeQR, { seed: otpauth })),
      h("div", { className: "mfa-scan-side" },
        h("div", { className: "mfa-num" }, h("span", { className: "mfa-num-b" }, "1"), "Scan this QR code with your authenticator app"),
        h("div", { className: "mfa-num" }, h("span", { className: "mfa-num-b" }, "2"), "Enter the 6-digit code it generates below"),
        h("button", { className: "mfa-secret-toggle", onClick: () => setShowSecret((s) => !s) },
          h(Icon, { name: "key", size: 13 }), showSecret ? "Hide setup key" : "Can't scan? Enter key manually"),
        showSecret && h("div", { className: "mfa-secret" },
          h("code", null, fmtSecret(secret)),
          h("button", { className: "mini-btn", title: "Copy key", onClick: () => copy(secret, "Setup key") }, h(Icon, { name: "copy", size: 14 }))))),
    h("div", { className: "mfa-verify" },
      h("div", { className: "field-label" }, "Verification code"),
      h(CodeInput, { value: code, onChange: setCode })));

  const recoveryStep = h("div", { className: "mfa-body" },
    h("div", { className: "mfa-success" },
      h("div", { className: "mfa-success-ic" }, h(Icon, { name: "verified", size: 24 })),
      h("div", null, h("div", { className: "mfa-success-t" }, "Multi-factor authentication enabled"),
        h("div", { className: "dim small" }, "Save these recovery codes somewhere safe."))),
    h("div", { className: "mfa-rec-head" },
      h(Icon, { name: "alert", size: 14 }),
      h("span", null, "Each code works ", h("strong", null, "once"), " if the authenticator device is lost. They won't be shown again.")),
    h("div", { className: "mfa-codes" }, recovery.map((c) => h("code", { key: c, className: "mfa-code" }, c))),
    h("div", { className: "mfa-rec-actions" },
      h(Button, { variant: "default", size: "sm", icon: "copy", onClick: () => copy(recovery.join("\n"), "Recovery codes") }, "Copy codes"),
      h(Button, { variant: "ghost", size: "sm", icon: "download", onClick: () => copy(recovery.join("\n"), "Recovery codes (download mock)") }, "Download")));

  const footer = step === "scan"
    ? h("div", { className: "drawer-actions", style: { width: "100%", justifyContent: "flex-end" } },
        h(Button, { variant: "ghost", onClick: onClose }, "Cancel"),
        h(Button, { variant: "primary", icon: "shield", disabled: code.length < 6, onClick: verify }, "Verify & enable"))
    : h("div", { className: "drawer-actions", style: { width: "100%", justifyContent: "flex-end" } },
        h(Button, { variant: "primary", icon: "check", onClick: finish }, "Done"));

  return h(Modal, { open, onClose: step === "scan" ? onClose : finish, width: 520,
    title: h("span", { className: "mfa-title" }, h(Icon, { name: "smartphone", size: 17 }), "Set up multi-factor auth"), footer },
    step === "scan" ? scanStep : recoveryStep);
}

/* ======================================================================== */
/* USER DETAIL / EDIT DRAWER                                                 */
/* ======================================================================== */
function UserDrawer({ user, lockTenant, tenants, onClose, onSave, onAction, toast }) {
  const [f, setF] = useState(null);
  const [dtab, setDtab] = useState("profile");
  const [mfaSetup, setMfaSetup] = useState(false);
  useEffect(() => { setF(user ? JSON.parse(JSON.stringify(user)) : null); setDtab("profile"); setMfaSetup(false); }, [user && user.id]);
  if (!user) return null;
  if (user.isSystemManaged) return h(SystemDrawer, { user, onClose });
  if (!f) return null;

  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  const setAddr = (k, v) => setF((p) => ({ ...p, address: { ...(p.address || {}), [k]: v } }));
  const setH = (k, v) => setF((p) => ({ ...p, health: { ...(p.health || {}), [k]: v } }));
  const setDeg = (k, v) => setF((p) => ({ ...p, degree: { ...(p.degree || {}), [k]: v } }));
  const setDegrees = (v) => setF((p) => ({ ...p, degrees: v, degree: undefined }));
  const isPatient = f.type === "patient";
  const h2 = f.health || {};
  const dg = f.degree || {};
  const degrees = f.degrees || (dg.title || dg.university || dg.year ? [dg] : []);
  const ad = f.address || {};
  const invited = f.status === "invited";

  const account = h(USection, { title: "Account" },
    h("div", { className: "uform-grid c2" },
      !isPatient && h(SRow, { label: "Type", value: f.type, onChange: (v) => set("type", v), options: CREATE_TYPES, disabled: true }),
      !isPatient && h(SRow, { label: "Tenant role", value: f.role, onChange: (v) => set("role", v), options: TENANT_ROLES }),
      !lockTenant && tenants && h(SRow, { label: "Tenant", value: f.tenant, onChange: (v) => set("tenant", v), options: tenants.map((t) => ({ value: t.id, label: t.name })), span: true }),
      h(SRow, { label: "Status", value: f.status, onChange: (v) => set("status", v), options: [{ value: "active", label: "Active" }, { value: "disabled", label: "Disabled" }, { value: "pending", label: "Pending identity" }].concat(invited ? [{ value: "invited", label: "Invited" }] : []) }),
      h("label", { className: "field" }, h("span", { className: "field-label" }, "Multi-factor auth"),
        h("div", { style: { paddingTop: "4px" } }, h(Toggle, { on: !!f.mfa, onChange: (v) => { if (v) setMfaSetup(true); else set("mfa", false); } })))));

  const identity = h(USection, { title: "Identity" },
    h("div", { className: "uform-grid c2" },
      h(TRow, { label: "First name", value: f.firstname, onChange: (v) => set("firstname", v), ph: "First name" }),
      h(TRow, { label: "Last name", value: f.lastname, onChange: (v) => set("lastname", v), ph: "Last name" }),
      h(SRow, { label: "Gender", value: f.gender, onChange: (v) => set("gender", v), options: GENDERS }),
      h(TRow, { label: "Date of birth", value: f.dob, onChange: (v) => set("dob", v), type: "date", hint: ageFromDob(f.dob) != null ? ageFromDob(f.dob) + " years old" : null })));

  const contact = h(USection, { title: "Contact" },
    h("div", { className: "uform-grid c2" },
      h(TRow, { label: "Email address", value: f.email, onChange: (v) => set("email", v), ph: "name@example.com", type: "email", span: true }),
      !isPatient && h(TRow, { label: "Phone (office)", value: f.phoneOffice, onChange: (v) => set("phoneOffice", v), ph: "+32 …" }),
      h(TRow, { label: "Phone (cell)", value: f.phoneCell, onChange: (v) => set("phoneCell", v), ph: "+32 …" }),
      h(SRow, { label: "Primary language", value: f.language, onChange: (v) => set("language", v), options: LANGUAGES })));

  const address = h(USection, { title: "Address" },
    h("div", { className: "uform-grid c2" },
      h(TRow, { label: "Street & number", value: ad.line, onChange: (v) => setAddr("line", v), ph: "Street address", span: true }),
      h(TRow, { label: "City", value: ad.city, onChange: (v) => setAddr("city", v), ph: "City" }),
      h(TRow, { label: "Postal code", value: ad.postal, onChange: (v) => setAddr("postal", v), ph: "Postal code" }),
      h(SRow, { label: "Country", value: ad.country, onChange: (v) => setAddr("country", v), options: COUNTRIES, span: true })));

  const professional = h(USection, { title: "Professional", sub: "Specialization & credentials" },
    h("div", { className: "uform-grid c2" },
      h(TRow, { label: "Specialization", value: f.specialization, onChange: (v) => set("specialization", v), ph: "e.g. Internal Medicine", span: true }),
      h(TRow, { label: "LinkedIn profile", value: f.linkedin, onChange: (v) => set("linkedin", v), ph: "https://www.linkedin.com/in/…", span: true }),
      h("label", { className: "field field-span" }, h("span", { className: "field-label" }, "Services description"),
        h("textarea", { className: "input", rows: 4, value: f.bio || "", onChange: (e) => set("bio", e.target.value), placeholder: "Describe the services and care this practitioner offers…" }))),
    h("div", { className: "uform-subhead" }, "Degrees"),
    h(DegreesEditor, { value: degrees, onChange: setDegrees }));

  const careTeam = h(USection, { title: "Care team", sub: "Practitioners attached to this patient" },
    h("div", { className: "uform-grid" }, h(AssignmentEditor, { value: f.assignments, onChange: (v) => set("assignments", v), tenantId: f.tenant })));

  const vitals = h(USection, { title: "Health metrics", sub: "Most recent recorded measurements" },
    h("div", { className: "uform-grid c3" },
      h(TRow, { label: "Height (cm)", value: h2.heightCm, onChange: (v) => setH("heightCm", v), ph: "cm", type: "number" }),
      h(TRow, { label: "Weight (kg)", value: h2.weightKg, onChange: (v) => setH("weightKg", v), ph: "kg", type: "number" }),
      h(SRow, { label: "Blood type", value: h2.bloodType, onChange: (v) => setH("bloodType", v), options: BLOOD_TYPES }),
      h(TRow, { label: "Systolic (mmHg)", value: h2.systolic, onChange: (v) => setH("systolic", v), ph: "mmHg", type: "number" }),
      h(TRow, { label: "Diastolic (mmHg)", value: h2.diastolic, onChange: (v) => setH("diastolic", v), ph: "mmHg", type: "number" }),
      h(TRow, { label: "Hip-waist ratio", value: h2.hipWaist, onChange: (v) => setH("hipWaist", v), ph: "e.g. 0.85" }),
      h(SRow, { label: "Smoker", value: h2.smoker, onChange: (v) => setH("smoker", v), options: SMOKER_OPTS }),
      h2.smoker === "Yes" && h(TRow, { label: "Smoking since", value: h2.smokingSince, onChange: (v) => setH("smokingSince", v), ph: "e.g. 2010 or age 18" }),
      h2.smoker === "Former" && h(TRow, { label: "Smoking years (total)", value: h2.smokingYears, onChange: (v) => setH("smokingYears", v), ph: "e.g. 12", type: "number" }),
      h2.smoker === "Former" && h(TRow, { label: "Quit smoking when?", value: h2.quitSmoking, onChange: (v) => setH("quitSmoking", v), ph: "e.g. 2018 or Mar 2018" })));

  const history = h(USection, { title: "Medical history" },
    h("div", { className: "uform-grid c2" },
      h(TRow, { label: "Diabetic history", value: h2.diabetic, onChange: (v) => setH("diabetic", v), ph: "e.g. Type 2 (2019) / No history", span: true }),
      h(TRow, { label: "History of heart / other conditions", value: h2.heartHistory, onChange: (v) => setH("heartHistory", v), ph: "Relevant conditions & family history", span: true }),
      h(ListEditor, { label: "Allergies & intolerances", items: h2.allergies, onChange: (v) => setH("allergies", v), ph: "Add an allergy or intolerance…" })));

  const care = h(USection, { title: "Care & goals" },
    h("div", { className: "uform-grid c2" },
      h("label", { className: "field field-span" }, h("span", { className: "field-label" }, "Most important health issues or concerns"),
        h("textarea", { className: "input", rows: 2, value: h2.concerns || "", onChange: (e) => setH("concerns", e.target.value), placeholder: "Primary concerns…" })),
      h(ListEditor, { label: "Medications & supplements", items: h2.medications, onChange: (v) => setH("medications", v), ph: "Add a medication or supplement…" }),
      h("label", { className: "field field-span" }, h("span", { className: "field-label" }, "Personal objective of using Eno"),
        h("textarea", { className: "input", rows: 2, value: h2.objective || "", onChange: (e) => setH("objective", e.target.value), placeholder: "What does this patient want to achieve?" }))));

  const social = h(USection, { title: "Social profiles", sub: "Public social media handles" },
    h(SocialEditor, { value: f.social, onChange: (v) => set("social", v) }));

  const profileHeader = h("div", { className: "uprofile" },
    h(AvatarUploader, { value: f.avatar, onChange: (v) => set("avatar", v) }),
    h("div", { className: "uprofile-main" },
      h("div", { className: "uprofile-name" }, uName(f) || "New user", f.verification && f.verification.status === "verified" && h(VerifiedTick, { verification: f.verification, size: 17 })),
      h("div", { className: "uprofile-sub" }, typeLabel(f.type), " · ", roleLabel(f.role), " · ", U.tenantName(f.tenant))));

  const verification = h(VerificationBlock, { value: f.verification, onChange: (v) => set("verification", v), toast });

  const languages = h(USection, { title: "Languages", sub: "Languages this user can communicate in" },
    h("div", { className: "uform-grid" }, h(LangAutocomplete, { value: f.languages, onChange: (v) => set("languages", v) })));

  const tabPanes = isPatient
    ? {
        profile: h(React.Fragment, null, account, languages),
        identity: h(React.Fragment, null, verification, identity, contact, address),
        care: careTeam,
        health: h(React.Fragment, null, vitals, history, care),
        social: social,
        documents: h(PatientDocsTab, { user, toast, onBump: () => set("_t", Date.now()) }),
        interviews: h(PatientInterviewsTab, { user, toast }),
      }
    : {
        profile: h(React.Fragment, null, account, languages),
        identity: h(React.Fragment, null, verification, identity, contact, address),
        professional: professional,
      };
  const drawerTabs = isPatient
    ? [
        { key: "profile", label: "Profile" },
        { key: "identity", label: "Identity" },
        { key: "care", label: "Care team", count: (f.assignments || []).length || undefined },
        { key: "health", label: "Health" },
        { key: "documents", label: "Documents", count: docsForUser(user.id).length || undefined },
        { key: "interviews", label: "Interviews", count: interviewsForUser(user.id).length || undefined },
        { key: "social", label: "Social" },
      ]
    : [
        { key: "profile", label: "Profile" },
        { key: "identity", label: "Identity" },
        { key: "professional", label: "Professional" },
      ];
  const activeTab = tabPanes[dtab] ? dtab : "profile";

  const body = h("div", { className: "uform" },
    profileHeader,
    invited && h("div", { className: "syscard warn" }, h(Icon, { name: "external", size: 16 }),
      h("div", null, h("strong", null, "Invitation pending."), " This user was invited and has not completed signup. Profile fields will be filled in when they accept.")),
    h("div", { className: "udrawer-tabs" }, h(Tabs, { tabs: drawerTabs, active: activeTab, onChange: setDtab })),
    h("div", { className: "udrawer-pane" }, tabPanes[activeTab]));

  const footer = h("div", { className: "drawer-actions", style: { width: "100%", justifyContent: "space-between" } },
    h("div", { className: "drawer-actions" },
      h(Button, { variant: "danger-ghost", size: "sm", icon: "trash", onClick: () => onAction(invited ? "revoke" : "delete", user) }, invited ? "Revoke" : "Delete"),
      !invited && h(Button, { variant: "ghost", size: "sm", icon: f.status === "disabled" ? "check" : "lock", onClick: () => onAction(f.status === "disabled" ? "enable" : "disable", user) },
        f.status === "disabled" ? "Enable" : "Disable")),
    h("div", { className: "drawer-actions" },
      h(Button, { variant: "ghost", onClick: onClose }, "Cancel"),
      h(Button, { variant: "primary", icon: "check", onClick: () => onSave(f) }, "Save changes")));

  return h(React.Fragment, null,
    h(Drawer, {
      open: true, onClose, width: 720, footer,
      title: uName(f),
      sub: h("div", { className: "drawer-subline" },
        h(Pill, { tone: typeTone(f.type) }, typeLabel(f.type)),
        h(Pill, { tone: STATUS_TONE[f.status] || "neutral" }, STATUS_LABEL[f.status] || f.status),
        f.verification && f.verification.status === "verified" && h(Pill, { tone: "ok" }, "Verified"),
        h("span", { className: "dim" }, roleLabel(f.role), " · ", U.tenantName(f.tenant))),
    }, body),
    h(MfaModal, { open: mfaSetup, user: f, onClose: () => setMfaSetup(false), onConfirm: () => set("mfa", true), toast }));
}

/* ======================================================================== */
/* CREATE + INVITE MODALS                                                    */
/* ======================================================================== */
function TypeSeg({ value, onChange }) {
  return h(SRow, { label: "Type", value, onChange, options: CREATE_TYPES });
}

function CreateUserModal({ open, onClose, onCreate, tenant, tenants }) {
  const seed = () => ({ type: "practitioner", firstname: "", lastname: "", email: "", phoneCell: "", role: "regular",
    tenant: tenant ? tenant.id : (tenants[0] && tenants[0].id), specialization: "", assignments: [], languages: [], status: "active",
    phoneOffice: "", language: "", gender: "", dob: "", address: { line: "", city: "", postal: "", country: "" },
    avatar: "", mfa: false, linkedin: "", bio: "", degrees: [], health: {}, social: {} });
  const [f, setF] = useState(seed());
  const [busy, setBusy] = useState(false);
  useEffect(() => { if (open) { setF(seed()); setBusy(false); } }, [open]);
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  const setAddr = (k, v) => setF((p) => ({ ...p, address: { ...(p.address || {}), [k]: v } }));
  const setH = (k, v) => setF((p) => ({ ...p, health: { ...(p.health || {}), [k]: v } }));
  const switchType = (type) => setF((p) => ({ ...p, type, role: type === "patient" ? "regular" : p.role, assignments: type === "patient" ? (p.assignments || []) : [] }));
  const create = () => {
    if (!ok || busy) return;
    setBusy(true);
    Promise.resolve(onCreate(f)).catch(() => {}).finally(() => setBusy(false));
  };
  const ok = f.tenant && f.firstname.trim() && f.lastname.trim() && f.email.trim() && (f.type !== "practitioner" || f.specialization.trim());
  const isPatient = f.type === "patient";
  const ad = f.address || {};
  const h2 = f.health || {};
  return h(Modal, { open, onClose, title: "Create user", width: 760,
    footer: h("div", { className: "drawer-actions", style: { width: "100%", justifyContent: "flex-end" } },
      h(Button, { variant: "ghost", onClick: onClose, disabled: busy }, "Cancel"),
      h(Button, { variant: "primary", icon: busy ? "spinner" : "plus", disabled: !ok || busy, onClick: create }, busy ? "Creating…" : "Create user")) },
    h("div", { className: "uform" },
      h("div", { className: "uprofile" },
        h(AvatarUploader, { value: f.avatar, onChange: (v) => set("avatar", v) }),
        h("div", { className: "uprofile-main" },
          h("div", { className: "uprofile-name" }, fullNameFrom(f) || "New user"),
          h("div", { className: "uprofile-sub" }, typeLabel(f.type), " · ", roleLabel(f.role), " · ", U.tenantName(f.tenant)))),
      h(USection, { title: "Account" },
        h("div", { className: "uform-grid c2" },
          h(TypeSeg, { value: f.type, onChange: switchType }),
          !isPatient && h(SRow, { label: "Tenant role", value: f.role, onChange: (v) => set("role", v), options: TENANT_ROLES }),
          isPatient && h(SRow, { label: "Tenant role", value: "regular", onChange: () => {}, options: [{ value: "regular", label: "Regular" }], disabled: true }),
          !tenant && h(SRow, { label: "Tenant", value: f.tenant, onChange: (v) => set("tenant", v), options: tenants.map((t) => ({ value: t.id, label: t.name })), span: true }),
          h("label", { className: "field" }, h("span", { className: "field-label" }, "Multi-factor auth"),
            h("div", { style: { paddingTop: "4px" } }, h(Toggle, { on: !!f.mfa, onChange: (v) => set("mfa", v) }))))),
      h(USection, { title: "Identity" },
        h("div", { className: "uform-grid c2" },
          h(TRow, { label: "First name", value: f.firstname, onChange: (v) => set("firstname", v), ph: "First name" }),
          h(TRow, { label: "Last name", value: f.lastname, onChange: (v) => set("lastname", v), ph: "Last name" }),
          h(SRow, { label: "Gender", value: f.gender, onChange: (v) => set("gender", v), options: GENDERS }),
          h(TRow, { label: "Date of birth", value: f.dob, onChange: (v) => set("dob", v), type: "date", hint: ageFromDob(f.dob) != null ? ageFromDob(f.dob) + " years old" : null }))),
      h(USection, { title: "Contact" },
      h("div", { className: "uform-grid c2" },
        h(TRow, { label: "Email address", value: f.email, onChange: (v) => set("email", v), ph: "name@example.com", type: "email", span: true }),
        !isPatient && h(TRow, { label: "Phone (office)", value: f.phoneOffice, onChange: (v) => set("phoneOffice", v), ph: "+32 …" }),
        h(TRow, { label: "Phone (cell)", value: f.phoneCell, onChange: (v) => set("phoneCell", v), ph: "+32 …" }),
        h(SRow, { label: "Primary language", value: f.language, onChange: (v) => set("language", v), options: LANGUAGES }))),
      h(USection, { title: "Languages" },
        h("div", { className: "uform-grid" }, h(LangAutocomplete, { value: f.languages, onChange: (v) => set("languages", v) }))),
      h(USection, { title: "Address" },
        h("div", { className: "uform-grid c2" },
          h(TRow, { label: "Street & number", value: ad.line, onChange: (v) => setAddr("line", v), ph: "Street address", span: true }),
          h(TRow, { label: "City", value: ad.city, onChange: (v) => setAddr("city", v), ph: "City" }),
          h(TRow, { label: "Postal code", value: ad.postal, onChange: (v) => setAddr("postal", v), ph: "Postal code" }),
          h(SRow, { label: "Country", value: ad.country, onChange: (v) => setAddr("country", v), options: COUNTRIES, span: true }))),
      !isPatient && h(USection, { title: "Professional" },
        h("div", { className: "uform-grid" },
          h(TRow, { label: "Specialization", value: f.specialization, onChange: (v) => set("specialization", v), ph: "e.g. MD, Functional Practitioner", span: true }))),
      isPatient && h(USection, { title: "Care team" },
        h("div", { className: "uform-grid" }, h(AssignmentEditor, { value: f.assignments, onChange: (v) => set("assignments", v), tenantId: f.tenant }))),
      isPatient && h(USection, { title: "Health metrics" },
        h("div", { className: "uform-grid c3" },
          h(TRow, { label: "Height (cm)", value: h2.heightCm, onChange: (v) => setH("heightCm", v), ph: "cm", type: "number" }),
          h(TRow, { label: "Weight (kg)", value: h2.weightKg, onChange: (v) => setH("weightKg", v), ph: "kg", type: "number" }),
          h(SRow, { label: "Blood type", value: h2.bloodType, onChange: (v) => setH("bloodType", v), options: BLOOD_TYPES }),
          h(TRow, { label: "Systolic (mmHg)", value: h2.systolic, onChange: (v) => setH("systolic", v), ph: "mmHg", type: "number" }),
          h(TRow, { label: "Diastolic (mmHg)", value: h2.diastolic, onChange: (v) => setH("diastolic", v), ph: "mmHg", type: "number" }),
          h(TRow, { label: "Hip-waist ratio", value: h2.hipWaist, onChange: (v) => setH("hipWaist", v), ph: "e.g. 0.85" }),
          h(SRow, { label: "Smoker", value: h2.smoker, onChange: (v) => setH("smoker", v), options: SMOKER_OPTS }),
          h(TRow, { label: "Diabetic history", value: h2.diabetic, onChange: (v) => setH("diabetic", v), ph: "No history / Type 2", span: true }),
          h(TRow, { label: "Heart / other conditions", value: h2.heartHistory, onChange: (v) => setH("heartHistory", v), ph: "Relevant conditions", span: true }))),
      isPatient && h(USection, { title: "Social profiles" },
        h(SocialEditor, { value: f.social, onChange: (v) => set("social", v) })),
      h("div", { className: "mform-note" }, h(Icon, { name: "shield", size: 14 }),
        h("span", null, "Manual create — ", h("strong", null, "no email is sent"), ". The account is created ", h("strong", null, "Active"), " immediately."))));
}

function MoveUserModal({ open, user, onClose, onMove }) {
  const others = U.TENANTS.filter((t) => !user || t.id !== user.tenant);
  const [dest, setDest] = useState(others[0] ? others[0].id : "");
  useEffect(() => { if (open) setDest(others[0] ? others[0].id : ""); }, [open, user && user.id]);
  if (!open || !user) return null;
  const destT = U.TENANTS.find((t) => t.id === dest);
  return h(Modal, { open, onClose, title: "Move user", width: 460,
    footer: h("div", { className: "drawer-actions", style: { width: "100%", justifyContent: "flex-end" } },
      h(Button, { variant: "ghost", onClick: onClose }, "Cancel"),
      h(Button, { variant: "primary", icon: "arrowRight", disabled: !dest, onClick: () => onMove(user, dest) }, "Move user")) },
    h("div", { className: "uform" },
      h("div", { className: "move-from" },
        h(AvatarImg, { user, size: 34 }),
        h("div", null, h("div", { style: { fontWeight: 600, fontSize: "13.5px" } }, uName(user)),
          h("div", { className: "dim small" }, "Currently in ", h("strong", null, U.tenantName(user.tenant))))),
      h(SRow, { label: "Move to tenant", value: dest, onChange: setDest, options: others.map((t) => ({ value: t.id, label: t.name })) }),
      h("div", { className: "mform-note" }, h(Icon, { name: "alert", size: 14 }),
        h("span", null, "The user keeps their profile and role, but their tenant membership moves to ",
          h("strong", null, destT ? destT.name : "the selected tenant"), "."))));
}

function InviteUserModal({ open, onClose, onInvite, tenant, tenants }) {
  const seed = () => ({ type: "practitioner", email: "", role: "regular", tenant: tenant ? tenant.id : (tenants[0] && tenants[0].id), specialization: "", assignments: [], note: "" });
  const [f, setF] = useState(seed());
  useEffect(() => { if (open) setF(seed()); }, [open]);
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  const ok = f.email.trim() && (f.type !== "practitioner" || f.specialization.trim());
  const isPatient = f.type === "patient";
  return h(Modal, { open, onClose, title: "Invite user", width: 500,
    footer: h("div", { className: "drawer-actions", style: { width: "100%", justifyContent: "flex-end" } },
      h(Button, { variant: "ghost", onClick: onClose }, "Cancel"),
      h(Button, { variant: "primary", icon: "external", disabled: !ok, onClick: () => onInvite(f) }, "Send invite")) },
    h("div", { className: "uform" },
      h(TypeSeg, { value: f.type, onChange: (v) => set("type", v) }),
      h(TRow, { label: "Email address", value: f.email, onChange: (v) => set("email", v), ph: "name@example.com", type: "email" }),
      h("div", { className: "uform-grid c2" },
        !tenant && h(SRow, { label: "Tenant", value: f.tenant, onChange: (v) => set("tenant", v), options: tenants.map((t) => ({ value: t.id, label: t.name })), span: true }),
        h(SRow, { label: "Tenant role", value: f.role, onChange: (v) => set("role", v), options: TENANT_ROLES, span: !!tenant })),
      !isPatient && h(TRow, { label: "Specialization", value: f.specialization, onChange: (v) => set("specialization", v), ph: "e.g. Internal Medicine" }),
      isPatient && h("div", { className: "uform-grid" }, h(AssignmentEditor, { value: f.assignments, onChange: (v) => set("assignments", v), tenantId: f.tenant })),
      h("label", { className: "field" }, h("span", { className: "field-label" }, "Note (optional)"),
        h("textarea", { className: "input", rows: 2, value: f.note, onChange: (e) => set("note", e.target.value), placeholder: "Add a personal note to the invitation…" })),
      h("div", { className: "mform-note" }, h(Icon, { name: "external", size: 14 }),
        h("span", null, "An invitation email is queued. The account stays ", h("strong", null, "Invited"), " until the recipient completes signup."))));
}

/* ======================================================================== */
/* USER MANAGER                                                              */
/* ======================================================================== */
function UserManager({ tenant, cell, getUsers, showTenantCol, subtitle }) {
  const toast = useToast();
  const api = userAPI();
  const [, setTick] = useState(0);
  const [live, setLive] = useState({ loading: false, error: "" });
  const [q, setQ] = useState("");
  const [tab, setTab] = useState("all");
  const [sel, setSel] = useState(null);
  const [ctx, setCtx] = useState(null);
  const [create, setCreate] = useState(false);
  const [invite, setInvite] = useState(false);
  const [moveUser, setMoveUser] = useState(null);
  const bump = () => setTick((t) => t + 1);
  const tenantsForPicker = tenant ? null : (cell ? U.TENANTS.filter((t) => t.cell === cell.id) : U.TENANTS);
  const loadUsers = useCallback(async () => {
    if (!api || (!api.users && !api.tenantUsers)) return;
    setLive({ loading: true, error: "" });
    try {
      const body = tenant && api.tenantUsers
        ? await api.tenantUsers(tenant.id)
        : await api.users({ cell_id: cell && cell.id });
      syncUserCache(body.users || [], tenant ? { tenant: tenant.id } : cell ? { cell: cell.id } : {});
      setLive({ loading: false, error: "" });
      bump();
    } catch (err) {
      setLive({ loading: false, error: err.message || "Unable to load users" });
    }
  }, [api, tenant && tenant.id, cell && cell.id]);
  useEffect(() => { loadUsers(); }, [loadUsers]);

  const all = (getUsers ? getUsers() : U.USERS).map(normalizeUIUser);
  const byTab = tab === "all" ? all
    : tab === "practitioners" ? all.filter((u) => u.type === "practitioner" && u.status !== "invited")
    : tab === "patients" ? all.filter((u) => u.type === "patient" && u.status !== "invited")
    : all.filter((u) => u.status === "invited");
  const rows = byTab.filter((u) => !q.trim() || (uName(u) + " " + u.email + " " + typeLabel(u.type) + " " + U.tenantName(u.tenant)).toLowerCase().includes(q.trim().toLowerCase()));
  const counts = {
    all: all.length,
    practitioners: all.filter((u) => u.type === "practitioner" && u.status !== "invited").length,
    patients: all.filter((u) => u.type === "patient" && u.status !== "invited").length,
    invitations: all.filter((u) => u.status === "invited").length,
  };
  const tabs = [
    { key: "all", label: "All users", count: counts.all },
    { key: "practitioners", label: "Practitioners", count: counts.practitioners },
    { key: "patients", label: "Patients", count: counts.patients },
    { key: "invitations", label: "Invitations", count: counts.invitations },
  ];

  const openUser = (u) => { setCtx(null); setSel(u); };
  const doAction = (action, u) => {
    if (u.isSystemManaged) { toast("System-managed account — action not allowed", "bad"); return; }
    if (action === "delete" || action === "revoke") {
      const finish = () => {
        const i = U.USERS.findIndex((x) => x.id === u.id);
        if (i >= 0) U.USERS.splice(i, 1);
        if (sel && sel.id === u.id) setSel(null);
        toast(action === "revoke" ? "Invitation revoked" : uName(u) + " deleted", "bad");
        bump();
      };
      if (api && api.patchTenantUser) {
        api.patchTenantUser(u.tenant, u.id, { status: "deleted" }).then(finish).catch((err) => toast(err.message || "Unable to delete user", "bad"));
      } else finish();
      return;
    } else if (action === "disable" || action === "enable") {
      const nextStatus = action === "enable" ? "active" : "disabled";
      const finish = (updated) => { const nu = upsertUserCache(updated || { ...u, status: nextStatus }); toast(uName(nu) + (nextStatus === "active" ? " enabled" : " disabled"), nextStatus === "active" ? "ok" : "warn"); if (sel && sel.id === u.id) setSel({ ...nu }); bump(); };
      if (api && api.patchTenantUser) api.patchTenantUser(u.tenant, u.id, { status: nextStatus }).then(finish).catch((err) => toast(err.message || "Unable to update user", "bad"));
      else finish({ ...u, status: nextStatus });
      return;
    } else if (action === "reset") { toast("Password reset link sent to " + u.email);
    } else if (action === "disableMfa") {
      const finish = (updated) => { const nu = upsertUserCache(updated || { ...u, mfa: false }); toast("MFA disabled for " + uName(nu), "warn"); if (sel && sel.id === u.id) setSel({ ...nu }); bump(); };
      if (api && api.patchTenantUser) api.patchTenantUser(u.tenant, u.id, { mfa: false }).then(finish).catch((err) => toast(err.message || "Unable to update MFA", "bad"));
      else finish({ ...u, mfa: false });
      return;
    } else if (action === "resend") { toast("Invitation resent to " + u.email);
    } else if (action === "export") { toast("Exporting " + uName(u) + " (mock)"); }
    bump();
  };
  const onRowContext = (e, u) => { e.preventDefault(); setCtx({ pos: { x: e.clientX, y: e.clientY }, user: u }); };
  const ctxItems = (u) => {
    if (u.isSystemManaged) return [{ label: "Open details", icon: "external", onClick: () => openUser(u) }, { sep: true }, { label: "System-managed", icon: "lock", disabled: true }];
    if (u.status === "invited") return [
      { label: "Open details", icon: "external", onClick: () => openUser(u) },
      { sep: true },
      { label: "Resend invite", icon: "refresh", onClick: () => doAction("resend", u) },
      { label: "Export…", icon: "download", onClick: () => doAction("export", u) },
      u.mfa && { label: "Disable MFA", icon: "shield", onClick: () => doAction("disableMfa", u) },
      { label: "Move to…", icon: "arrowRight", onClick: () => setMoveUser(u) },
      { sep: true },
      { label: "Revoke invite", icon: "trash", danger: true, onClick: () => doAction("revoke", u) },
    ].filter(Boolean);
    return [
      { label: "Open details", icon: "external", onClick: () => openUser(u) },
      { sep: true },
      { label: "Export…", icon: "download", onClick: () => doAction("export", u) },
      { label: "Password reset", icon: "key", onClick: () => doAction("reset", u) },
      u.mfa && { label: "Disable MFA", icon: "shield", onClick: () => doAction("disableMfa", u) },
      { label: "Move to…", icon: "arrowRight", onClick: () => setMoveUser(u) },
      { label: u.status === "disabled" ? "Enable" : "Disable", icon: u.status === "disabled" ? "check" : "lock", onClick: () => doAction(u.status === "disabled" ? "enable" : "disable", u) },
      { sep: true },
      { label: "Delete", icon: "trash", danger: true, onClick: () => doAction("delete", u) },
    ].filter(Boolean);
  };

  const saveUser = (f) => {
    const finish = (updated) => {
      const saved = upsertUserCache(updated || { ...f, name: uName(f) });
      setSel(null); bump(); toast("User saved", "ok");
      return saved;
    };
    if (api && api.patchTenantUser) {
      api.patchTenantUser(f.tenant, f.id, userPayload(f)).then(finish).catch((err) => toast(err.message || "Unable to save user", "bad"));
      return;
    }
    finish(f);
  };
  const createUser = (data) => {
    const local = { id: newUserId(), type: data.type, firstname: data.firstname, lastname: data.lastname, name: (data.firstname + " " + data.lastname).trim(),
      email: data.email, phoneCell: data.phoneCell || "", phoneOffice: data.phoneOffice || "", tenant: tenant ? tenant.id : data.tenant,
      role: data.type === "patient" ? "regular" : (data.role || "regular"), status: "active",
      lastActive: 0, mfa: !!data.mfa, avatar: data.avatar || "", languages: data.languages || [],
      language: data.language || (data.languages || [])[0] || "", gender: data.gender || "", dob: data.dob || "",
      address: data.address || { line: "", city: "", postal: "", country: "" } };
    if (data.type === "practitioner") {
      local.specialization = data.specialization || "";
      local.linkedin = data.linkedin || "";
      local.bio = data.bio || "";
      local.degrees = data.degrees || [];
    } else {
      local.health = data.health || {};
      local.social = data.social || {};
      local.assignments = data.assignments || [];
    }
    const finish = (created) => { const u = upsertUserCache(created || local); setCreate(false); bump(); setSel(u); toast("User created — complete the profile", "ok"); };
    if (api && api.createTenantUser) api.createTenantUser(local.tenant, createPayload(local)).then(finish).catch((err) => toast(err.message || "Unable to create user", "bad"));
    else finish(local);
  };
  const inviteUser = (data) => {
    const local = { id: newUserId(), type: data.type, firstname: data.firstname || "", lastname: data.lastname || "", name: data.email.split("@")[0],
      email: data.email, tenant: tenant ? tenant.id : data.tenant, role: data.role, status: "invited",
      lastActive: null, mfa: false, language: "", gender: "", dob: "", phoneCell: "", phoneOffice: "",
      inviteNote: data.note || "", address: { line: "", city: "", postal: "", country: "" } };
    if (data.type === "practitioner") { local.specialization = data.specialization || ""; local.degrees = []; }
    else { local.health = {}; local.assignments = data.assignments || []; }
    const finish = (invited) => { const u = upsertUserCache(invited || local); setInvite(false); bump(); setTab("invitations"); setSel(u); toast("Invitation sent to " + data.email, "ok"); };
    if (api && api.inviteTenantUser) api.inviteTenantUser(local.tenant, invitePayload(local)).then(finish).catch((err) => toast(err.message || "Unable to invite user", "bad"));
    else finish(local);
  };

  const cols = ["User", showTenantCol && "Tenant", "Type", "Role", "Status", "MFA", tab === "invitations" ? "Invited" : "Last active"].filter(Boolean);
  return h(React.Fragment, null,
    h(Card, { pad: false },
      h("div", { className: "td-tabs", style: { paddingTop: "10px" } }, h(Tabs, { tabs, active: tab, onChange: setTab })),
      live.error && h("div", { className: "scope-banner global", style: { margin: "12px 16px 0" } },
        h("span", { className: "sb-ic" }, h(Icon, { name: "alert", size: 16 })),
        h("div", { className: "sb-main" }, h("strong", null, "Live users unavailable."), " Showing local mock data. ", live.error)),
      h("div", { className: "toolbar" },
        h("div", { className: "search" }, h(Icon, { name: "search", size: 16 }),
          h("input", { className: "search-input", placeholder: "Search name, email, type…", value: q, onChange: (e) => setQ(e.target.value) })),
        h("span", { className: "toolbar-count" }, live.loading ? "Loading users…" : [rows.length, " users"]),
        h("div", { className: "toolbar-actions" },
          h(Button, { variant: "default", size: "sm", icon: "external", onClick: () => setInvite(true) }, "Invite user"),
          h(Button, { variant: "primary", size: "sm", icon: "plus", onClick: () => setCreate(true) }, "Create user"))),
      h("div", { className: "table-wrap flush" },
        h("table", { className: "table table-tight" },
          h("thead", null, h("tr", null, cols.map((c) => h("th", { key: c }, c)))),
          h("tbody", null,
            rows.map((u) => h("tr", { key: u.id, className: "row-click" + (u.isSystemManaged ? " row-system" : ""), onClick: () => openUser(u), onContextMenu: (e) => onRowContext(e, u) },
              h("td", null, h("div", { className: "user-cell" },
                h(AvatarImg, { user: u, size: 28 }),
                h("div", null,
                  h("div", { className: "user-name-row" }, uName(u), h(VerifiedTick, { verification: u.verification }), u.isSystemManaged && h("span", { className: "sys-tag" }, h(Icon, { name: "lock", size: 11 }), "System managed")),
                  h("div", { className: "dim mono small" }, u.email)))),
              showTenantCol && h("td", null, U.tenantName(u.tenant)),
              h("td", null, h(Pill, { tone: typeTone(u.type), soft: true }, typeLabel(u.type))),
              h("td", null, h(Pill, { tone: u.role === "owner" ? "accent" : "neutral", soft: true }, roleLabel(u.role))),
              h("td", null, h(Pill, { tone: STATUS_TONE[u.status] || "neutral", soft: true }, STATUS_LABEL[u.status] || u.status)),
              h("td", null, u.mfa ? h(Pill, { tone: "ok", soft: true }, "on") : h(Pill, { tone: "warn", soft: true }, "off")),
              h("td", { className: "dim" }, u.lastActive == null ? (u.status === "invited" ? "pending" : "—") : fmtAgo(U.ago(u.lastActive))))),
            !rows.length && h("tr", null, h("td", { colSpan: cols.length }, h(Empty, { icon: "tenants", title: "No users", sub: tab === "invitations" ? "No pending invitations." : "Create or invite a user to get started." }))))),
        h("div", { className: "table-hint" }, h(Icon, { name: "info", size: 13 }), h("span", null, "Click a row to view and edit. Right-click for quick actions.")))),
    ctx && h(ContextMenu, { pos: ctx.pos, items: ctxItems(ctx.user), onClose: () => setCtx(null) }),
    h(UserDrawer, { user: sel, lockTenant: !!tenant, tenants: tenantsForPicker, onClose: () => setSel(null), onSave: saveUser, onAction: doAction, toast }),
    h(CreateUserModal, { open: create, onClose: () => setCreate(false), onCreate: createUser, tenant, tenants: tenantsForPicker || U.TENANTS }),
    h(InviteUserModal, { open: invite, onClose: () => setInvite(false), onInvite: inviteUser, tenant, tenants: tenantsForPicker || U.TENANTS }),
    h(MoveUserModal, { open: !!moveUser, user: moveUser, onClose: () => setMoveUser(null), onMove: (u, dest) => { u.tenant = dest; upsertUserCache(u); setMoveUser(null); if (sel && sel.id === u.id) setSel({ ...u }); bump(); toast(uName(u) + " moved to " + U.tenantName(dest), api ? "warn" : "ok"); } }));
}

Object.assign(window, { UserManager, USER_TYPES, uName, uInitials, typeLabel });
