/* ============================================================
   MUIY 2.0 — restored modals (donor + health + data flows)
   Authored in the new citrus-and-sky design language.
   Loads AFTER me.jsx, BEFORE shell.jsx. Exports modals to window.
   ============================================================ */

/* ---------- local sheet + dialog primitives ---------- */
function MSheet({ title, sub, children, onClose }) {
  return (
    <div className="sheet-backdrop" onClick={onClose}>
      <div className="sheet" onClick={(e) => e.stopPropagation()}>
        <div className="sheet-grip" />
        {title && <div className="sheet-title">{title}</div>}
        {sub && <div className="body" style={{ marginBottom: 8 }}>{sub}</div>}
        <div style={{ marginTop: title ? 10 : 0 }}>{children}</div>
      </div>
    </div>
  );
}
function MDialog({ children, onClose }) {
  return <div className="dialog-backdrop" onClick={onClose}><div className="dialog" onClick={(e) => e.stopPropagation()}>{children}</div></div>;
}
function fillTpl2(tpl, donorName, patientName) {
  return (tpl || '').replace(/\[Donor Name\]/g, donorName || 'friend').replace(/\[Patient Name\]/g, patientName || '');
}
function SLabel({ children, action }) {
  return (
    <div className="between" style={{ marginBottom: 8 }}>
      <span style={{ fontSize: 11.5, fontWeight: 900, letterSpacing: '.05em', textTransform: 'uppercase', color: 'var(--ink-3)' }}>{children}</span>
      {action}
    </div>
  );
}
function MWarn({ children, tone = 'soon' }) {
  const map = { soon: ['var(--yellow-wash)', 'var(--waiting)'], good: ['var(--green-wash)', 'var(--success)'] };
  const [bg, col] = map[tone] || map.soon;
  return <div style={{ background: bg, color: col, padding: '10px 12px', borderRadius: 12, fontSize: 13, fontWeight: 700, marginBottom: 12, lineHeight: 1.4 }}>{children}</div>;
}

/* ---------- form widgets ---------- */
function Segmented({ options, value, onChange }) {
  return <div className="seg">{options.map((o) => <button key={o.value} className={value === o.value ? 'on' : ''} onClick={() => onChange(o.value)}>{o.label}</button>)}</div>;
}
function Switch({ on, onChange, label }) {
  return <button className={'switch' + (on ? ' on' : '')} role="switch" aria-checked={!!on} aria-label={label} onClick={() => onChange(!on)}><span className="knob" /></button>;
}
function BloodGrid({ value, onChange }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 8 }}>
      {TC.BLOOD_GROUPS.map((g) => (
        <button key={g} className="btn" style={{ padding: '11px 0', background: value === g ? bloodColor(g) : 'var(--surface-2)', color: value === g ? '#fff' : 'var(--ink)', border: value === g ? 'none' : '1.5px solid var(--hairline-2)' }} onClick={() => onChange(g)}>{g}</button>
      ))}
    </div>
  );
}
function Chips({ options, value, onChange, multi }) {
  const on = (v) => multi ? value.includes(v) : value === v;
  const toggle = (v) => multi ? onChange(value.includes(v) ? value.filter((x) => x !== v) : [...value, v]) : onChange(v);
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
      {options.map((o) => { const val = o.value ?? o; const lbl = o.label ?? o; return <button key={val} className={'chip' + (on(val) ? ' on' : '')} onClick={() => toggle(val)}>{lbl}</button>; })}
    </div>
  );
}
function MStepper({ value, onChange, max = 12, accent }) {
  const btn = (delta, label) => <button className="stepper-btn" onClick={() => onChange(Math.max(0, Math.min(max, value + delta)))} aria-label={label}>{delta > 0 ? '+' : '–'}</button>;
  return (
    <div className="row" style={{ gap: 8, alignItems: 'center' }}>
      {btn(-1, 'decrease')}
      <span className="num" style={{ minWidth: 26, textAlign: 'center', fontWeight: 800, fontSize: 17, color: value > 0 ? (accent || 'var(--orange)') : 'var(--ink-3)' }}>{value}</span>
      {btn(1, 'increase')}
    </div>
  );
}

/* ============================================================
   DONOR FLOWS
   ============================================================ */

/* ---------- Pick donor to log ---------- */
function PickLogDonor({ store, close }) {
  const [q, setQ] = React.useState('');
  const list = store.donors.filter((d) => !d.archived && d.name.toLowerCase().includes(q.toLowerCase()));
  return (
    <MSheet title="Log donation for…" onClose={close}>
      <div className="card-flat row" style={{ gap: 9, padding: '11px 14px', marginBottom: 12 }}>
        <Icon name="search" size={18} color="var(--ink-3)" />
        <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search donors…" style={{ flex: 1, border: 'none', background: 'none', outline: 'none', fontFamily: 'inherit', fontSize: 15, fontWeight: 600, color: 'var(--ink)' }} />
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', maxHeight: 360, overflowY: 'auto', scrollbarWidth: 'none' }}>
        {list.map((d) => (
          <button key={d.id} className="prow" style={{ border: 'none', background: 'none', cursor: 'pointer', fontFamily: 'inherit', width: '100%', textAlign: 'left' }} onClick={() => store.openModal('logDonation', { donor: d })}>
            <Avatar name={d.name} size={42} photoUrl={d.photoUrl} count={TC.donationCount(d)} />
            <div style={{ flex: 1, minWidth: 0 }}><div className="dname" style={{ fontSize: 15 }}>{d.name}</div><div className="dmeta muted">{d.mobile}</div></div>
            <BloodBadge group={d.bloodGroup} />
          </button>
        ))}
        {list.length === 0 && <div className="body" style={{ padding: '18px 4px' }}>No donors match “{q}”.</div>}
      </div>
    </MSheet>
  );
}

/* ---------- Log donation (rest-window guardrail) ---------- */
function LogDonationSheet({ store, close, donor, edit }) {
  const [f, setF] = React.useState({ date: edit?.date || TC.daysAgoDate(0), method: edit?.method || 'normal', hb: edit?.hbValue || '' });
  const set = (k, v) => setF((s) => ({ ...s, [k]: v }));
  const [override, setOverride] = React.useState(false);
  const first = donor.name.split(' ')[0];

  // a donation already exists on this exact date → not allowed (edit it instead)
  const dupDate = React.useMemo(() => (donor.donations || []).some((d) =>
    (!edit || d.id !== edit.id) && d.date === f.date
  ), [f.date, donor, edit]);

  // most recent prior donation — is this new date still inside its rest window?
  const recovery = React.useMemo(() => {
    const prior = (donor.donations || [])
      .filter((d) => (!edit || d.id !== edit.id) && TC.parse(d.date) < TC.parse(f.date))
      .sort((a, b) => TC.parse(b.date) - TC.parse(a.date))[0];
    if (!prior) return null;
    const win = TC.ELIGIBILITY_WINDOWS[prior.method] || 90;
    const since = TC.daysBetween(TC.parse(prior.date), TC.parse(f.date));
    if (since < win) return { win, since, remaining: win - since, method: prior.method };
    return null;
  }, [f.date, donor, edit]);

  // eligible donation range is 12.0–18.0 g/dL Hb
  const MIN_DONOR_HB = 12.0;
  const MAX_DONOR_HB = 18.0;
  const outHb = f.hb !== '' && +f.hb > 0 && (+f.hb < MIN_DONOR_HB || +f.hb > MAX_DONOR_HB);

  // editing the date or Hb clears any pending override prompt
  React.useEffect(() => { setOverride(false); }, [f.date, f.hb]);
  const plural = (n) => (n === 1 ? 'day' : 'days');

  // force=true bypasses the guardrail prompt (user explicitly chose "Log anyway")
  const save = (force) => {
    if (dupDate) return;
    if ((recovery || outHb) && !force) { setOverride('warn'); return; }
    store.mutate((d) => {
      const x = d.donors.find((z) => z.id === donor.id);
      if (edit) { const dn = x.donations.find((z) => z.id === edit.id); dn.date = f.date; dn.method = f.method; dn.hbValue = f.hb ? +f.hb : null; }
      else x.donations.push({ id: TC.uid(), date: f.date, method: f.method, hbValue: f.hb ? +f.hb : null });
    });
    if (edit) { store.showToast('Donation updated', '🩸'); close(); }
    else store.openModal('thankYou', { donor });
  };

  const del = () => store.openModal('confirm', {
    title: 'Delete this donation?',
    message: `The ${edit.method === 'apheresis' ? 'apheresis' : 'normal'} donation on ${TC.fmtDate(edit.date)} will be permanently removed from ${first}’s history. This cannot be undone.`,
    confirmLabel: 'Delete',
    onConfirm: () => { store.mutate((d) => { const x = d.donors.find((z) => z.id === donor.id); x.donations = x.donations.filter((z) => z.id !== edit.id); }); store.showToast('Donation deleted', '🗑️'); },
  });

  return (
    <MSheet title={edit ? 'Edit donation' : `Log donation — ${donor.name.split(' ')[0]}`} onClose={close}>
      <div className="field"><label className="field-label">Date</label><input className="input" type="date" value={f.date} onChange={(e) => set('date', e.target.value)} /></div>
      <div className="field"><label className="field-label">Method</label><Segmented options={[{ value: 'normal', label: 'Normal' }, { value: 'apheresis', label: 'Apheresis' }]} value={f.method} onChange={(v) => set('method', v)} /></div>
      <div className="field"><label className="field-label">HB value (g/dL)</label><input className="input" type="number" step="0.1" min="12" max="18" value={f.hb} onChange={(e) => set('hb', e.target.value)} placeholder="e.g. 14.2" />{outHb ? <div className="body" style={{ fontSize: 12, marginTop: 5, color: 'var(--alert)' }}>Outside the 12.0–18.0 g/dL donation range — double-check.</div> : null}</div>
      {dupDate && <MWarn tone="soon">A donation is already logged for {first} on this date. Open that entry from the donation history to edit it instead of adding a duplicate.</MWarn>}
      {!dupDate && override === 'warn' && outHb && (
        <MWarn>{first}’s Hb of {(+f.hb).toFixed(1)} g/dL is outside the 12.0–18.0 g/dL donation range. They normally wouldn’t be eligible to give blood today. Log it anyway?</MWarn>
      )}
      {!dupDate && override === 'warn' && recovery && (
        <MWarn>{first} is still in their recovery period — their last {recovery.method === 'apheresis' ? 'apheresis' : 'normal'} donation was {recovery.since} {plural(recovery.since)} ago, and the {recovery.win}-day window ends in {recovery.remaining} more {plural(recovery.remaining)}. Donating again this soon is earlier than recommended. Log it anyway?</MWarn>
      )}
      <div className="row" style={{ gap: 10, marginTop: 4 }}>
        {edit && <button className="btn btn-ghost" style={{ flex: '0 0 auto', color: 'var(--waiting)' }} onClick={del} aria-label="Delete donation"><Icon name="trash" size={17} color="var(--waiting)" /></button>}
        <button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button>
        <button className="btn btn-primary" style={{ flex: 1.4, opacity: dupDate ? 0.5 : 1 }} disabled={dupDate} onClick={() => { if (dupDate) return; save(override === 'warn'); }}>{override === 'warn' ? 'Log anyway' : 'Save'}</button>
      </div>
    </MSheet>
  );
}

/* ---------- Thank-you dialog ---------- */
function ThankYouDialog({ store, close, donor }) {
  const [msg, setMsg] = React.useState(fillTpl2((store.patient.messageTemplates || {}).thankYou, donor.name.split(' ')[0], store.patient.name));
  const wa = () => { window.open(`https://wa.me/${donor.mobile.replace(/\D/g, '')}?text=${encodeURIComponent(msg)}`, '_blank'); close(); store.showToast('Donation logged · thank-you sent', '💚'); };
  const sms = () => { window.location.href = `sms:${donor.mobile}?&body=${encodeURIComponent(msg)}`; close(); store.showToast('Donation logged', '💚'); };
  return (
    <MDialog onClose={close}>
      <div className="row" style={{ gap: 10, alignItems: 'center', marginBottom: 12 }}>
        <div className="leaf" style={{ width: 42, height: 42, background: 'var(--green-wash)', color: 'var(--success)' }}><Icon name="heart" size={20} color="var(--success)" fill="var(--success)" /></div>
        <span className="h2">Say thank you to {donor.name.split(' ')[0]}?</span>
      </div>
      <textarea className="input textarea" rows={4} value={msg} onChange={(e) => setMsg(e.target.value)} />
      <div style={{ display: 'flex', flexDirection: 'column', gap: 9, marginTop: 14 }}>
        <button className="btn" style={{ background: '#25D366', color: '#fff' }} onClick={wa}><Icon name="whatsapp" size={18} color="#fff" /> Send via WhatsApp</button>
        <button className="btn btn-ghost" onClick={sms}><Icon name="sms" size={18} /> Send via SMS</button>
        <button className="btn" style={{ background: 'none', color: 'var(--ink-3)' }} onClick={() => { close(); store.showToast('Donation logged', '🩸'); }}>Skip</button>
      </div>
    </MDialog>
  );
}

/* ---------- Defer ---------- */
function DeferSheet({ store, close, donor }) {
  const [reason, setReason] = React.useState('Low HB');
  const [ret, setRet] = React.useState('');
  const save = () => { store.mutate((d) => { const x = d.donors.find((z) => z.id === donor.id); x.deferred = true; x.deferReason = reason; x.deferReturn = ret || null; }); store.showToast('Donor deferred', '🚩'); close(); };
  return (
    <MSheet title={`Defer — ${donor.name.split(' ')[0]}`} onClose={close}>
      <label className="field-label">Reason</label>
      <div style={{ marginBottom: 16 }}><Chips options={['Low HB', 'Low BP', 'High BP', 'On Medication', 'Recent Operation', 'Recent Illness', 'Under Weight', 'Traveling', 'Other']} value={reason} onChange={setReason} /></div>
      <div className="field"><label className="field-label">Expected return (optional)</label><input className="input" type="date" value={ret} onChange={(e) => setRet(e.target.value)} /></div>
      <div className="row" style={{ gap: 10 }}><button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button><button className="btn btn-primary" style={{ flex: 1.4 }} onClick={save}>Defer</button></div>
    </MSheet>
  );
}

/* ---------- Archive ---------- */
function ArchiveSheet({ store, close, donor }) {
  const [reason, setReason] = React.useState('Moved Away');
  const save = () => { store.mutate((d) => { const x = d.donors.find((z) => z.id === donor.id); x.archived = true; x.archiveReason = reason; x.archiveDate = TC.daysAgoDate(0); }); store.showToast('Donor archived', '🗃️'); close(); };
  return (
    <MSheet title={`Archive ${donor.name.split(' ')[0]}?`} onClose={close}>
      <label className="field-label">Reason</label>
      <div style={{ marginBottom: 14 }}><Chips options={['Passed Away', 'Medically Unable', 'Moved Away', 'No Longer Available', 'Other']} value={reason} onChange={setReason} /></div>
      <div className="body" style={{ marginBottom: 14 }}>Full donation history is preserved. You can restore this donor anytime from the Archived section.</div>
      <div className="row" style={{ gap: 10 }}><button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button><button className="btn" style={{ flex: 1.4, background: 'var(--waiting)', color: '#fff' }} onClick={save}>Archive</button></div>
    </MSheet>
  );
}

/* ---------- Log contact ---------- */
function LogContactSheet({ store, close, donor }) {
  const [date, setDate] = React.useState(TC.daysAgoDate(0));
  const [outcome, setOutcome] = React.useState('answered');
  const [note, setNote] = React.useState('');
  const save = () => { store.mutate((d) => { const x = d.donors.find((z) => z.id === donor.id); x.contactLog = x.contactLog || []; x.contactLog.push({ id: TC.uid(), date, outcome, note: note.trim() || null }); }); store.showToast('Contact logged', '📞'); close(); };
  return (
    <MSheet title={`Log contact — ${donor.name.split(' ')[0]}`} onClose={close}>
      <div className="field"><label className="field-label">Date</label><input className="input" type="date" value={date} onChange={(e) => setDate(e.target.value)} /></div>
      <label className="field-label">Outcome</label>
      <div style={{ marginBottom: 16 }}><Chips options={[{ value: 'answered', label: 'Answered' }, { value: 'no_answer', label: 'No Answer' }, { value: 'declined', label: 'Declined' }, { value: 'confirmed', label: 'Confirmed' }]} value={outcome} onChange={setOutcome} /></div>
      <div className="field"><label className="field-label">Your note (optional)</label><textarea className="input textarea" rows={2} value={note} onChange={(e) => setNote(e.target.value)} placeholder="e.g. Will confirm after his exams · prefers a call after 6pm" /></div>
      <div className="row" style={{ gap: 10 }}><button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button><button className="btn btn-primary" style={{ flex: 1.4 }} onClick={save}>Save</button></div>
    </MSheet>
  );
}

/* ---------- Donor full history ---------- */
function DonorHistorySheet({ store, close, donorId }) {
  const donor = store.donors.find((d) => d.id === donorId);
  if (!donor) return null;
  const dons = [...(donor.donations || [])].sort((a, b) => TC.parse(b.date) - TC.parse(a.date));
  return (
    <MSheet title={`${donor.name} — history`} onClose={close}>
      <SLabel>All donations · {dons.length}</SLabel>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 9, maxHeight: 420, overflowY: 'auto', scrollbarWidth: 'none' }}>
        {dons.map((d) => (
          <div key={d.id} className="card-flat between" style={{ padding: '12px 14px' }}>
            <div><div className="dname" style={{ fontSize: 14.5 }}>{TC.fmtDate(d.date)}</div><div className="dmeta muted">{d.method === 'apheresis' ? 'Apheresis' : 'Normal'}{d.hbValue ? ` · HB ${d.hbValue}` : ''}</div></div>
            <div className="row" style={{ gap: 7 }}>
              <button className="icon-btn" style={{ width: 34, height: 34, background: 'var(--surface-2)' }} onClick={() => store.openModal('logDonation', { donor, edit: d })} aria-label="Edit"><Icon name="edit" size={15} /></button>
              <button className="icon-btn" style={{ width: 34, height: 34, background: 'var(--surface-2)' }} onClick={() => store.openModal('confirm', { title: 'Delete this donation?', message: `The ${d.method === 'apheresis' ? 'apheresis' : 'normal'} donation on ${TC.fmtDate(d.date)} will be permanently removed. This cannot be undone.`, confirmLabel: 'Delete', onConfirm: () => { store.mutate((s) => { const x = s.donors.find((z) => z.id === donor.id); x.donations = x.donations.filter((z) => z.id !== d.id); }); store.showToast('Donation deleted', '🗑️'); } })} aria-label="Delete"><Icon name="trash" size={15} color="var(--waiting)" /></button>
            </div>
          </div>
        ))}
      </div>
    </MSheet>
  );
}

/* ============================================================
   HEALTH FLOWS
   ============================================================ */

/* ---------- Log transfusion ---------- */
function LogTransfusionSheet({ store, close, edit }) {
  const editing = !!edit;
  const initTypes = editing && edit.reactionTypes ? edit.reactionTypes.map((x) => x[0].toUpperCase() + x.slice(1)) : [];
  const [f, setF] = React.useState({ date: edit?.date || TC.daysAgoDate(0), donatedOn: edit?.donorDonatedDate || '', units: edit?.units ?? 2, vol: edit?.volumeMl ?? '', donorHb: edit?.donorHb ?? '', source: edit?.donorSource || 'direct', hb: editing ? (TC.transfusionHb(store.data, edit.id) ?? '') : '', reaction: edit?.reaction || false, types: initTypes, notes: edit?.notes || '' });
  const set = (k, v) => setF((s) => ({ ...s, [k]: v }));
  const weightKg = store.patient && store.patient.weightKg > 0 ? store.patient.weightKg : null;
  const volNum = f.vol !== '' ? +f.vol : null;
  const volValid = volNum != null && volNum > 0;
  const perKg = volValid && weightKg ? (volNum / weightKg).toFixed(1) : null;
  // ---- clinical guardrails ----
  const G = window.CLINICALGUARD;
  const volNote = G ? G.volumeMl(f.vol, weightKg) : null;
  const unitNote = G ? G.units(f.units) : null;
  const donorHbNote = G ? G.donorHb(f.donorHb) : null;
  const hbBeforeNote = G ? G.hb(f.hb) : null;
  const dupNote = G ? G.duplicateTransfusion(store.data.transfusions, f.date, edit?.id) : null;
  const blocked = G ? G.blocks([volNote, unitNote, donorHbNote, hbBeforeNote]) : false;
  const valid = +f.units > 0 && volValid;
  const save = () => {
    if (!valid || blocked) return;
    store.mutate((d) => {
      const id = editing ? edit.id : TC.uid();
      const rec = { id, date: f.date, donorDonatedDate: f.donatedOn || null, units: +f.units, volumeMl: volValid ? +f.vol : null, donorHb: f.donorHb !== '' && +f.donorHb > 0 ? +f.donorHb : null, donorSource: f.source, reaction: f.reaction, reactionTypes: f.types.map((x) => x.toLowerCase()), notes: f.notes };
      if (editing) { const i = d.transfusions.findIndex((x) => x.id === id); d.transfusions[i] = rec; }
      else d.transfusions.push(rec);
      // Upsert the linked pre-transfusion Hb point in the single hbLog store.
      d.hbLog = d.hbLog || [];
      const h = d.hbLog.find((x) => x.source === 'transfusion' && x.transfusionId === id);
      if (f.hb) {
        if (h) { h.value = +f.hb; h.date = f.date; h.preTransfusion = true; }
        else d.hbLog.push({ id: TC.uid(), date: f.date, value: +f.hb, source: 'transfusion', transfusionId: id, preTransfusion: true });
      } else if (h) {
        d.hbLog = d.hbLog.filter((x) => x !== h);
      }
    });
    store.showToast(editing ? 'Transfusion updated' : 'Transfusion logged', '🩸'); close();
  };
  return (
    <MSheet title={editing ? 'Edit transfusion' : 'Log transfusion'} onClose={close}>
      <div className="field"><label className="field-label">Date</label><input className="input" type="date" value={f.date} onChange={(e) => set('date', e.target.value)} /></div>
      <div className="field">
        <label className="field-label">Amount transfused (mL) <span style={{ color: 'var(--orange)' }}>*</span></label>
        <input className="input" type="number" inputMode="numeric" step="10" min="0" max="2500" value={f.vol} onChange={(e) => set('vol', e.target.value)} placeholder="e.g. 450" style={f.vol === '' ? { borderColor: 'var(--hairline-2)' } : undefined} />
        <div className="body" style={{ fontSize: 11.5, marginTop: 5, color: perKg ? 'var(--success)' : 'var(--ink-3)' }}>{perKg ? `≈ ${perKg} mL/kg · total packed-cell volume this session` : 'Total packed-cell volume given this session — sharpens your forecast'}</div>
        <FieldNote note={volNote} />
      </div>
      <FieldNote note={dupNote} />
      <div className="grid-2">
        <div className="field"><label className="field-label">Units received</label><input className="input" type="number" value={f.units} onChange={(e) => set('units', e.target.value)} /></div>
        <div className="field"><label className="field-label">HB before (g/dL)</label><input className="input" type="number" step="0.1" min="0" max="250" value={f.hb} onChange={(e) => set('hb', e.target.value)} placeholder="7.2" /></div>
      </div>
      <FieldNote note={unitNote} />
      <FieldNote note={hbBeforeNote} onApplySuggest={(v) => set('hb', v)} />
      <div className="field">
        <label className="field-label">Donor haemoglobin (g/dL)</label>
        <input className="input" type="number" step="0.1" min="0" max="250" value={f.donorHb} onChange={(e) => set('donorHb', e.target.value)} placeholder="e.g. 13.8" />
        <div className="body" style={{ fontSize: 11.5, marginTop: 5, color: 'var(--ink-3)' }}>The donor’s pre-donation Hb. A richer unit lifts your Hb higher and tends to last longer — this sharpens your next-transfusion window.</div>
        <FieldNote note={donorHbNote} onApplySuggest={(v) => set('donorHb', v)} />
      </div>
      <div className="field"><label className="field-label">Donor source</label><Segmented options={[{ value: 'direct', label: 'Direct Donor' }, { value: 'camp', label: 'Camp' }]} value={f.source} onChange={(v) => set('source', v)} /></div>
      <div className="field"><label className="field-label">Donor's donation date (optional)</label><input className="input" type="date" value={f.donatedOn} onChange={(e) => set('donatedOn', e.target.value)} /></div>
      <div className="field between" style={{ alignItems: 'center' }}><label className="field-label" style={{ margin: 0 }}>Any reaction?</label><Switch on={f.reaction} onChange={(v) => set('reaction', v)} /></div>
      {f.reaction && <div className="field"><label className="field-label">Reaction type</label><Chips multi options={['Rash', 'Fever', 'Chills', 'Itching', 'Shortness of Breath', 'Other']} value={f.types} onChange={(v) => set('types', v)} /></div>}
      <div className="field"><label className="field-label">Notes (optional)</label><textarea className="input textarea" rows={2} value={f.notes} onChange={(e) => set('notes', e.target.value)} /></div>
      <div className="row" style={{ gap: 10 }}>
        {editing && <button className="btn btn-ghost" style={{ flex: '0 0 auto', color: 'var(--waiting)' }} onClick={() => store.openModal('confirm', { title: 'Delete transfusion?', message: 'This transfusion record will be permanently removed. This cannot be undone.', confirmLabel: 'Delete', onConfirm: () => { store.mutate((d) => { d.transfusions = d.transfusions.filter((x) => x.id !== edit.id); d.hbLog = (d.hbLog || []).filter((x) => !(x.source === 'transfusion' && x.transfusionId === edit.id)); }); store.showToast('Transfusion removed', '🗑️'); } })}><Icon name="trash" size={17} color="var(--waiting)" /></button>}
        <button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button>
        <button className="btn btn-primary" style={{ flex: 1.4, opacity: valid && !blocked ? 1 : 0.5, pointerEvents: valid && !blocked ? 'auto' : 'none' }} onClick={save}>Save</button>
      </div>
      <MedicalDisclaimer style={{ marginTop: 14 }} />
    </MSheet>
  );
}

/* ---------- Upload lab (mandatory verify) ---------- */
function UploadLabSheet({ store, close }) {
  const [stage, setStage] = React.useState('upload');
  const [date, setDate] = React.useState(TC.daysAgoDate(0));
  const [v, setV] = React.useState({ hb: '', ferritin: '', wbc: '', rbc: '', platelets: '' });
  const set = (k, val) => setV((s) => ({ ...s, [k]: val }));
  const [notes, setNotes] = React.useState('');
  const G = window.CLINICALGUARD;
  const hbN = G ? G.hb(v.hb) : null;
  const ferN = G ? G.ferritin(v.ferritin) : null;
  const labBlocked = G ? G.blocks([hbN, ferN]) : false;
  const fakeExtract = () => { setV({ hb: '9.4', ferritin: '1265', wbc: '6.1', rbc: '3.1', platelets: '205' }); setStage('verify'); };
  const save = () => {
    if (labBlocked) return;
    store.mutate((d) => {
      const lid = TC.uid();
      d.labReports.push({ id: lid, date, fileType: 'pdf', fileRef: null, extractedValues: { hb: +v.hb || null, ferritin: +v.ferritin || null, wbc: +v.wbc || null, rbc: +v.rbc || null, platelets: +v.platelets || null }, verifiedByUser: true, notes });
      if (v.hb) d.hbLog.push({ id: TC.uid(), date, value: +v.hb, source: 'lab_report', labReportId: lid });
      if (v.ferritin) d.ferritinLog.push({ id: TC.uid(), date, value: +v.ferritin, source: 'lab_report' });
    });
    store.showToast('Lab report saved', '📄'); close();
  };
  return (
    <MSheet title="Upload lab report" onClose={close}>
      {stage === 'upload' ? (
        <div>
          <div className="field"><label className="field-label">Report date</label><input className="input" type="date" value={date} onChange={(e) => setDate(e.target.value)} /></div>
          <label className="field-label">File</label>
          <button className="upload-drop" onClick={fakeExtract}>
            <Icon name="upload" size={26} color="var(--orange)" />
            <span style={{ fontWeight: 800, fontSize: 14, color: 'var(--ink)' }}>Choose PDF or photo</span>
            <span className="body" style={{ fontSize: 12 }}>We’ll try to read the values automatically</span>
          </button>
          <div className="body" style={{ fontSize: 12.5, marginTop: 14 }}>Or <button className="link" style={{ padding: 0, fontSize: 12.5 }} onClick={() => setStage('verify')}>enter values manually →</button></div>
        </div>
      ) : (
        <div>
          <MWarn>Extracted automatically — please verify every value before saving.</MWarn>
          <div className="grid-2">
            <div className="field"><label className="field-label">HB (g/dL)</label><input className="input" value={v.hb} onChange={(e) => set('hb', e.target.value)} /></div>
            <div className="field"><label className="field-label">Ferritin (ng/mL)</label><input className="input" value={v.ferritin} onChange={(e) => set('ferritin', e.target.value)} /></div>
            <div className="field"><label className="field-label">WBC</label><input className="input" value={v.wbc} onChange={(e) => set('wbc', e.target.value)} /></div>
            <div className="field"><label className="field-label">RBC</label><input className="input" value={v.rbc} onChange={(e) => set('rbc', e.target.value)} /></div>
          </div>
          <FieldNote note={hbN} onApplySuggest={(x) => set('hb', x)} />
          <FieldNote note={ferN} />
          <div className="field"><label className="field-label">Platelets</label><input className="input" value={v.platelets} onChange={(e) => set('platelets', e.target.value)} /></div>
          <div className="field"><label className="field-label">Notes (optional)</label><textarea className="input textarea" rows={2} value={notes} onChange={(e) => setNotes(e.target.value)} /></div>
          <MedicalDisclaimer variant="card" style={{ margin: '2px 0 14px' }} />
          <div className="row" style={{ gap: 10 }}><button className="btn btn-ghost" style={{ flex: 1 }} onClick={() => setStage('upload')}>Back</button><button className="btn btn-primary" style={{ flex: 1.4, opacity: labBlocked ? 0.5 : 1, pointerEvents: labBlocked ? 'none' : 'auto' }} onClick={save}>Verify &amp; save</button></div>
        </div>
      )}
    </MSheet>
  );
}

/* ---------- Add / edit medication (structured dosing) ---------- */
function AddMedSheet({ store, close, med }) {
  const editing = !!med;
  const [brand, setBrand] = React.useState(med?.brand || 'Jadenu');
  const cat = TC.findChelator(brand) || TC.CHELATORS[0];
  const [counts, setCounts] = React.useState(() => {
    const init = {}; cat.strengths.forEach((s) => { init[s.mg] = 0; });
    if (med?.strengths) med.strengths.forEach((s) => { init[s.mg] = s.count; });
    else if (!editing) init[cat.strengths[cat.strengths.length - 1].mg] = 1;
    return init;
  });
  const [freq, setFreq] = React.useState(med?.frequency || (cat.infusion ? 'daily' : 'once_daily'));
  const [times, setTimes] = React.useState(med?.times || []);
  const [duration, setDuration] = React.useState(med?.duration || '');
  const [refill, setRefill] = React.useState(med?.nextRefill || TC.inDaysDate(30));
  const [weight, setWeight] = React.useState(med?.weightKg || store.patient.weightKg || '');
  const isInfusion = !!cat.infusion;
  const freqOptions = isInfusion ? TC.INFUSION_FREQ : TC.FREQ_OPTIONS;

  const pickBrand = (b) => {
    setBrand(b); const c = TC.findChelator(b);
    const init = {}; c.strengths.forEach((s) => { init[s.mg] = 0; }); init[c.strengths[c.strengths.length - 1].mg] = 1;
    setCounts(init); setFreq(c.infusion ? 'daily' : 'once_daily'); setTimes([]); setDuration('');
  };
  const setCount = (mg, v) => setCounts((c) => ({ ...c, [mg]: v }));
  const total = Object.values(counts).reduce((a, b) => a + b, 0);
  const toggleTime = (t) => setTimes((ts) => ts.includes(t) ? ts.filter((x) => x !== t) : [...ts, t]);

  const previewMed = { brand, chelator: cat.chelator, frequency: freq, strengths: cat.strengths.filter((s) => counts[s.mg] > 0).map((s) => ({ mg: s.mg, count: counts[s.mg], unit: s.unit || 'tablet' })) };
  const daily = TC.medDailyMg(previewMed);
  const wKg = parseFloat(weight) || 0;
  const target = TC.targetDose(brand, wKg);
  let doseFlag = null;
  if (target && daily) {
    if (daily < target.min) doseFlag = { c: 'var(--waiting)', t: `Below typical range (${target.min}–${target.max} mg/day)` };
    else if (daily > target.max) doseFlag = { c: 'var(--waiting)', t: `Above typical range (${target.min}–${target.max} mg/day)` };
    else doseFlag = { c: 'var(--green)', t: `Within typical range (${target.min}–${target.max} mg/day)` };
  }

  const save = () => {
    if (total === 0) return;
    const strengths = cat.strengths.filter((s) => counts[s.mg] > 0).map((s) => ({ mg: s.mg, count: counts[s.mg], unit: s.unit || 'tablet' }));
    store.mutate((d) => {
      if (wKg > 0) d.patient.weightKg = wKg;
      const rec = { id: editing ? med.id : TC.uid(), name: cat.chelator, brand, form: cat.form, strengths, frequency: freq, times: isInfusion ? [] : times, duration: isInfusion ? duration : null, weightKg: wKg || null, dose: TC.medDoseLabel({ strengths }), nextRefill: refill };
      if (editing) { const i = d.patient.medications.findIndex((x) => x.id === med.id); d.patient.medications[i] = rec; }
      else d.patient.medications.push(rec);
    });
    store.showToast(editing ? 'Medication updated' : 'Medication added', '💊'); close();
  };

  return (
    <MSheet title={editing ? 'Edit medication' : 'Add medication'} onClose={close}>
      <label className="field-label">Chelator</label>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 9, marginBottom: 18 }}>
        {TC.CHELATORS.map((c) => {
          const on = brand === c.brand;
          return (
            <button key={c.brand} onClick={() => pickBrand(c.brand)} className="qa-item" style={{ borderColor: on ? 'var(--orange)' : 'transparent', background: on ? 'var(--orange-wash)' : 'var(--surface-2)' }}>
              <div className="qa-ic" style={{ background: 'var(--orange-wash)', color: 'var(--orange)' }}><Icon name="pill" size={20} color="var(--orange)" /></div>
              <div style={{ flex: 1, textAlign: 'left' }}><div style={{ fontWeight: 800, fontSize: 15 }}>{c.brand}</div><div className="body" style={{ fontSize: 12 }}>{c.chelator} · {c.form}</div></div>
              <div style={{ width: 20, height: 20, borderRadius: '50%', border: on ? 'none' : '1.5px solid var(--hairline-2)', background: on ? 'var(--orange)' : 'transparent', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{on && <Icon name="check" size={12} color="#fff" sw={3} />}</div>
            </button>
          );
        })}
      </div>

      <div className="field"><label className="field-label">Body weight</label>
        <div className="row" style={{ gap: 8 }}>
          <input className="input" type="number" inputMode="decimal" value={weight} onChange={(e) => setWeight(e.target.value)} placeholder="e.g. 58" />
          <span className="input" style={{ width: 'auto', flex: 'none', color: 'var(--ink-3)', display: 'flex', alignItems: 'center' }}>kg</span>
        </div>
      </div>
      {target ? (
        <div className="card-flat" style={{ padding: '14px 15px', marginBottom: 18, borderLeft: '3px solid var(--orange)' }}>
          <div className="between" style={{ alignItems: 'center' }}>
            <span className="row" style={{ gap: 7, alignItems: 'center' }}><Icon name="sparkle" size={16} color="var(--orange)" /><span style={{ fontWeight: 800, fontSize: 13 }}>Recommended dose</span></span>
            <span className="body" style={{ fontSize: 11 }}>{target.perKgRange}</span>
          </div>
          <div className="row" style={{ alignItems: 'baseline', gap: 6, marginTop: 8 }}>
            <span className="num" style={{ fontWeight: 800, fontSize: 26, color: 'var(--orange)' }}>{target.typical.toLocaleString()}</span>
            <span style={{ fontWeight: 700, fontSize: 13, color: 'var(--ink-2)' }}>mg/day</span>
            <span className="body" style={{ fontSize: 12, marginLeft: 'auto' }}>range {target.min.toLocaleString()}–{target.max.toLocaleString()}</span>
          </div>
          {target.infusion && <div className="body" style={{ fontSize: 11.5, marginTop: 6 }}>Infusion — usually given 5–7 days/week.</div>}
          {doseFlag && <div className="row" style={{ gap: 8, alignItems: 'center', marginTop: 10, padding: '8px 10px', borderRadius: 10, background: 'var(--surface-2)' }}><span style={{ width: 8, height: 8, borderRadius: '50%', background: doseFlag.c, flexShrink: 0 }} /><span style={{ fontSize: 12, fontWeight: 700, color: doseFlag.c }}>Your regimen: {daily.toLocaleString()} mg/day — {doseFlag.t}</span></div>}
          <div className="body" style={{ fontSize: 10.5, marginTop: 10, color: 'var(--ink-3)' }}>Estimate only — always follow your haematologist’s prescription.</div>
        </div>
      ) : (
        <div className="body" style={{ fontSize: 12, marginBottom: 18, marginTop: -6 }}>Enter your weight to auto-calculate the typical dose for {brand}.</div>
      )}

      <label className="field-label">How many of each strength — per dose</label>
      <div className="card-flat" style={{ padding: '4px 14px', marginBottom: 18 }}>
        {cat.strengths.map((s, i) => (
          <div key={s.mg} className="between" style={{ alignItems: 'center', padding: '12px 0', borderTop: i > 0 ? '1px solid var(--hairline)' : 'none' }}>
            <div><div style={{ fontWeight: 800, fontSize: 15 }}>{TC.strengthLabel(s)}</div><div className="body" style={{ fontSize: 11.5 }}>{(s.unit || 'tablet') === 'mL' ? 'oral solution (mL)' : (s.unit || 'tablet') + (counts[s.mg] === 1 ? '' : 's')} per dose</div></div>
            <MStepper value={counts[s.mg] || 0} onChange={(v) => setCount(s.mg, v)} />
          </div>
        ))}
      </div>

      <div className="field"><label className="field-label">How often</label><Chips options={freqOptions.map((o) => ({ value: o.value, label: o.label }))} value={freq} onChange={setFreq} /></div>

      {isInfusion ? (
        <div className="field"><label className="field-label">How long (infusion duration)</label><Chips options={TC.INFUSION_DURATIONS} value={duration} onChange={(v) => setDuration(duration === v ? '' : v)} /></div>
      ) : (
        <div className="field"><label className="field-label">When (optional)</label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>{['Morning', 'Afternoon', 'Evening', 'Night'].map((t) => <button key={t} className={'chip' + (times.includes(t) ? ' on' : '')} onClick={() => toggleTime(t)}>{t}</button>)}</div>
        </div>
      )}

      <div className="field"><label className="field-label">Next refill date</label><input className="input" type="date" value={refill} onChange={(e) => setRefill(e.target.value)} /></div>

      {total > 0 && (
        <div style={{ background: 'var(--orange-wash)', borderRadius: 14, padding: '12px 14px', marginBottom: 16 }}>
          <div style={{ fontSize: 11, fontWeight: 800, letterSpacing: '.06em', textTransform: 'uppercase', color: 'var(--orange)' }}>You’ll take</div>
          <div style={{ fontWeight: 800, fontSize: 14, marginTop: 4, color: 'var(--ink)' }}>{TC.medDoseLabel(previewMed)}</div>
          <div className="body" style={{ fontSize: 12.5, marginTop: 2 }}>{TC.medFreqLabel(freq)}{isInfusion ? (duration ? ' · ' + duration : '') : (times.length ? ' · ' + times.join(', ') : '')}{daily ? ` · ≈ ${daily.toLocaleString()} mg/day` : ''}</div>
        </div>
      )}

      <div className="row" style={{ gap: 10 }}>
        {editing && <button className="btn btn-ghost" style={{ flex: '0 0 auto', color: 'var(--waiting)' }} onClick={() => store.openModal('confirm', { title: 'Delete medication?', message: `“${cat.chelator}” will be removed from your medications.`, confirmLabel: 'Delete', onConfirm: () => { store.mutate((d) => { d.patient.medications = d.patient.medications.filter((x) => x.id !== med.id); }); store.showToast('Medication removed', '🗑️'); } })}><Icon name="trash" size={17} color="var(--waiting)" /></button>}
        <button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button>
        <button className="btn btn-primary" style={{ flex: 1.4, opacity: total === 0 ? 0.5 : 1 }} onClick={save}>{editing ? 'Save' : 'Add'}</button>
      </div>
    </MSheet>
  );
}

/* ---------- Bulk import (working CSV parser) ---------- */
const CSV_TEMPLATE =
  'Name,Mobile,BloodGroup,LastDonationDate,Method,HB,Notes\r\n' +
  'Ahmed Waheed,+9609123456,O-,2026-02-15,normal,14.5,Universal donor\r\n' +
  'Hawwa Shanna,+9607654321,O+,2026-04-10,apheresis,12.8,Prefers WhatsApp message\r\n';

function ImportSheet({ store, close }) {
  const [csv, setCsv] = React.useState('');
  const [summary, setSummary] = React.useState(null);
  const fileRef = React.useRef(null);

  const downloadTemplate = () => {
    const uri = encodeURI('data:text/csv;charset=utf-8,' + CSV_TEMPLATE);
    const link = document.createElement('a'); link.setAttribute('href', uri); link.setAttribute('download', 'mui_donor_import_template.csv');
    document.body.appendChild(link); link.click(); document.body.removeChild(link); store.showToast('Template downloaded', '📥');
  };
  const onFile = (e) => { const file = e.target.files && e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = () => setCsv(String(reader.result || '')); reader.readAsText(file); };

  const parseAndImport = () => {
    const text = csv.trim(); if (!text) return;
    const lines = text.split(/\r?\n/);
    const looksHeader = /name/i.test(lines[0]) && /mobile|phone/i.test(lines[0]);
    const start = looksHeader ? 1 : 0;
    const norm = (m) => (m || '').replace(/\D/g, '');
    const seen = new Set(store.donors.map((d) => norm(d.mobile)));
    const toAdd = []; let ok = 0, dup = 0, bad = 0;
    for (let i = start; i < lines.length; i++) {
      const line = lines[i].trim(); if (!line) continue;
      const cols = line.split(',');
      if (cols.length < 3 || !cols[0].trim() || !cols[1].trim()) { bad++; continue; }
      const name = cols[0].trim();
      let mobile = cols[1].trim(); if (!mobile.startsWith('+')) mobile = '+960' + mobile.replace(/\D/g, '');
      let bg = (cols[2] || '').trim().toUpperCase();
      if (!TC.BLOOD_GROUPS.includes(bg)) { bad++; continue; }
      const lastDate = (cols[3] || '').trim() || TC.daysAgoDate(0);
      const method = (cols[4] || '').trim().toLowerCase() === 'apheresis' ? 'apheresis' : 'normal';
      const hb = cols[5] && cols[5].trim() ? parseFloat(cols[5].trim()) : null;
      const notes = (cols.slice(6).join(',') || '').trim();
      const key = norm(mobile);
      if (seen.has(key)) { dup++; continue; }
      seen.add(key);
      toAdd.push({ id: TC.uid(), name, mobile, countryCode: '+960', bloodGroup: bg, status: 'active', awayStatus: false, addedOn: TC.daysAgoDate(0), notes, donations: [{ id: TC.uid(), date: lastDate, method, hbValue: hb }], contactLog: [], archived: false, archiveReason: null, archiveDate: null, deferred: false, deferReason: null, deferReturn: null });
      ok++;
    }
    if (toAdd.length) store.mutate((d) => { d.donors = [...toAdd, ...d.donors]; });
    setSummary({ ok, dup, bad, tone: ok > 0 ? 'good' : 'warn' });
    if (ok > 0) { store.showToast(`Imported ${ok} donor${ok === 1 ? '' : 's'}`, '🌱'); setCsv(''); }
  };

  return (
    <MSheet title="Bulk import donors" onClose={close}>
      <div className="between" style={{ alignItems: 'center', marginBottom: 12 }}>
        <div className="body" style={{ fontSize: 13, maxWidth: 220 }}>Paste rows below, or load a CSV file. We skip duplicates by mobile number.</div>
        <button className="link" style={{ fontSize: 12, whiteSpace: 'nowrap' }} onClick={downloadTemplate}><Icon name="download" size={15} color="var(--orange)" /> Template</button>
      </div>
      <textarea className="input textarea" rows={5} value={csv} onChange={(e) => setCsv(e.target.value)} style={{ fontFamily: 'ui-monospace, Menlo, monospace', fontSize: 12.5, lineHeight: 1.5 }} placeholder={'Name,Mobile,BloodGroup,LastDonationDate,Method,HB,Notes\nAhmed Waheed,+9609123456,O-,2026-02-15,normal,14.5,Universal donor'} />
      <input ref={fileRef} type="file" accept=".csv,text/csv" onChange={onFile} style={{ display: 'none' }} />
      <div className="row" style={{ gap: 8, marginTop: 12 }}>
        <button className="btn btn-ghost" style={{ flex: 1 }} onClick={() => fileRef.current && fileRef.current.click()}><Icon name="upload" size={17} /> Load file</button>
        <button className="btn btn-primary" style={{ flex: 1.3 }} onClick={parseAndImport}>Import donors</button>
      </div>
      {summary && <div style={{ marginTop: 14 }}><MWarn tone={summary.tone === 'good' ? 'good' : 'soon'}>Imported <b>{summary.ok}</b> donor{summary.ok === 1 ? '' : 's'}{summary.dup ? ` · skipped ${summary.dup} duplicate${summary.dup === 1 ? '' : 's'}` : ''}{summary.bad ? ` · ${summary.bad} row${summary.bad === 1 ? '' : 's'} had errors` : ''}.</MWarn></div>}
      <div className="row" style={{ marginTop: 8 }}><button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Done</button></div>
    </MSheet>
  );
}

/* ============================================================
   CONFIRM DIALOG (used before any destructive delete)
   ============================================================ */
function ConfirmDialog({ store, close, title, message, confirmLabel = 'Delete', danger = true, onConfirm }) {
  return (
    <MDialog onClose={close}>
      <div className="row" style={{ gap: 11, alignItems: 'center', marginBottom: 12 }}>
        <div className="leaf" style={{ width: 42, height: 42, background: danger ? 'var(--waiting-wash)' : 'var(--orange-wash)', color: danger ? 'var(--waiting)' : 'var(--orange)' }}><Icon name={danger ? 'trash' : 'warn'} size={20} color={danger ? 'var(--waiting)' : 'var(--orange)'} /></div>
        <span className="h2">{title}</span>
      </div>
      <div className="body" style={{ marginBottom: 18, lineHeight: 1.5 }}>{message}</div>
      <div className="row" style={{ gap: 10 }}>
        <button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button>
        <button className="btn" style={{ flex: 1.3, background: danger ? 'var(--waiting)' : 'var(--orange)', color: '#fff' }} onClick={() => { onConfirm && onConfirm(); close(); }}>{confirmLabel}</button>
      </div>
    </MDialog>
  );
}

/* ============================================================
   LOG HB LEVEL — date · value · auto day-since-transfusion
   ============================================================ */
function LogHbSheet({ store, close, edit }) {
  const editing = !!edit;
  const [f, setF] = React.useState({ date: edit?.date || TC.daysAgoDate(0), value: edit?.value ?? '', pre: editing ? (edit.source === 'transfusion' || edit.preTransfusion === true) : true });
  const set = (k, v) => setF((s) => ({ ...s, [k]: v }));
  const day = React.useMemo(() => TC.daysSinceTransfusion(store.data.transfusions, f.date), [f.date, store.data.transfusions]);
  const lastTrans = React.useMemo(() => {
    const prior = (store.data.transfusions || []).filter((t) => TC.parse(t.date) <= TC.parse(f.date)).sort((a, b) => TC.parse(b.date) - TC.parse(a.date));
    return prior[0] || null;
  }, [f.date, store.data.transfusions]);
  const fromTransfusion = editing && edit.source === 'transfusion';
  const G = window.CLINICALGUARD;
  const vNote = G ? G.hb(f.value) : null;
  const dNote = G ? G.duplicateReading(store.data.hbLog, f.date, edit?.id) : null;
  const blocked = G ? G.blocks([vNote]) : false;

  const save = () => {
    if (!f.value || blocked) return;
    store.mutate((d) => {
      if (editing) { const x = d.hbLog.find((z) => z.id === edit.id); x.date = f.date; x.value = +f.value; if (x.source !== 'transfusion') x.preTransfusion = f.pre; }
      else d.hbLog.push({ id: TC.uid(), date: f.date, value: +f.value, source: 'manual', preTransfusion: f.pre });
    });
    store.showToast(editing ? 'HB updated' : 'HB logged', '🩸'); close();
  };
  const del = () => store.openModal('confirm', { title: 'Delete HB reading?', message: 'This HB reading will be permanently removed. This cannot be undone.', confirmLabel: 'Delete', onConfirm: () => { store.mutate((d) => { d.hbLog = d.hbLog.filter((x) => x.id !== edit.id); }); store.showToast('HB reading removed', '🗑️'); } });

  return (
    <MSheet title={editing ? 'Edit HB reading' : 'Log HB level'} onClose={close}>
      <div className="field"><label className="field-label">Date</label><input className="input" type="date" value={f.date} onChange={(e) => set('date', e.target.value)} /></div>
      <div className="field"><label className="field-label">HB level (g/dL)</label><input className="input" type="number" step="0.1" min="0" max="250" value={f.value} onChange={(e) => set('value', e.target.value)} placeholder="e.g. 9.4" /></div>
      <FieldNote note={vNote} onApplySuggest={(v) => set('value', v)} />
      <FieldNote note={dNote} />
      {!fromTransfusion && (
        <div className="card-flat" style={{ padding: '12px 14px', marginBottom: 16 }}>
          <div className="between" style={{ alignItems: 'center' }}>
            <span style={{ flex: 1, minWidth: 0, paddingRight: 12 }}>
              <span style={{ display: 'block', fontWeight: 800, fontSize: 13, color: 'var(--ink)' }}>Pre-transfusion reading</span>
              <span className="body" style={{ fontSize: 11.5, display: 'block', marginTop: 3, lineHeight: 1.4 }}>Counts toward your Pre-transfusion Hb status, trend &amp; milestones. Turn off for a mid-cycle lab value.</span>
            </span>
            <Switch on={f.pre} onChange={(v) => set('pre', v)} />
          </div>
        </div>
      )}
      <div className="card-flat" style={{ padding: '12px 14px', marginBottom: 16, borderLeft: '3px solid var(--sky-deep)' }}>
        <div className="between" style={{ alignItems: 'center' }}>
          <span className="row" style={{ gap: 7 }}><Icon name="drop" size={15} color="var(--sky-deep)" /><span style={{ fontWeight: 800, fontSize: 12.5 }}>Days since last transfusion</span></span>
          <span className="num" style={{ fontWeight: 800, fontSize: 18, color: 'var(--sky-deep)' }}>{day != null ? `Day ${day}` : '—'}</span>
        </div>
        <div className="body" style={{ fontSize: 11.5, marginTop: 5 }}>{lastTrans ? `Auto-calculated from your ${TC.fmtDate(lastTrans.date)} transfusion.` : 'No earlier transfusion on record to count from.'}</div>
      </div>
      <div className="row" style={{ gap: 10 }}>
        {editing && <button className="btn btn-ghost" style={{ flex: '0 0 auto', color: 'var(--waiting)' }} onClick={del}><Icon name="trash" size={17} color="var(--waiting)" /></button>}
        <button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button>
        <button className="btn btn-primary" style={{ flex: 1.4, opacity: f.value && !blocked ? 1 : 0.5, pointerEvents: f.value && !blocked ? 'auto' : 'none' }} onClick={save}>Save</button>
      </div>
    </MSheet>
  );
}

/* ============================================================
   LOG FERRITIN LEVEL — date · value · lab (opt) · notes (opt)
   ============================================================ */
function LogFerritinSheet({ store, close, edit }) {
  const editing = !!edit;
  const [f, setF] = React.useState({ date: edit?.date || TC.daysAgoDate(0), value: edit?.value ?? '', lab: edit?.lab || '', notes: edit?.notes || '' });
  const set = (k, v) => setF((s) => ({ ...s, [k]: v }));
  const G = window.CLINICALGUARD;
  const vNote = G ? G.ferritin(f.value) : null;
  const dNote = G ? G.duplicateReading(store.data.ferritinLog, f.date, edit?.id) : null;
  const blocked = G ? G.blocks([vNote]) : false;

  const save = () => {
    if (!f.value || blocked) return;
    store.mutate((d) => {
      if (editing) { const x = d.ferritinLog.find((z) => z.id === edit.id); x.date = f.date; x.value = +f.value; x.lab = f.lab || null; x.notes = f.notes || null; }
      else d.ferritinLog.push({ id: TC.uid(), date: f.date, value: +f.value, source: 'manual', lab: f.lab || null, notes: f.notes || null });
    });
    store.showToast(editing ? 'Ferritin updated' : 'Ferritin logged', '🧪'); close();
  };
  const del = () => store.openModal('confirm', { title: 'Delete ferritin reading?', message: 'This ferritin reading will be permanently removed. This cannot be undone.', confirmLabel: 'Delete', onConfirm: () => { store.mutate((d) => { d.ferritinLog = d.ferritinLog.filter((x) => x.id !== edit.id); }); store.showToast('Ferritin reading removed', '🗑️'); } });

  return (
    <MSheet title={editing ? 'Edit ferritin reading' : 'Log ferritin level'} onClose={close}>
      <div className="field"><label className="field-label">Date</label><input className="input" type="date" value={f.date} onChange={(e) => set('date', e.target.value)} /></div>
      <div className="field"><label className="field-label">Ferritin level (ng/mL)</label><input className="input" type="number" value={f.value} onChange={(e) => set('value', e.target.value)} placeholder="e.g. 1265" /></div>
      <FieldNote note={vNote} />
      <FieldNote note={dNote} />
      <div className="field"><label className="field-label">Laboratory (optional)</label><input className="input" value={f.lab} onChange={(e) => set('lab', e.target.value)} placeholder="e.g. Maldivian Blood Servicestal Lab" /></div>
      <div className="field"><label className="field-label">Notes (optional)</label><textarea className="input textarea" rows={2} value={f.notes} onChange={(e) => set('notes', e.target.value)} placeholder="Infection, illness, transfusion changes…" /></div>
      <div className="body" style={{ fontSize: 11.5, marginTop: -6, marginBottom: 14, color: 'var(--ink-3)' }}>Different labs can vary — noting the lab helps you compare like with like.</div>
      <div className="row" style={{ gap: 10 }}>
        {editing && <button className="btn btn-ghost" style={{ flex: '0 0 auto', color: 'var(--waiting)' }} onClick={del}><Icon name="trash" size={17} color="var(--waiting)" /></button>}
        <button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button>
        <button className="btn btn-primary" style={{ flex: 1.4, opacity: f.value && !blocked ? 1 : 0.5, pointerEvents: f.value && !blocked ? 'auto' : 'none' }} onClick={save}>Save</button>
      </div>
    </MSheet>
  );
}

/* ============================================================
   FULL HISTORY POPUPS (hb / ferritin levels, transfusions)
   ============================================================ */
function LevelHistorySheet({ store, close, kind }) {
  const isHb = kind === 'hb';
  const arr = [...(isHb ? store.data.hbLog : store.data.ferritinLog) || []].sort((a, b) => TC.parse(b.date) - TC.parse(a.date));
  return (
    <MSheet title={isHb ? 'All HB readings' : 'All ferritin readings'} onClose={close}>
      <SLabel action={<button className="link" style={{ fontSize: 12.5 }} onClick={() => store.openModal(isHb ? 'logHb' : 'logFerritin', {})}>+ Log</button>}>{arr.length} reading{arr.length === 1 ? '' : 's'}</SLabel>
      <div style={{ display: 'flex', flexDirection: 'column', maxHeight: 440, overflowY: 'auto', scrollbarWidth: 'none' }}>
        {arr.map((e) => isHb ? <HbRow key={e.id} store={store} e={e} /> : <FerritinRow key={e.id} store={store} e={e} />)}
        {arr.length === 0 && <div className="body" style={{ padding: '18px 4px' }}>No readings yet.</div>}
      </div>
    </MSheet>
  );
}

function TransfusionHistorySheet({ store, close }) {
  const arr = [...(store.data.transfusions || [])].sort((a, b) => TC.parse(b.date) - TC.parse(a.date));
  return (
    <MSheet title="All transfusions" onClose={close}>
      <SLabel action={<button className="link" style={{ fontSize: 12.5 }} onClick={() => store.openModal('logTransfusion', {})}>+ Log</button>}>{arr.length} transfusion{arr.length === 1 ? '' : 's'}</SLabel>
      <div style={{ display: 'flex', flexDirection: 'column', maxHeight: 460, overflowY: 'auto', scrollbarWidth: 'none' }}>
        {arr.map((t, i) => <TransfusionRow key={t.id} store={store} t={t} latest={i === 0} />)}
        {arr.length === 0 && <div className="body" style={{ padding: '18px 4px' }}>No transfusions logged.</div>}
      </div>
    </MSheet>
  );
}

/* ---- appointments: create / edit a doctor or clinic visit (date + reminder) ---- */
function AddAppointmentSheet({ store, close, edit }) {
  const A = TC.appts;
  const editing = !!edit;
  const [f, setF] = React.useState(() => edit ? {
    title: edit.title || '', type: edit.type || 'clinic', date: edit.date || TC.inDaysDate(7),
    time: edit.time || '', location: edit.location || '', notes: edit.notes || '',
    remind: edit.remind || '1d', repeat: edit.repeat || 'none',
  } : {
    title: '', type: 'clinic', date: TC.inDaysDate(7), time: '',
    location: store.patient.treatmentCenter || '', notes: '', remind: '1d', repeat: 'none',
  });
  const set = (k, v) => setF((s) => ({ ...s, [k]: v }));
  const [warn, setWarn] = React.useState('');
  const typeOpts = ['clinic', 'lab', 'imaging', 'review', 'other'].map((k) => ({ value: k, label: A.typeMeta(k).short }));

  const save = () => {
    if (!f.title.trim()) { setWarn('Please give the appointment a name.'); return; }
    if (!f.date) { setWarn('Please choose a date.'); return; }
    const rec = {
      title: f.title.trim(), type: f.type, date: f.date, time: f.time || null,
      location: f.location.trim() || null, notes: f.notes.trim() || null,
      remind: f.remind, repeat: f.repeat,
    };
    store.mutate((d) => {
      d.appointments = d.appointments || [];
      if (editing) {
        const x = d.appointments.find((z) => z.id === edit.id);
        if (x) Object.assign(x, rec);
      } else {
        d.appointments.push(Object.assign({ id: 'a_' + TC.uid(), createdAt: new Date().toISOString() }, rec));
      }
    });
    store.showToast(editing ? 'Appointment updated' : 'Appointment saved', '📅');
    close();
  };

  const del = () => {
    store.openModal('confirm', {
      title: 'Delete this appointment?',
      message: `“${edit.title}” on ${A.dateLine(edit)} will be removed.`,
      confirmLabel: 'Delete',
      onConfirm: () => { store.mutate((d) => { d.appointments = (d.appointments || []).filter((z) => z.id !== edit.id); }); store.showToast('Appointment deleted', '🗑️'); },
    });
  };

  return (
    <MSheet title={editing ? 'Edit appointment' : 'Schedule an appointment'} onClose={close}>
      <div className="field">
        <label className="field-label">What is it? *</label>
        <input className="input" value={f.title} onChange={(e) => set('title', e.target.value)}
          placeholder="e.g. Cardiology review, T2* MRI, Blood test" autoFocus={!editing} />
      </div>

      <div className="field">
        <label className="field-label">Type</label>
        <Segmented options={typeOpts} value={f.type} onChange={(v) => set('type', v)} />
      </div>

      <div className="row" style={{ gap: 10 }}>
        <div className="field" style={{ flex: 1.3 }}>
          <label className="field-label">Date *</label>
          <input className="input" type="date" value={f.date} min={TC.daysAgoDate(365)} onChange={(e) => set('date', e.target.value)} />
        </div>
        <div className="field" style={{ flex: 1 }}>
          <label className="field-label">Time</label>
          <input className="input" type="time" value={f.time} onChange={(e) => set('time', e.target.value)} />
        </div>
      </div>

      <div className="field">
        <label className="field-label">Where (optional)</label>
        <input className="input" value={f.location} onChange={(e) => set('location', e.target.value)} placeholder="e.g. IGMH, Malé · Thalassaemia Centre" />
      </div>

      <div className="row" style={{ gap: 10 }}>
        <div className="field" style={{ flex: 1 }}>
          <label className="field-label"><Icon name="bell" size={12} color="var(--ink-3)" /> Remind me</label>
          <select className="input" value={f.remind} onChange={(e) => set('remind', e.target.value)} style={{ appearance: 'auto' }}>
            {A.REMINDERS.map((r) => <option key={r.key} value={r.key}>{r.label}</option>)}
          </select>
        </div>
        <div className="field" style={{ flex: 1 }}>
          <label className="field-label"><Icon name="refresh" size={12} color="var(--ink-3)" /> Repeats</label>
          <select className="input" value={f.repeat} onChange={(e) => set('repeat', e.target.value)} style={{ appearance: 'auto' }}>
            {A.REPEATS.map((r) => <option key={r.key} value={r.key}>{r.label}</option>)}
          </select>
        </div>
      </div>

      <div className="field">
        <label className="field-label">Notes (optional)</label>
        <textarea className="input textarea" rows={2} value={f.notes} onChange={(e) => set('notes', e.target.value)} placeholder="e.g. Bring previous MRI report · fast from midnight" />
      </div>

      {(store.settings.reminders && store.settings.reminders.appointment === false && f.remind !== 'none') ? (
        <MWarn>Appointment reminders are turned off in your notification settings, so this won’t notify you yet. You can turn them on in Me · Notifications.</MWarn>
      ) : null}
      {warn ? <MWarn>{warn}</MWarn> : null}

      <div className="row" style={{ gap: 10, marginTop: 4 }}>
        {editing
          ? <button className="btn btn-ghost" style={{ flex: 'none', color: 'var(--waiting)' }} onClick={del} aria-label="Delete"><Icon name="trash" size={17} color="var(--waiting)" /></button>
          : <button className="btn btn-ghost" style={{ flex: 1 }} onClick={close}>Cancel</button>}
        <button className="btn btn-primary" style={{ flex: 1.6 }} onClick={save}>
          <Icon name="check" size={17} color="#fff" sw={2.6} /> {editing ? 'Save changes' : 'Save appointment'}
        </button>
      </div>
    </MSheet>
  );
}

Object.assign(window, {
  MSheet, MDialog, fillTpl2, Segmented, Switch, BloodGrid, Chips, MStepper, SLabel, MWarn,
  PickLogDonor, LogDonationSheet, ThankYouDialog, DeferSheet, ArchiveSheet, LogContactSheet, DonorHistorySheet,
  LogTransfusionSheet, UploadLabSheet, AddMedSheet, ImportSheet,
  ConfirmDialog, LogHbSheet, LogFerritinSheet, LevelHistorySheet, TransfusionHistorySheet,
  AddAppointmentSheet,
});
