/* Ward Desk — routing and every commit in the product.
   The reversibility tiers are decided here, once (§3):
     · instant and harmless   → a bare control (a reaction, a filter)
     · instant, consequential → applies immediately plus an undo toast
     · irreversible           → a confirm dialog: discharging somebody, recording
                                a procedure as abandoned, stopping a course
     · needs three decisions  → a staged dialog opened from an instant screen
   Auth renders outside the shell (§7.1): it has no navigation owner, so it is
   returned before HdShell is reached rather than nested inside it. */
function App(props) {
  const options = props || {};
  const [path, setPath] = React.useState(options.startPath || "/");
  const [dark, setDark] = React.useState(options.theme === "dark");
  const [read, setRead] = React.useState(false);
  const [toasts, setToasts] = React.useState([]);
  const [confirm, setConfirm] = React.useState(null);
  const [form, setForm] = React.useState(null);
  const [medWard, setMedWard] = React.useState("all");
  const [reviewingId, setReviewingId] = React.useState(null);
  /* The address the reset flow is working on: the request screen sets it and the
     confirmation states it, so the confirmation never claims one nobody typed. */
  const [authEmail, setAuthEmail] = React.useState(HD_RESET_LINK.email);
  const [data, setData] = React.useState({
    patients: PATIENTS, admissions: ADMISSIONS, interventions: INTERVENTIONS, orders: MEDICATION_ORDERS,
    formulary: FORMULARY, staff: STAFF, comments: COMMENTS, activity: ACTIVITY,
    transfers: TRANSFERS, transferRows: TRANSFER_ROWS, wardBeds: WARD_BEDS, rota: ROTA,
    invoices: INVOICES, payments: PAYMENTS, tariffItems: TARIFF_ITEMS, contracts: CONTRACTS,
    contractPrices: CONTRACT_PRICES, chases: CHASES, sessions: SESSIONS,
  });
  const [hospital, setHospital] = React.useState(HD_HOSPITAL);
  const [prefs, setPrefs] = React.useState(NOTIFICATION_PREFS);
  const [billing, setBilling] = React.useState(BILLING_SETTINGS);
  const [integrations, setIntegrations] = React.useState(INTEGRATIONS);
  const [security, setSecurity] = React.useState(SECURITY_SETTINGS);
  /* Bumped when the role matrix is saved: the capability maps in enums.js are
     what every transition function reads, so writing into them is what makes
     Settings real — and this makes the render that follows it honest. */
  const [rolesVersion, setRolesVersion] = React.useState(0);
  const palette = useCommandPalette(!!confirm || !!form);
  const now = HD_NOW;
  /* The signed-in person is a staff record, not a second literal: the profile
     screen edits the same entry every permission predicate reads. */
  const viewer = data.staff.find((s) => s.id === HD_SIGNED_IN);

  React.useEffect(() => { if (options.startPath) setPath(options.startPath); }, [options.startPath]);
  React.useEffect(() => { setDark(options.theme === "dark"); }, [options.theme]);
  React.useEffect(() => {
    document.documentElement.classList.toggle("dark", dark);
    document.body.classList.toggle("dark", dark);
  }, [dark]);
  /* Anything scoped to one record closes when the route changes: the row-review
     state, the confirm dialog and the staged dialog all belong to the screen they
     were opened from, and a live commit closure must not outlive it. */
  React.useEffect(() => {
    if (path !== "/data") setReviewingId(null);
    setConfirm(null);
    setForm(null);
  }, [path]);

  const dismiss = (id) => setToasts((list) => list.filter((t) => t.id !== id));
  const pushToast = (toast) => {
    const id = "t" + Date.now() + Math.random().toString(36).slice(2, 6);
    setToasts((list) => list.concat([Object.assign({ id: id }, toast)]));
    setTimeout(() => dismiss(id), 7000);
  };

  const patch = (key, id, fields) => setData((d) => Object.assign({}, d, { [key]: d[key].map((r) => (r.id === id ? Object.assign({}, r, fields) : r)) }));
  const restore = (key, snapshot) => setData((d) => Object.assign({}, d, { [key]: d[key].map((r) => (r.id === snapshot.id ? snapshot : r)) }));
  const logActivity = (verb, record, note) => {
    const id = "act_" + Math.random().toString(36).slice(2, 7);
    setData((d) => Object.assign({}, d, { activity: [{ id: id, actorId: viewer.id, at: now, verb: verb, record: record, note: note || null }].concat(d.activity) }));
    return id;
  };
  const unlogActivity = (id) => setData((d) => Object.assign({}, d, { activity: d.activity.filter((a) => a.id !== id) }));

  /* ── Admissions ────────────────────────────────────────────────────────── */
  const assignBed = (admission) => {
    const patient = patientById(data.patients, admission.patientId);
    const taken = data.admissions.filter((a) => a.ward === admission.ward && a.bed).map((a) => a.bed);
    const prefix = wardName(admission.ward)[0].toUpperCase();
    const free = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((n) => prefix + "-" + String(n).padStart(2, "0")).filter((bed) => taken.indexOf(bed) < 0);
    setForm({
      title: "Assign a bed to " + patient.name,
      description: "They have waited " + formatCountdown(admission.requestedAt, now).replace(" over", "").replace(" left", "") + " for a bed on " + wardName(admission.ward) + ". Assigning one puts them on the ward and starts their length of stay.",
      submitLabel: "Assign bed",
      initial: { bed: free[0], ward: admission.ward },
      fields: [
        { id: "ward", kind: "select", label: "Ward", options: WARDS.map((w) => ({ value: w.value, label: labelOf(WARDS, w.value) })), hint: "Changing the ward moves the request as well as the bed." },
        { id: "bed", kind: "select", label: "Bed", options: free.map((bed) => ({ value: bed, label: bed })), hint: free.length + " beds on " + wardName(admission.ward) + " have nobody against them." },
      ],
      validate: (v) => (!v.bed ? { bed: "Pick a bed." } : {}),
      run: (v) => {
        const snapshot = admission;
        patch("admissions", admission.id, { status: "on_ward", ward: v.ward, bed: v.bed, admittedAt: now });
        patch("patients", patient.id, { status: "inpatient" });
        const act = logActivity("assigned a bed", { type: "admission", id: admission.id }, wardName(v.ward) + " " + v.bed);
        pushToast({
          variant: "success",
          title: "Bed assigned",
          description: patient.name + " is on " + wardName(v.ward) + " " + v.bed + " · " + (bedsWaiting(data.admissions).length - 1) + " people still waiting for a bed",
          onUndo: () => { restore("admissions", snapshot); restore("patients", patient); unlogActivity(act); },
        });
      },
    });
  };

  const markFit = (admission) => {
    const patient = patientById(data.patients, admission.patientId);
    patch("admissions", admission.id, { status: "fit_for_discharge", fitAt: now });
    const act = logActivity("marked fit for discharge", { type: "admission", id: admission.id }, null);
    pushToast({
      title: "Marked fit for discharge",
      description: patient.name + " · " + wardName(admission.ward) + " " + admission.bed + " is now being held until they go home",
      onUndo: () => { restore("admissions", admission); unlogActivity(act); },
    });
  };

  const bulkMarkFit = (admissions) => {
    const snapshot = data.admissions;
    const ids = admissions.map((a) => a.id);
    setData((d) => Object.assign({}, d, {
      admissions: d.admissions.map((a) => (ids.indexOf(a.id) > -1 ? Object.assign({}, a, { status: "fit_for_discharge", fitAt: now }) : a)),
    }));
    pushToast({
      title: admissions.length + (admissions.length === 1 ? " admission marked fit" : " admissions marked fit"),
      description: admissions.map((a) => patientName(data.patients, a.patientId)).join(", ") + " — their beds are held until they go home",
      onUndo: () => setData((d) => Object.assign({}, d, { admissions: snapshot })),
    });
  };

  const discharge = (admission) => {
    const patient = patientById(data.patients, admission.patientId);
    const live = activeOrders(ordersForPatient(data.orders, patient.id));
    setConfirm({
      title: "Discharge " + patient.name + "?",
      description: "They leave " + wardName(admission.ward) + " " + admission.bed + " after " + ADMISSION_FLAGS.lengthOfStayDays(admission, now) + " days. " +
        (live.length ? live.length + (live.length === 1 ? " active order" : " active orders") + " on their chart will be closed with the episode and cannot be reopened." : "Nothing is active on their chart.") +
        " The bed is released immediately.",
      confirmLabel: "Discharge " + patient.name.split(" ")[0],
      run: () => {
        patch("admissions", admission.id, { status: "discharged", dischargedAt: now });
        patch("patients", patient.id, { status: "discharged" });
        setData((d) => Object.assign({}, d, {
          orders: d.orders.map((o) => (o.patientId === patient.id && o.status === "active" ? Object.assign({}, o, { status: "completed", endsAt: now, nextDoseAt: null }) : o)),
        }));
        logActivity("discharged", { type: "admission", id: admission.id }, wardName(admission.ward) + " " + admission.bed + " released");
        pushToast({ title: "Discharged", description: patient.name + " has left " + wardName(admission.ward) + " " + admission.bed + " · " + live.length + (live.length === 1 ? " order closed" : " orders closed") });
      },
    });
  };

  const transferOut = (admission) => {
    const patient = patientById(data.patients, admission.patientId);
    setForm({
      title: "Transfer " + patient.name + " out",
      description: "They leave " + HD_HOSPITAL.short + " for another hospital. The episode closes here and the receiving trust takes over the record.",
      submitLabel: "Transfer out",
      initial: { destination: "", reason: "" },
      fields: [
        { id: "destination", kind: "input", label: "Receiving hospital", placeholder: "Westmere General" },
        { id: "reason", kind: "text", label: "Why", placeholder: "Needs electrophysiology, not available here.", hint: "Written onto the record as a note." },
      ],
      validate: (v) => {
        const errors = {};
        if (!v.destination || v.destination.trim().length < 3) errors.destination = "Name the hospital taking them.";
        if (!v.reason || v.reason.trim().length < 10) errors.reason = "Say why — a sentence is enough.";
        return errors;
      },
      run: (v) => {
        const snapshot = admission;
        patch("admissions", admission.id, { status: "transferred", dischargedAt: now, reason: "Transferred to " + v.destination.trim() + " — " + v.reason.trim() });
        const act = logActivity("transferred out", { type: "admission", id: admission.id }, "To " + v.destination.trim());
        pushToast({
          title: "Transferred out",
          description: patient.name + " → " + v.destination.trim() + " · the bed on " + wardName(admission.ward) + " is released",
          onUndo: () => { restore("admissions", snapshot); unlogActivity(act); },
        });
      },
    });
  };

  const onAdmissionTransition = (admission, transition) => {
    if (transition.id === "assign_bed") assignBed(admission);
    if (transition.id === "mark_fit") markFit(admission);
    if (transition.id === "discharge") discharge(admission);
    if (transition.id === "transfer_out") transferOut(admission);
  };

  /* ── Interventions ─────────────────────────────────────────────────────── */
  const scheduleIntervention = (intervention) => {
    const patient = patientById(data.patients, intervention.patientId);
    setForm({
      title: "Schedule " + intervention.name,
      description: "For " + patient.name + ", requested " + formatWhen(intervention.requestedAt, now) + ". Scheduling does not record consent — that is a separate step, and the procedure cannot start without it.",
      submitLabel: "Schedule",
      initial: { theatre: "t1", day: "1", time: "09:00" },
      fields: [
        { id: "theatre", kind: "select", label: "Theatre", options: THEATRES.map((t) => ({ value: t.value, label: t.label })) },
        { id: "day", kind: "select", label: "Day", options: [0, 1, 2, 3, 4, 5, 6].map((n) => ({ value: String(n), label: n === 0 ? "Today" : new Date(now + n * DAY_MS).toLocaleDateString("en-GB", { weekday: "long", day: "numeric", month: "short" }) })) },
        { id: "time", kind: "input", label: "Start time", placeholder: "09:00", hint: "24-hour clock. " + intervention.plannedMin + " minutes are planned for it." },
      ],
      validate: (v) => (!/^\d\d:\d\d$/.test(v.time || "") ? { time: "Use HH:MM." } : {}),
      run: (v) => {
        const snapshot = intervention;
        const [h, m] = v.time.split(":").map(Number);
        const at = dayAt(Number(v.day), h, m);
        patch("interventions", intervention.id, { status: "scheduled", theatre: v.theatre, scheduledAt: at });
        const act = logActivity("scheduled a procedure", { type: "intervention", id: intervention.id }, labelOf(THEATRES, v.theatre) + " · " + formatWhen(at, now));
        pushToast({
          variant: "success",
          title: "Scheduled",
          description: intervention.name + " · " + labelOf(THEATRES, v.theatre) + " · " + formatWhen(at, now) + " · consent is still not recorded, so it cannot start",
          onUndo: () => { restore("interventions", snapshot); unlogActivity(act); },
        });
      },
    });
  };

  const onInterventionTransition = (intervention, transition) => {
    const patient = patientById(data.patients, intervention.patientId);
    if (transition.id === "schedule") return scheduleIntervention(intervention);
    if (transition.id === "record_consent") {
      patch("interventions", intervention.id, { consentAt: now });
      const act = logActivity("recorded consent", { type: "intervention", id: intervention.id }, null);
      return pushToast({
        variant: "success", title: "Consent recorded",
        description: patient.name + " · " + intervention.name + " can now start · " + (consentMissing(data.interventions).length - 1) + " procedures still without consent",
        onUndo: () => { restore("interventions", intervention); unlogActivity(act); },
      });
    }
    if (transition.id === "start") {
      patch("interventions", intervention.id, { status: "in_theatre" });
      const act = logActivity("started in theatre", { type: "intervention", id: intervention.id }, labelOf(THEATRES, intervention.theatre));
      return pushToast({ title: "In theatre", description: intervention.name + " · " + patient.name + " · " + labelOf(THEATRES, intervention.theatre), onUndo: () => { restore("interventions", intervention); unlogActivity(act); } });
    }
    if (transition.id === "to_recovery") {
      patch("interventions", intervention.id, { status: "recovery" });
      const act = logActivity("moved to recovery", { type: "intervention", id: intervention.id }, null);
      return pushToast({ title: "In recovery", description: patient.name + " left " + labelOf(THEATRES, intervention.theatre) + " at " + formatWhen(now, now), onUndo: () => { restore("interventions", intervention); unlogActivity(act); } });
    }
    if (transition.id === "complete") {
      patch("interventions", intervention.id, { status: "completed", completedAt: now });
      const act = logActivity("completed a procedure", { type: "intervention", id: intervention.id }, intervention.plannedMin + " minutes planned");
      return pushToast({ variant: "success", title: "Completed", description: intervention.name + " · " + patient.name, onUndo: () => { restore("interventions", intervention); unlogActivity(act); } });
    }
    if (transition.id === "cancel") {
      patch("interventions", intervention.id, { status: "cancelled" });
      const act = logActivity("cancelled a procedure", { type: "intervention", id: intervention.id }, null);
      return pushToast({
        title: "Cancelled",
        description: intervention.name + " · " + patient.name + (intervention.scheduledAt ? " · the " + labelOf(THEATRES, intervention.theatre) + " slot at " + formatWhen(intervention.scheduledAt, now) + " is free" : ""),
        onUndo: () => { restore("interventions", intervention); unlogActivity(act); },
      });
    }
    if (transition.id === "abandon") {
      return setConfirm({
        title: "Record " + intervention.name + " as abandoned?",
        description: "This says the procedure started and could not be finished. It goes on " + patient.name + "'s record permanently and cannot be undone — a new request would be needed to try again.",
        confirmLabel: "Record as abandoned",
        run: () => {
          patch("interventions", intervention.id, { status: "abandoned", completedAt: now });
          logActivity("recorded a procedure as abandoned", { type: "intervention", id: intervention.id }, null);
          pushToast({ variant: "error", title: "Recorded as abandoned", description: intervention.name + " · " + patient.name });
        },
      });
    }
  };

  /* ── Medication ────────────────────────────────────────────────────────── */
  const DOSE_HOURS = { "Once daily": 24, "Twice daily": 12, "Three times daily": 8, "Four times daily": 6 };

  const onMedicationTransition = (order, transition) => {
    const patient = patientById(data.patients, order.patientId);
    const drug = drugById(data.formulary, order.drugId);
    if (transition.id === "verify") {
      const hours = DOSE_HOURS[order.frequency] || 8;
      patch("orders", order.id, { status: "active", verifiedById: viewer.id, nextDoseAt: order.nextDoseAt || now + hours * HOUR_MS });
      const act = logActivity("verified an order", { type: "medication", id: order.id }, null);
      return pushToast({
        variant: "success", title: "Order verified",
        description: order.drug + " " + order.dose + " for " + patient.name + " · " + (ordersAwaitingPharmacy(data.orders).length - 1) + " orders still awaiting a pharmacist",
        onUndo: () => { restore("orders", order); unlogActivity(act); },
      });
    }
    if (transition.id === "record_dose") {
      const hours = DOSE_HOURS[order.frequency] || 8;
      patch("orders", order.id, { lastGivenAt: now, nextDoseAt: now + hours * HOUR_MS });
      const act = logActivity("recorded a dose", { type: "medication", id: order.id }, order.dose + " " + labelOf(DRUG_ROUTES, order.route).toLowerCase());
      return pushToast({
        title: "Dose recorded",
        description: order.drug + " " + order.dose + " given to " + patient.name + " · next dose " + formatWhen(now + hours * HOUR_MS, now),
        onUndo: () => { restore("orders", order); unlogActivity(act); },
      });
    }
    if (transition.id === "hold") {
      patch("orders", order.id, { status: "on_hold", nextDoseAt: null });
      const act = logActivity("put an order on hold", { type: "medication", id: order.id }, null);
      return pushToast({ title: "On hold", description: order.drug + " for " + patient.name + " — no further doses until somebody resumes it", onUndo: () => { restore("orders", order); unlogActivity(act); } });
    }
    if (transition.id === "resume") {
      const hours = DOSE_HOURS[order.frequency] || 8;
      patch("orders", order.id, { status: "active", nextDoseAt: now + hours * HOUR_MS });
      const act = logActivity("resumed an order", { type: "medication", id: order.id }, null);
      return pushToast({ variant: "success", title: "Resumed", description: order.drug + " for " + patient.name + " · next dose " + formatWhen(now + hours * HOUR_MS, now), onUndo: () => { restore("orders", order); unlogActivity(act); } });
    }
    if (transition.id === "stop") {
      return setConfirm({
        title: "Stop " + order.drug + " for " + patient.name + "?",
        description: "The course closes now and cannot be restarted — a new order would have to be written and verified again by a pharmacist." + (drug ? " " + drug.name + " has " + formatCount(drug.onHand) + " " + drug.unit + " in stock." : ""),
        confirmLabel: "Stop course",
        run: () => {
          patch("orders", order.id, { status: "stopped", endsAt: now, nextDoseAt: null });
          logActivity("stopped a course", { type: "medication", id: order.id }, null);
          pushToast({ title: "Course stopped", description: order.drug + " " + order.dose + " · " + patient.name });
        },
      });
    }
  };

  /* ── Formulary ─────────────────────────────────────────────────────────── */
  const onReorder = (drug) => {
    patch("formulary", drug.id, { reorderedAt: now });
    pushToast({
      title: "Stock ordered",
      description: drug.name + " " + drug.form + " · " + drug.supplier + " · " + ordersForDrug(data.orders, drug.id).length + " live courses depend on it",
      onUndo: () => restore("formulary", drug),
    });
  };

  /* ── Creating records (§5: everything the product lists can be made) ───── */
  const createPatient = (values) => {
    const id = "pat_" + Math.random().toString(36).slice(2, 6);
    const number = "H-40-" + Math.floor(4600 + Math.random() * 300);
    const patient = {
      id: id, name: values.name.trim(), number: number, born: values.born.trim(), sex: values.sex,
      status: values.status, avatar: null, allergies: values.allergies.split(",").map((a) => a.trim()).filter(Boolean),
      lastReviewAt: now, gp: values.gp.trim(), phone: values.phone.trim(), registeredAt: now,
      nextOfKin: values.nextOfKin.trim() || "Not recorded",
    };
    setData((d) => Object.assign({}, d, { patients: d.patients.concat([patient]) }));
    setPath("/patients/" + id);
    pushToast({
      variant: "success", title: "Patient registered",
      description: patient.name + " · " + number + " · " + (patient.allergies.length ? patient.allergies.length + " allergy alert" + (patient.allergies.length === 1 ? "" : "s") + " recorded" : "no allergies recorded") + " · no photograph yet",
      onUndo: () => { setData((d) => Object.assign({}, d, { patients: d.patients.filter((p) => p.id !== id) })); setPath("/patients"); },
    });
  };

  const newAdmission = () => {
    const admittable = data.patients.filter((p) => {
      const admission = admissionOfPatient(data.admissions, p.id);
      return !admission || admission.status === "discharged" || admission.status === "transferred";
    });
    setForm({
      title: "New admission",
      description: "This requests a bed. Nobody is on a ward until a bed is assigned, and the wait is on the clock from the moment you save.",
      submitLabel: "Request bed",
      initial: { patient: admittable.length ? admittable[0].id : "", ward: "linden", source: "ed", reason: "", stay: "3" },
      fields: [
        { id: "patient", kind: "select", label: "Patient", options: admittable.map((p) => ({ value: p.id, label: p.name + " — " + p.number })), hint: admittable.length + " of " + data.patients.length + " registered patients are not on a ward." },
        { id: "ward", kind: "select", label: "Ward", options: WARDS.map((w) => ({ value: w.value, label: labelOf(WARDS, w.value) })) },
        { id: "source", kind: "select", label: "Coming from", options: ADMISSION_SOURCES },
        { id: "reason", kind: "input", label: "Why they need a bed", placeholder: "Chest pain, troponin rise" },
        { id: "stay", kind: "input", label: "Expected stay in days", hint: "Used to flag a stay that runs long." },
      ],
      validate: (v) => {
        const errors = {};
        if (!v.patient) errors.patient = "Pick a patient, or register them first.";
        if (!v.reason || v.reason.trim().length < 5) errors.reason = "Say why in a few words.";
        const days = Number(v.stay);
        if (!(days >= 1 && days <= 60)) errors.stay = "Between 1 and 60 days.";
        return errors;
      },
      run: (v) => {
        const id = "adm_" + Math.random().toString(36).slice(2, 6);
        const admission = {
          id: id, patientId: v.patient, ward: v.ward, bed: null, status: "awaiting_bed", source: v.source,
          reason: v.reason.trim(), requestedAt: now, admittedAt: null, fitAt: null, dischargedAt: null,
          expectedStayDays: Number(v.stay), consultantId: viewer.family === "medical" ? viewer.id : "stf_04",
        };
        setData((d) => Object.assign({}, d, { admissions: d.admissions.concat([admission]) }));
        logActivity("requested a bed", { type: "admission", id: id }, v.reason.trim());
        pushToast({
          variant: "success", title: "Bed requested",
          description: patientName(data.patients, v.patient) + " · " + wardName(v.ward) + " · " + (bedsWaiting(data.admissions).length + 1) + " people are now waiting for a bed",
          onUndo: () => setData((d) => Object.assign({}, d, { admissions: d.admissions.filter((a) => a.id !== id) })),
        });
      },
    });
  };

  const newIntervention = () => setForm({
    title: "New intervention",
    description: "It starts as a request with no theatre and no consent. Scheduling it and recording consent are the next two steps, in that order.",
    submitLabel: "Request procedure",
    initial: { patient: data.patients[0].id, name: "", specialty: "general_surgery", priority: "routine", surgeon: doctorsOf(data.staff)[0].id, minutes: "60" },
    fields: [
      { id: "patient", kind: "select", label: "Patient", options: data.patients.map((p) => ({ value: p.id, label: p.name + " — " + p.number })) },
      { id: "name", kind: "input", label: "Procedure", placeholder: "Laparoscopic cholecystectomy" },
      { id: "specialty", kind: "select", label: "Specialty", options: SPECIALTIES },
      { id: "priority", kind: "select", label: "Priority", options: PRIORITIES },
      { id: "surgeon", kind: "select", label: "Under", options: doctorsOf(data.staff).filter((s) => s.status === "active").map((s) => ({ value: s.id, label: s.name + " — " + s.jobTitle })) },
      { id: "minutes", kind: "input", label: "Planned minutes", hint: "What theatre will hold for it." },
    ],
    validate: (v) => {
      const errors = {};
      if (!v.name || v.name.trim().length < 4) errors.name = "Name the procedure.";
      const minutes = Number(v.minutes);
      if (!(minutes >= 10 && minutes <= 480)) errors.minutes = "Between 10 and 480 minutes.";
      return errors;
    },
    run: (v) => {
      const id = "int_" + Math.random().toString(36).slice(2, 6);
      const intervention = {
        id: id, patientId: v.patient, name: v.name.trim(), specialty: v.specialty, priority: v.priority,
        status: "requested", theatre: null, requestedAt: now, scheduledAt: null, consentAt: null,
        surgeonId: v.surgeon, anaesthetistId: null, plannedMin: Number(v.minutes), completedAt: null,
        notes: "Requested by " + viewer.name + " on " + formatAbsolute(now).split(",")[0] + ".",
      };
      setData((d) => Object.assign({}, d, { interventions: d.interventions.concat([intervention]) }));
      logActivity("requested a procedure", { type: "intervention", id: id }, labelOf(PRIORITIES, v.priority));
      setPath("/interventions/" + id);
      pushToast({
        variant: "success", title: "Procedure requested",
        description: intervention.name + " · " + patientName(data.patients, v.patient) + " · not scheduled and no consent, so it counts against both badges",
        onUndo: () => { setData((d) => Object.assign({}, d, { interventions: d.interventions.filter((i) => i.id !== id) })); setPath("/interventions"); },
      });
    },
  });

  const newOrder = () => setForm({
    title: "New medication order",
    description: "It arrives awaiting verification. A pharmacist has to verify it before the first dose can be given.",
    submitLabel: "Write order",
    initial: { patient: data.patients[0].id, drug: data.formulary[0].id, dose: "", frequency: "Three times daily", indication: "" },
    fields: [
      { id: "patient", kind: "select", label: "Patient", options: data.patients.map((p) => ({ value: p.id, label: p.name + " — " + p.number + (PATIENT_FLAGS.hasAllergyAlert(p) ? " · allergic to " + p.allergies.join(", ") : "") })) },
      { id: "drug", kind: "select", label: "Drug", options: data.formulary.filter((d) => d.stock !== "discontinued").map((d) => ({ value: d.id, label: d.name + " " + d.form + (d.stock === "out" ? " — out of stock" : "") })) },
      { id: "dose", kind: "input", label: "Dose", placeholder: "1 g" },
      { id: "frequency", kind: "select", label: "Frequency", options: ["Once daily", "Twice daily", "Three times daily", "Four times daily", "As required, eight hourly"].map((f) => ({ value: f, label: f })) },
      { id: "indication", kind: "input", label: "Indication", placeholder: "Wound infection" },
    ],
    validate: (v) => {
      const errors = {};
      if (!v.dose || !/\d/.test(v.dose)) errors.dose = "Give a dose with a number in it.";
      if (!v.indication || v.indication.trim().length < 4) errors.indication = "Say what it is for.";
      const drug = drugById(data.formulary, v.drug);
      const patient = patientById(data.patients, v.patient);
      if (drug && patient && patient.allergies.some((a) => drug.name.toLowerCase().indexOf(a.toLowerCase().slice(0, 6)) > -1)) errors.drug = patient.name + " is recorded as allergic to " + patient.allergies.join(", ") + ".";
      return errors;
    },
    run: (v) => {
      const id = "med_" + Math.random().toString(36).slice(2, 6);
      const drug = drugById(data.formulary, v.drug);
      const order = {
        id: id, patientId: v.patient, drug: drug.name, dose: v.dose.trim(), route: drug.route, frequency: v.frequency,
        status: "awaiting_verification", indication: v.indication.trim(), prescriberId: viewer.id, verifiedById: null,
        startedAt: now, nextDoseAt: null, lastGivenAt: null, endsAt: null, drugId: drug.id,
      };
      setData((d) => Object.assign({}, d, { orders: d.orders.concat([order]) }));
      logActivity("wrote an order", { type: "medication", id: id }, drug.name + " " + v.dose.trim());
      pushToast({
        variant: "success", title: "Order written",
        description: drug.name + " " + order.dose + " for " + patientName(data.patients, v.patient) + " · " + (ordersAwaitingPharmacy(data.orders).length + 1) + " orders now awaiting a pharmacist" + (drug.stock === "out" ? " · nothing in stock to dispense" : ""),
        onUndo: () => setData((d) => Object.assign({}, d, { orders: d.orders.filter((o) => o.id !== id) })),
      });
    },
  });

  const newFormularyLine = () => setForm({
    title: "New formulary line",
    description: "A line can be prescribed the moment it exists. Its stock state is worked out from what you hold against the reorder level.",
    submitLabel: "Add line",
    initial: { name: "", form: "", route: "oral", onHand: "0", reorderAt: "50", unit: "tablets", supplier: "Trust wholesaler" },
    fields: [
      { id: "name", kind: "input", label: "Drug", placeholder: "Oxycodone" },
      { id: "form", kind: "input", label: "Form", placeholder: "5 mg capsule" },
      { id: "route", kind: "select", label: "Route", options: DRUG_ROUTES },
      { id: "onHand", kind: "input", label: "Held now" },
      { id: "reorderAt", kind: "input", label: "Reorder at" },
      { id: "unit", kind: "input", label: "Counted in", placeholder: "capsules" },
      { id: "supplier", kind: "input", label: "Supplier" },
    ],
    validate: (v) => {
      const errors = {};
      if (!v.name || v.name.trim().length < 3) errors.name = "Name the drug.";
      else if (data.formulary.some((d) => d.name.toLowerCase() === v.name.trim().toLowerCase())) errors.name = "That drug is already in the formulary.";
      if (!v.form || v.form.trim().length < 3) errors.form = "Give the form and strength.";
      if (!/^\d+$/.test(v.onHand || "")) errors.onHand = "A whole number.";
      if (!/^\d+$/.test(v.reorderAt || "")) errors.reorderAt = "A whole number.";
      return errors;
    },
    run: (v) => {
      const id = "drg_" + Math.random().toString(36).slice(2, 6);
      const onHand = Number(v.onHand), reorderAt = Number(v.reorderAt);
      const line = {
        id: id, name: v.name.trim(), form: v.form.trim(), route: v.route,
        stock: onHand === 0 ? "out" : onHand <= reorderAt ? "low" : "in_stock",
        onHand: onHand, reorderAt: reorderAt, unit: v.unit.trim() || "units", supplier: v.supplier.trim(),
        earliestExpiry: null, controlled: false,
      };
      setData((d) => Object.assign({}, d, { formulary: d.formulary.concat([line]) }));
      pushToast({
        variant: "success", title: "Formulary line added",
        description: line.name + " " + line.form + " · " + statusValue(STOCK_STATUS, line.stock).label.toLowerCase() + " at " + formatCount(onHand) + " " + line.unit,
        onUndo: () => setData((d) => Object.assign({}, d, { formulary: d.formulary.filter((x) => x.id !== id) })),
      });
    },
  });

  const newEmployee = () => setForm({
    title: "New employee",
    description: "They arrive onboarding: the badge exists and Ward Desk works, but nothing is signed in their name until somebody marks them active.",
    submitLabel: "Add employee",
    initial: { name: "", email: "", family: "nursing", jobTitle: "", staffRole: "clinician", ward: "beaumont" },
    fields: [
      { id: "name", kind: "input", label: "Name", placeholder: "Saoirse Whelan" },
      { id: "email", kind: "input", label: "Work email", placeholder: "s.whelan@haldengeneral.nhs.uk" },
      { id: "family", kind: "select", label: "Job family", options: JOB_FAMILIES },
      { id: "jobTitle", kind: "input", label: "Job title", placeholder: "Staff nurse" },
      { id: "staffRole", kind: "radio", label: "What they may do", options: STAFF_ROLES.map((role) => ({ value: role.value, label: role.label + " — " + (ROLE_CAN_VERIFY_MEDICATION[role.value] ? "verifies medication orders" : ROLE_CAN_MOVE_ADMISSION[role.value] ? "moves admissions and beds" : "reads only") })) },
      { id: "ward", kind: "select", label: "Base ward", options: [{ value: "", label: "No base ward" }].concat(WARDS.map((w) => ({ value: w.value, label: wardName(w.value) }))) },
    ],
    validate: (v) => {
      const errors = {};
      if (!v.name || v.name.trim().split(/\s+/).length < 2) errors.name = "Give a full name.";
      if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test((v.email || "").trim())) errors.email = "Enter a valid email address.";
      else if (data.staff.some((s) => s.email.toLowerCase() === v.email.trim().toLowerCase())) errors.email = "Somebody already has that address.";
      if (!v.jobTitle || v.jobTitle.trim().length < 3) errors.jobTitle = "Give their job title.";
      return errors;
    },
    run: (v) => {
      const id = "stf_" + Math.random().toString(36).slice(2, 6);
      const person = {
        id: id, name: v.name.trim(), email: v.email.trim().toLowerCase(), family: v.family,
        jobTitle: v.jobTitle.trim(), specialty: null, staffRole: v.staffRole, status: "onboarding",
        ward: v.ward || null, avatar: null, startedAt: now, phone: "ext 4000", gmc: null, timezone: hospital.timezone,
      };
      setData((d) => Object.assign({}, d, { staff: d.staff.concat([person]) }));
      pushToast({
        variant: "success", title: "Employee added",
        description: person.name + " · " + labelOf(JOB_FAMILIES, v.family) + " · " + labelOf(STAFF_ROLES, v.staffRole) + " · onboarding, so nothing can be signed in their name yet",
        onUndo: () => setData((d) => Object.assign({}, d, { staff: d.staff.filter((s) => s.id !== id) })),
      });
    },
  });

  /* ── Access ────────────────────────────────────────────────────────────── */
  const onStaffTransition = (person, transition) => {
    if (transition.id === "suspend") {
      return setForm({
        title: "Suspend " + person.name + "'s access",
        description: "They keep their record and their history. They cannot open Ward Desk, and nothing can be signed in their name, until access is restored.",
        submitLabel: "Suspend access",
        initial: { note: "" },
        fields: [{ id: "note", kind: "text", label: "Reason", placeholder: "Access suspended pending an information-governance review opened 4 March.", hint: "Shown on their record and on the Employees screen." }],
        validate: (v) => (!v.note || v.note.trim().length < 12 ? { note: "Record the reason — a sentence is enough." } : {}),
        run: (v) => {
          patch("staff", person.id, { status: "suspended", suspendedNote: v.note.trim() });
          pushToast({ title: "Access suspended", description: person.name + " · " + person.jobTitle, onUndo: () => restore("staff", person) });
        },
      });
    }
    const next = { activate: "active", restore: "active", returned: "active" }[transition.id];
    patch("staff", person.id, { status: next, suspendedNote: undefined });
    pushToast({
      variant: "success",
      title: transition.id === "activate" ? "Marked active" : transition.id === "restore" ? "Access restored" : "Marked returned",
      description: person.name + " · " + labelOf(STAFF_ROLES, person.staffRole) + " · they can sign work in their own name again",
      onUndo: () => restore("staff", person),
    });
  };

  /* Finance and credit control commit in their own file — App.jsx is the router
     and the commit index, not the place every dialog is spelled out. The factory
     is given exactly what a commit needs, so nothing there reaches for state it
     does not own. */
  const money = makeFinanceCommits({
    data: data, setData: setData, patch: patch, restore: restore, logActivity: logActivity,
    unlogActivity: unlogActivity, pushToast: pushToast, setForm: setForm, setConfirm: setConfirm,
    viewer: viewer, now: now, setPath: setPath, billing: billing,
  });
  const { onInvoiceTransition, bulkIssue, recordPayment, newInvoice, onChase } = money;

  /* ── Import and export ─────────────────────────────────────────────────── */
  const onExport = (label, scope, rows, format) => {
    const id = "trf_" + Math.random().toString(36).slice(2, 6);
    const job = {
      id: id, kind: "export", label: label, scope: scope, format: format, source: null,
      status: "completed", rows: rows, accepted: rows, rejected: 0, pending: 0,
      startedAt: now, finishedAt: now, byId: viewer.id,
      fileName: label.toLowerCase().replace(/[^a-z0-9]+/g, "-") + "-17-03-2026." + format.toLowerCase(), sizeKb: Math.max(1, Math.round(rows * 1.4)),
    };
    setData((d) => Object.assign({}, d, { transfers: [job].concat(d.transfers) }));
    logActivity("exported a report", { type: "transfer", id: id }, label + ", " + format);
    pushToast({
      variant: "success", title: "Export ready",
      description: formatCount(rows) + " rows · " + scope + " · " + job.fileName + " · kept for " + hospital.retentionYears + " years",
    });
  };

  const onImport = () => setForm({
    title: "Import data",
    description: "The file is parsed and every row matched against the patient index. Nothing is written until you have decided what to do with the rows that cannot be placed.",
    submitLabel: "Start import",
    initial: { source: "pas_csv", fileName: "", rows: "" },
    fields: [
      { id: "source", kind: "select", label: "Where it is from", options: IMPORT_SOURCES.filter((s) => integrations.some((i) => i.source === s.value && i.enabled)), hint: integrations.filter((i) => !i.enabled).length ? integrations.filter((i) => !i.enabled).length + " further feeds are switched off in Settings and cannot be imported from." : null },
      { id: "fileName", kind: "input", label: "File", placeholder: "pas-index-17-03-2026.csv", hint: "The file name is kept with the job so the run can be traced." },
      { id: "rows", kind: "input", label: "Rows in the file", hint: "The sending system states this in its header." },
    ],
    validate: (v) => {
      const errors = {};
      if (!v.fileName || v.fileName.trim().length < 5) errors.fileName = "Name the file, with its extension.";
      if (!/^\d+$/.test(v.rows || "") || Number(v.rows) < 1) errors.rows = "A whole number of rows.";
      return errors;
    },
    run: (v) => {
      const id = "trf_" + Math.random().toString(36).slice(2, 6);
      const source = IMPORT_SOURCES.find((s) => s.value === v.source);
      const job = {
        id: id, kind: "import", label: source.label.split(" — ")[0], scope: "Uploaded by " + viewer.name, format: source.label.split(" — ")[1] || "CSV",
        source: v.source, status: "queued", rows: Number(v.rows), accepted: 0, rejected: 0, pending: 0,
        startedAt: now, finishedAt: null, byId: viewer.id, fileName: v.fileName.trim(), sizeKb: Math.round(Number(v.rows) * 1.3),
      };
      setData((d) => Object.assign({}, d, { transfers: [job].concat(d.transfers) }));
      logActivity("queued an import", { type: "transfer", id: id }, formatCount(Number(v.rows)) + " rows from " + job.label);
      pushToast({
        title: "Import queued",
        description: formatCount(Number(v.rows)) + " rows from " + job.label + " · nothing is written into the patient index until it runs",
        onUndo: () => setData((d) => Object.assign({}, d, { transfers: d.transfers.filter((t) => t.id !== id) })),
      });
    },
  });

  const onTransferTransition = (job, transition) => {
    if (transition.id === "retry_job") {
      patch("transfers", job.id, { status: "queued", startedAt: now, finishedAt: null, failure: undefined });
      pushToast({ title: "Queued again", description: job.label + " · " + job.fileName + " · it will run against the same file", onUndo: () => restore("transfers", job) });
    }
    if (transition.id === "download_file") {
      pushToast({ title: "File sent to your browser", description: job.fileName + " · " + formatCount(job.rows) + " rows · " + job.sizeKb + " KB" });
    }
  };

  /* Deciding a row writes into the fixture, so the job's own accepted, rejected
     and pending counts — and the nav badge above them — move with the decision. */
  const onRowDecision = (job, row, decision) => {
    const snapshotRows = data.transferRows[job.id];
    const snapshotJob = job;
    const remaining = snapshotRows.filter((r) => r.line !== row.line);
    setData((d) => Object.assign({}, d, {
      transferRows: Object.assign({}, d.transferRows, { [job.id]: remaining }),
      transfers: d.transfers.map((t) => (t.id === job.id ? Object.assign({}, t, {
        accepted: t.accepted + (decision === "accept" ? 1 : 0),
        rejected: t.rejected + (decision === "reject" ? 1 : 0),
        pending: remaining.length,
        status: remaining.length ? "needs_review" : "completed",
        finishedAt: remaining.length ? t.finishedAt : now,
      }) : t)),
    }));
    pushToast({
      title: decision === "accept" ? "Row accepted" : "Row rejected",
      description: "Line " + row.line + " · " + (decision === "accept" ? row.detail.replace("Matches", "written against") : "left in the file and sent to " + hospital.recordsEmail) + " · " + remaining.length + " rows still to decide",
      onUndo: () => setData((d) => Object.assign({}, d, {
        transferRows: Object.assign({}, d.transferRows, { [job.id]: snapshotRows }),
        transfers: d.transfers.map((t) => (t.id === job.id ? snapshotJob : t)),
      })),
    });
  };

  const onAcceptMatched = (job, matched) => {
    const snapshotRows = data.transferRows[job.id];
    const snapshotJob = job;
    const lines = matched.map((r) => r.line);
    const remaining = snapshotRows.filter((r) => lines.indexOf(r.line) < 0);
    setData((d) => Object.assign({}, d, {
      transferRows: Object.assign({}, d.transferRows, { [job.id]: remaining }),
      transfers: d.transfers.map((t) => (t.id === job.id ? Object.assign({}, t, {
        accepted: t.accepted + matched.length, pending: remaining.length,
        status: remaining.length ? "needs_review" : "completed",
        finishedAt: remaining.length ? t.finishedAt : now,
      }) : t)),
    }));
    pushToast({
      variant: "success",
      title: matched.length + " rows accepted",
      description: "Each matched an existing patient on name and date of birth · " + remaining.length + " rows still to decide",
      onUndo: () => setData((d) => Object.assign({}, d, {
        transferRows: Object.assign({}, d.transferRows, { [job.id]: snapshotRows }),
        transfers: d.transfers.map((t) => (t.id === job.id ? snapshotJob : t)),
      })),
    });
  };

  /* ── The social layer, instant ─────────────────────────────────────────── */
  const onPostNote = (record, body) => {
    const id = "cmt_" + Math.random().toString(36).slice(2, 7);
    const comment = {
      id: id, record: record, authorId: viewer.id, at: now, body: body,
      mentions: (body.match(/@stf_\w+/g) || []).map((m) => m.slice(1)),
      reactions: {},
    };
    setData((d) => Object.assign({}, d, {
      comments: d.comments.concat([comment]),
      activity: [{ id: "act_" + id, actorId: viewer.id, at: now, verb: "commented", record: record, note: null }].concat(d.activity),
    }));
    const named = comment.mentions.map((m) => staffName(data.staff, m));
    pushToast({
      variant: "success", title: "Note posted",
      description: named.length
        ? "On " + recordTitle(data, record.type, record.id) + " · waiting on " + named.join(" and ") + " until they write on it"
        : "On " + recordTitle(data, record.type, record.id) + " · nobody was mentioned, so nothing is waiting on anyone",
      onUndo: () => setData((d) => Object.assign({}, d, {
        comments: d.comments.filter((c) => c.id !== id),
        activity: d.activity.filter((a) => a.id !== "act_" + id),
      })),
    });
  };

  /* Instant and harmless, so it is a bare control: no toast, no confirm.
     Clicking again takes yours off. */
  const onReactToNote = (comment, key) => setData((d) => Object.assign({}, d, {
    comments: d.comments.map((c) => {
      if (c.id !== comment.id) return c;
      const ids = c.reactions[key] || [];
      const next = ids.indexOf(viewer.id) > -1 ? ids.filter((id) => id !== viewer.id) : ids.concat([viewer.id]);
      const reactions = Object.assign({}, c.reactions);
      if (next.length) reactions[key] = next; else delete reactions[key];
      return Object.assign({}, c, { reactions: reactions });
    }),
  }));

  /* ── Staged screens ───────────────────────────────────────────────────── */
  const saveWards = (rows) => {
    const before = data.wardBeds;
    setData((d) => Object.assign({}, d, {
      wardBeds: d.wardBeds.map((w) => {
        const row = rows.find((r) => r.ward === w.ward);
        return row ? { ward: w.ward, beds: Number(row.beds), establishment: { day: Number(row.day), late: Number(row.late), night: Number(row.night) } } : w;
      }),
    }));
    const beds = rows.reduce((n, r) => n + Number(r.beds), 0);
    const occupied = onWard(data.admissions).concat(fitForDischarge(data.admissions)).length;
    pushToast({
      variant: "success", title: "Wards saved",
      description: beds + " beds across " + rows.length + " wards · occupancy now reads " + Math.round((occupied / beds) * 100) + "% on Today, Wards and Reports",
      onUndo: () => setData((d) => Object.assign({}, d, { wardBeds: before })),
    });
  };

  /* The capability maps in enums.js are the live source every transition reads,
     so saving writes into them rather than into a copy nothing consults. */
  const saveRoles = (rows) => {
    const before = rows.map((row) => ({
      role: row.role,
      verify: !!ROLE_CAN_VERIFY_MEDICATION[row.role], move: !!ROLE_CAN_MOVE_ADMISSION[row.role],
      consent: !!ROLE_CAN_RECORD_CONSENT[row.role], import: !!ROLE_CAN_IMPORT[row.role], bill: !!ROLE_CAN_BILL[row.role],
    }));
    const apply = (list) => {
      list.forEach((row) => {
        ROLE_CAN_VERIFY_MEDICATION[row.role] = row.verify;
        ROLE_CAN_MOVE_ADMISSION[row.role] = row.move;
        ROLE_CAN_RECORD_CONSENT[row.role] = row.consent;
        ROLE_CAN_IMPORT[row.role] = row.import;
        ROLE_CAN_BILL[row.role] = row.bill;
      });
      setRolesVersion((n) => n + 1);
    };
    apply(rows);
    const mine = rows.find((r) => r.role === viewer.staffRole);
    const gained = mine ? ["verify", "move", "consent", "import", "bill"].filter((k) => mine[k]).length : 0;
    pushToast({
      variant: "success", title: "Permissions saved",
      description: "Your role can now do " + gained + " of the 5 things · every row action and every disabled reason in the product reads this",
      onUndo: () => apply(before),
    });
  };

  const saveBilling = (values) => {
    const before = billing;
    setBilling(values);
    pushToast({
      variant: "success", title: "Billing saved",
      description: values.referencePrefix + " on new invoices · balances over " + formatPounds(values.writeOffThresholdMinor) + " need " + values.approver.toLowerCase() + " approval to write off",
      onUndo: () => setBilling(before),
    });
  };

  const saveIntegrations = (rows) => {
    const before = integrations;
    setIntegrations(rows);
    const on = rows.filter((r) => r.enabled);
    pushToast({
      variant: "success", title: "Integrations saved",
      description: on.length + " of " + rows.length + " feeds are available to import · " + rows.filter((r) => r.enabled && r.autoAccept).length + " auto-accept matched rows",
      onUndo: () => setIntegrations(before),
    });
  };

  const saveNotifications = (values) => {
    const before = prefs;
    setPrefs(Object.assign({}, prefs, { rows: values.rows, quietHours: values.quietHours }));
    const paged = values.rows.filter((r) => r.pager).length;
    pushToast({
      variant: "success", title: "Notifications saved",
      description: paged + " of " + values.rows.length + " events page somebody · quiet from " + values.quietHours.from + " to " + values.quietHours.to,
      onUndo: () => setPrefs(before),
    });
  };

  const saveSecurity = (values) => {
    const before = security;
    setSecurity(values);
    pushToast({
      variant: "success", title: "Security saved",
      description: "Idle sessions lock after " + values.sessionMinutes + " minutes · " + (values.requireTwoFactor ? "a second factor is required" : "no second factor is required") + " · passwords expire after " + values.passwordAgeDays + " days",
      onUndo: () => setSecurity(before),
    });
  };

  const onSaveProfile = (values) => {
    const before = viewer;
    patch("staff", viewer.id, values);
    const uploaded = values.avatar && values.avatar.indexOf("data:") === 0;
    pushToast({
      variant: "success", title: "Profile saved",
      description: values.name + " · " + values.jobTitle + " · " + (uploaded ? "your uploaded photograph is" : values.avatar ? "your badge photograph is" : "no photograph is") + " now beside every note you have written",
      onUndo: () => restore("staff", before),
    });
  };

  const saveHospital = (values) => {
    const before = hospital;
    setHospital(Object.assign({}, hospital, {
      name: values.name.trim(), trust: values.trust.trim(), recordsEmail: values.recordsEmail.trim(),
      retentionYears: Number(values.retentionYears), timezone: values.timezone,
    }));
    pushToast({
      variant: "success", title: "Hospital saved",
      description: values.name.trim() + " · exports kept " + values.retentionYears + " years · rejected rows go to " + values.recordsEmail.trim(),
      onUndo: () => setHospital(before),
    });
  };

  /* Harness chrome, not product chrome: the floating page menu is how a reader
     reaches every registered screen, including the auth ones the shell cannot
     render. It sits outside the shell so it is on those screens too. */
  const preview = (
    <TemplateMenu product="Ward Desk" path={path} onNavigate={setPath} groups={HD_PAGES(data)}
      dark={dark} onToggleTheme={() => setDark(!dark)} />
  );

  if (HD_AUTH_PATHS.indexOf(path) > -1) {
    const authScreen = () => {
      if (path === "/forgot-password") return <ForgotPasswordScreen email={authEmail} onSubmit={(value) => { setAuthEmail(value); setPath("/forgot-password/sent"); }} onNavigate={setPath} />;
      if (path === "/forgot-password/sent") return <ResetLinkSentScreen email={authEmail} onNavigate={setPath} />;
      if (path === "/reset-password") return <SetNewPasswordScreen now={now} onSubmit={() => setPath("/reset-password/done")} onNavigate={setPath} />;
      if (path === "/reset-password/expired") return <ResetLinkExpiredScreen onNavigate={setPath} />;
      if (path === "/reset-password/done") return <PasswordResetDoneScreen email={HD_RESET_LINK.email} onNavigate={setPath} />;
      return <SignInScreen onSignIn={() => setPath("/")} onNavigate={setPath} />;
    };
    return (<>{authScreen()}{preview}</>);
  }

  const patientMatch = path.match(/^\/patients\/([^/]+)$/);
  const selectedPatient = patientMatch && data.patients.some((p) => p.id === patientMatch[1]) ? patientMatch[1] : null;
  const interventionMatch = path.match(/^\/interventions\/([^/]+)$/);
  const selectedIntervention = interventionMatch && data.interventions.some((i) => i.id === interventionMatch[1]) ? interventionMatch[1] : null;
  const invoiceMatch = path.match(/^\/invoices\/([^/]+)$/);
  const selectedInvoice = invoiceMatch && data.invoices.some((i) => i.id === invoiceMatch[1]) ? invoiceMatch[1] : null;
  const doctorMatch = path.match(/^\/doctors\/([^/]+)$/);
  const employeeMatch = path.match(/^\/employees\/([^/]+)$/);
  const staffMatch = (doctorMatch && data.staff.some((s) => s.id === doctorMatch[1]) ? doctorMatch[1] : null)
    || (employeeMatch && data.staff.some((s) => s.id === employeeMatch[1]) ? employeeMatch[1] : null);

  const screen = () => {
    if (path === "/") {
      return <TodayScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onAdmissionTransition={onAdmissionTransition} onInterventionTransition={onInterventionTransition}
        onReactToNote={onReactToNote} onExport={onExport} />;
    }
    if (path === "/patients/new") return <NewPatientScreen data={data} viewer={viewer} onCreate={createPatient} onNavigate={setPath} />;
    if (selectedPatient) {
      return <PatientScreen data={data} now={now} viewer={viewer} patientId={selectedPatient} onNavigate={setPath}
        onAdmissionTransition={onAdmissionTransition} onMedicationTransition={onMedicationTransition}
        onPostNote={onPostNote} onReactToNote={onReactToNote} onExport={onExport} />;
    }
    if (path === "/patients") {
      return <PatientsScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onNewPatient={() => setPath("/patients/new")} onImport={onImport} onExport={onExport} />;
    }
    if (path === "/admissions") {
      return <AdmissionsScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onAdmissionTransition={onAdmissionTransition} onBulkMarkFit={bulkMarkFit} onNewAdmission={newAdmission}
        onImport={onImport} onExport={onExport} />;
    }
    if (selectedIntervention) {
      return <InterventionScreen data={data} now={now} viewer={viewer} interventionId={selectedIntervention} onNavigate={setPath}
        onInterventionTransition={onInterventionTransition} onPostNote={onPostNote} onReactToNote={onReactToNote} onExport={onExport} />;
    }
    if (path === "/interventions") {
      return <InterventionsScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onInterventionTransition={onInterventionTransition} onNewIntervention={newIntervention} onExport={onExport} />;
    }
    if (path === "/contracts") return <ContractsScreen data={data} now={now} viewer={viewer} onNavigate={setPath} onExport={onExport} />;
    if (path === "/credit-control") return <CreditControlScreen data={data} now={now} viewer={viewer} onNavigate={setPath} onChase={onChase} onExport={onExport} />;
    if (path === "/margin") return <MarginScreen data={data} now={now} viewer={viewer} onNavigate={setPath} onExport={onExport} />;
    if (selectedInvoice) {
      return <InvoiceScreen data={data} now={now} viewer={viewer} invoiceId={selectedInvoice} onNavigate={setPath}
        onInvoiceTransition={onInvoiceTransition} onPostNote={onPostNote} onReactToNote={onReactToNote} onExport={onExport} />;
    }
    if (path === "/invoices") {
      return <InvoicesScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onInvoiceTransition={onInvoiceTransition} onBulkIssue={bulkIssue} onNewInvoice={newInvoice} onExport={onExport} />;
    }
    if (path === "/payments") {
      return <PaymentsScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onNewPayment={() => recordPayment(null)} onExport={onExport} />;
    }
    if (path === "/revenue") return <RevenueScreen data={data} now={now} viewer={viewer} onNavigate={setPath} onExport={onExport} />;
    if (path === "/wards") {
      return <WardsScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onAdmissionTransition={onAdmissionTransition} onExport={onExport} />;
    }
    if (path === "/rota") return <RotaScreen data={data} now={now} viewer={viewer} onNavigate={setPath} onExport={onExport} />;
    if (path === "/rounds") {
      return <RoundsScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onMedicationTransition={onMedicationTransition} onExport={onExport} />;
    }
    if (path === "/reports") return <ReportsScreen data={data} now={now} viewer={viewer} onNavigate={setPath} onExport={onExport} />;
    if (path === "/medication") {
      return <MedicationScreen data={data} now={now} viewer={viewer} ward={medWard} onWardChange={setMedWard} onNavigate={setPath}
        onMedicationTransition={onMedicationTransition} onNewOrder={newOrder} onExport={onExport} />;
    }
    if (path === "/formulary") {
      return <FormularyScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onReorder={onReorder} onNewLine={newFormularyLine} onImport={onImport} onExport={onExport} />;
    }
    if (staffMatch) {
      return <StaffScreen data={data} now={now} viewer={viewer} staffId={staffMatch}
        routePath={doctorMatch ? "/doctors/:id" : "/employees/:id"} onNavigate={setPath}
        onStaffTransition={onStaffTransition} onReactToNote={onReactToNote} onExport={onExport} />;
    }
    if (path === "/doctors") return <DoctorsScreen data={data} now={now} viewer={viewer} onNavigate={setPath} onStaffTransition={onStaffTransition} onExport={onExport} />;
    if (path === "/employees") {
      return <EmployeesScreen data={data} now={now} viewer={viewer} onNavigate={setPath}
        onStaffTransition={onStaffTransition} onNewEmployee={newEmployee} onImport={onImport} onExport={onExport} />;
    }
    if (path === "/feed") return <FeedScreen data={data} now={now} viewer={viewer} onNavigate={setPath} onReactToNote={onReactToNote} onExport={onExport} />;
    if (path === "/data") {
      return <DataScreen data={data} now={now} viewer={viewer} reviewingId={reviewingId}
        onReview={setReviewingId} onCloseReview={() => setReviewingId(null)}
        onTransferTransition={onTransferTransition} onImport={onImport} onExport={onExport}
        onRowDecision={onRowDecision} onAcceptMatched={onAcceptMatched} onPostNote={onPostNote} onReactToNote={onReactToNote} />;
    }
    if (path === "/me/profile") return <MyProfileScreen data={data} now={now} viewer={viewer} onSave={onSaveProfile} onNavigate={setPath} />;
    if (path === "/settings") return <HospitalSettingsScreen data={data} hospital={hospital} viewer={viewer} onNavigate={setPath} onSave={saveHospital} />;
    if (path === "/settings/wards") return <WardSettingsScreen data={data} now={now} viewer={viewer} onNavigate={setPath} onSave={saveWards} />;
    if (path === "/settings/roles") return <RoleSettingsScreen key={rolesVersion} data={data} viewer={viewer} onNavigate={setPath} onSave={saveRoles} />;
    if (path === "/settings/billing") return <BillingSettingsScreen data={data} now={now} billing={billing} viewer={viewer} onNavigate={setPath} onSave={saveBilling} />;
    if (path === "/settings/integrations") return <IntegrationSettingsScreen data={data} now={now} integrations={integrations} viewer={viewer} onNavigate={setPath} onSave={saveIntegrations} />;
    if (path === "/settings/notifications") return <NotificationSettingsScreen data={data} prefs={prefs} hospital={hospital} viewer={viewer} onNavigate={setPath} onSave={saveNotifications} />;
    if (path === "/settings/security") return <SecuritySettingsScreen data={data} now={now} security={security} viewer={viewer} onNavigate={setPath} onSave={saveSecurity} />;
    return <RouteNotBuilt path={path} onNavigate={setPath} />;
  };

  const recordGroups = [
    { label: "Waiting for a bed", items: bedsWaiting(data.admissions).map((a) => ({ value: a.id, label: patientName(data.patients, a.patientId) + " · " + wardName(a.ward) + " · " + formatCountdown(a.requestedAt, now), route: "/patients/" + a.patientId })) },
    { label: "In a theatre today", items: interventionsToday(data.interventions, now).map((i) => ({ value: i.id, label: i.name + " · " + patientName(data.patients, i.patientId), route: "/interventions/" + i.id })) },
    { label: "Lines billed off contract", items: offContractLines(data).map((f, index) => ({ value: f.invoice.id + index, label: f.invoice.reference + " · " + f.line.label + " · " + (f.kind === "no_price" ? "not in the contract" : "off contract by " + formatPounds(Math.abs(f.difference))), route: "/invoices/" + f.invoice.id })) },
    { label: "Invoices past due", items: invoicesOverdue(data.invoices, data.payments, now).map((i) => ({ value: i.id, label: i.reference + " · " + formatPounds(invoiceBalance(i, data.payments)) + " · " + formatCountdown(i.dueAt, now), route: "/invoices/" + i.id })) },
    { label: "Invoices", items: data.invoices.map((i) => ({ value: i.id, label: i.reference + " · " + patientName(data.patients, i.patientId) + " · " + statusValue(INVOICE_STATUS, i.status).label, route: "/invoices/" + i.id })) },
    { label: "Patients", items: data.patients.map((p) => ({ value: p.id, label: p.name + " · " + p.number, route: "/patients/" + p.id })) },
    { label: "Interventions", items: data.interventions.map((i) => ({ value: i.id, label: i.name + " · " + statusValue(INTERVENTION_STATUS, i.status).label, route: "/interventions/" + i.id })) },
    { label: "Shifts short of establishment", items: understaffedShifts(data.rota, data.wardBeds).map((s) => ({ value: s.ward + s.day + s.shift, label: wardName(s.ward) + " · " + (s.day === 0 ? "today" : "in " + s.day + " days") + " · " + labelOf(SHIFT_TYPES, s.shift).split(",")[0].toLowerCase() + " · " + s.shortfall + " short", route: "/rota" })) },
    { label: "Doctors", items: doctorsOf(data.staff).map((s) => ({ value: s.id, label: s.name + " · " + s.jobTitle, route: "/doctors/" + s.id })) },
    { label: "Employees", items: data.staff.filter((s) => s.family !== "medical").map((s) => ({ value: s.id, label: s.name + " · " + s.jobTitle, route: "/employees/" + s.id })) },
  ];

  return (
    <HdShell
      path={path}
      onNavigate={setPath}
      dark={dark}
      onToggleTheme={() => setDark(!dark)}
      data={data}
      viewer={viewer}
      notifications={NOTIFICATIONS}
      unread={read ? 0 : NOTIFICATIONS.length}
      onRead={() => setRead(true)}
      palette={palette}
      toasts={toasts}
      onDismissToast={dismiss}
    >
      {screen()}
      <CommandPalette
        open={palette.open}
        onClose={() => palette.setOpen(false)}
        routes={HD_ROUTES}
        recordGroups={recordGroups}
        onNavigate={setPath}
        placeholder="Search patients, procedures, staff, invoices…"
      />
      <ConfirmDialog request={confirm} onCancel={() => setConfirm(null)} onConfirm={() => { confirm.run(); setConfirm(null); }} />
      <FormDialog request={form} onCancel={() => setForm(null)} onSubmit={(values) => { form.run(values); setForm(null); }} />
      {preview}
    </HdShell>
  );
}
window.__hdReal = App;
if (!window.HdApp) window.HdApp = App;
