// patients.jsx — Patient list (grouped by appt) + full-page chart view
// Wired to /api/patients, /api/patients/profile, POST /api/patients,
// PUT /api/patients/update via the store.

const { useState: usePSt, useMemo: usePMemo, useCallback: usePCb, useEffect: usePEf } = React;

// ── Helpers ──────────────────────────────────────────────────────────────────

function daysSince(iso) {
  if (!iso) return 999;
  const d = new Date(iso);
  if (isNaN(d)) return 999;
  return Math.round((Date.now() - d.getTime()) / 86400000);
}

// ── VitalSpark (inline sparkline) ───────────────────────────────────────────

function VitalSparkline({ values, warn, width = 56, height = 24 }) {
  if (!values || values.length === 0) {
    return (
      <svg width={width} height={height} style={{display: "block", flexShrink: 0, opacity: 0.4}}>
        <line x1={0} y1={height/2} x2={width} y2={height/2} stroke="var(--ink-5)" strokeWidth="1" strokeDasharray="3 3"/>
      </svg>
    );
  }
  const max = Math.max(...values), min = Math.min(...values);
  const range = max - min || 1;
  const pts = values.map((v, i) => {
    const x = values.length === 1 ? width / 2 : (i / (values.length - 1)) * width;
    const y = height - ((v - min) / range) * (height - 4) - 2;
    return `${x},${y}`;
  }).join(" ");
  const color = warn ? "var(--accent-danger)" : "var(--primary)";
  const lastX = values.length === 1 ? width / 2 : width;
  const lastY = height - ((values[values.length - 1] - min) / range) * (height - 4) - 2;
  return (
    <svg width={width} height={height} style={{display: "block", flexShrink: 0}}>
      <polyline points={pts} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" opacity="0.8"/>
      <circle cx={lastX} cy={lastY} r="2.5" fill={color}/>
    </svg>
  );
}

// ── PatientRow ───────────────────────────────────────────────────────────────

function PatientRow({ p, onOpen, todayAppt, lastReason, isFavorite, onToggleFavorite }) {
  const t = window.MSStore.useT();
  const open = () => onOpen(p.id);

  return (
    <div
      className="ms-prow"
      role="button"
      tabIndex="0"
      onClick={open}
      onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); open(); } }}
    >
      <div className="ms-prow-id">
        <div className="avatar">{p.avatar}</div>
        <div className="ms-prow-name-col">
          <span className="ms-prow-name">{p.first} {p.last}</span>
          <span className="ms-prow-sub">
            {isFavorite ? <><Icon.Star size={12} fill="currentColor"/> {t("pat.favorite")}</> : (p.age ? <>{p.age}{p.sex || ""}</> : (p.phone || p.email || ""))}
          </span>
        </div>
      </div>

      <div className="ms-prow-cell">
        <span className="ms-prow-cell-val">{p.lastVisit ? new Date(p.lastVisit).toLocaleDateString("en-US", {month: "short", day: "numeric"}) : "—"}</span>
        <span className="ms-prow-cell-sub">{lastReason || (p.total_visits ? `${p.total_visits} visit${p.total_visits === 1 ? "" : "s"}` : "No visits yet")}</span>
      </div>

      <div className="ms-prow-action">
        <button
          type="button"
          className={"ms-star-btn" + (isFavorite ? " is-active" : "")}
          onClick={(e) => { e.stopPropagation(); onToggleFavorite(p.id); }}
          aria-label={isFavorite ? "Remove favorite" : "Add favorite"}
          title={isFavorite ? "Remove favorite" : "Add favorite"}
        >
          <Icon.Star size={15} fill={isFavorite ? "currentColor" : "none"}/>
        </button>
        <Icon.ChevronRight size={15} style={{color: "var(--ink-5)"}}/>
      </div>
    </div>
  );
}

// ── Add patient modal ────────────────────────────────────────────────────────

function AddPatientModal({ onClose, onAdd }) {
  const [form, setForm] = usePSt({
    first: "", last: "", dob: "", sex: "F",
    phone: "", email: "", insurance: "",
    guardian: "", flags: "", chronic: "",
  });
  const [pending, setPending] = usePSt(false);
  const [error, setError] = usePSt("");
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const valid = form.first.trim() && form.last.trim();

  async function handleSubmit() {
    if (!valid || pending) return;
    setError("");
    setPending(true);
    try {
      const fullName = `${form.first.trim()} ${form.last.trim()}`.trim();
      let age = "";
      if (form.dob) {
        const d = new Date(form.dob);
        if (!isNaN(d)) {
          const ageNum = Math.floor((Date.now() - d.getTime()) / (365.25 * 86400000));
          if (ageNum >= 0 && ageNum < 130) age = String(ageNum);
        }
      }
      await onAdd({ name: fullName, age, phone: form.phone, email: form.email });
      onClose();
    } catch (e) {
      setError(e && e.message || "Could not add patient.");
    } finally {
      setPending(false);
    }
  }

  return (
    <div className="ms-edit-overlay" onClick={e => e.target === e.currentTarget && onClose()}>
      <div className="ms-edit-drawer slide-up">
        <div className="ms-edit-head">
          <span style={{fontWeight: 600, fontSize: 15}}>Add patient</span>
          <button className="btn btn-ghost btn-icon btn-sm" onClick={onClose}><Icon.X size={15}/></button>
        </div>
        <div className="ms-edit-body scroll">
          <div className="ms-edit-section">
            <div className="eyebrow" style={{marginBottom: 12}}>Demographics</div>
            <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12}}>
              <div>
                <label className="field-label">First name <span style={{color: "var(--accent-danger)"}}>*</span></label>
                <input className="input" placeholder="First name" value={form.first} onChange={e => set("first", e.target.value)}/>
              </div>
              <div>
                <label className="field-label">Last name <span style={{color: "var(--accent-danger)"}}>*</span></label>
                <input className="input" placeholder="Last name" value={form.last} onChange={e => set("last", e.target.value)}/>
              </div>
              <div>
                <label className="field-label">Date of birth</label>
                <input className="input" type="date" value={form.dob} onChange={e => set("dob", e.target.value)}/>
              </div>
              <div>
                <label className="field-label">Sex</label>
                <select className="input select" value={form.sex} onChange={e => set("sex", e.target.value)}>
                  <option value="F">Female</option>
                  <option value="M">Male</option>
                  <option value="X">Non-binary / Other</option>
                </select>
              </div>
            </div>
          </div>
          <div className="ms-edit-section">
            <div className="eyebrow" style={{marginBottom: 12}}>Contact</div>
            <div className="col" style={{gap: 12}}>
              <div><label className="field-label">Phone</label><input className="input" placeholder="(415) 555-0100" value={form.phone} onChange={e => set("phone", e.target.value)}/></div>
              <div><label className="field-label">Email</label><input className="input" placeholder="patient@email.com" value={form.email} onChange={e => set("email", e.target.value)}/></div>
            </div>
          </div>
          {error && (
            <div style={{padding: "10px 12px", borderRadius: 10, background: "color-mix(in oklch, var(--accent-danger) 10%, white)", border: "1px solid color-mix(in oklch, var(--accent-danger) 30%, white)", color: "var(--accent-danger)", fontSize: 12.5}}>{error}</div>
          )}
        </div>
        <div className="ms-edit-foot">
          <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary" disabled={!valid || pending}
            style={{opacity: (valid && !pending) ? 1 : 0.5, cursor: (valid && !pending) ? "pointer" : "not-allowed"}}
            onClick={handleSubmit}>
            <Icon.Plus size={14}/>{pending ? "Adding…" : "Add patient"}
          </button>
        </div>
      </div>
    </div>
  );
}

// ── Edit patient drawer ─────────────────────────────────────────────────────

function PatientEditDrawer({ p, onClose, onSave }) {
  const [form, setForm] = usePSt({
    age: p.age || "",
    phone: p.phone || "",
    email: p.email || "",
  });
  const [pending, setPending] = usePSt(false);
  const [error, setError] = usePSt("");
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  async function submit() {
    setError("");
    setPending(true);
    try {
      await onSave(form);
      onClose();
    } catch (e) {
      setError(e && e.message || "Could not save changes.");
    } finally {
      setPending(false);
    }
  }

  return (
    <div className="ms-edit-overlay" onClick={e => e.target === e.currentTarget && onClose()}>
      <div className="ms-edit-drawer slide-up">
        <div className="ms-edit-head">
          <span style={{fontWeight: 600, fontSize: 15}}>Edit patient</span>
          <button className="btn btn-ghost btn-icon btn-sm" onClick={onClose}><Icon.X size={15}/></button>
        </div>
        <div className="ms-edit-body scroll">
          <div className="ms-edit-section">
            <div className="eyebrow" style={{marginBottom: 12}}>Patient · <span className="mono" style={{textTransform: "none"}}>{p.first} {p.last}</span></div>
            <div className="col" style={{gap: 12}}>
              <div><label className="field-label">Age</label><input className="input" value={form.age} onChange={e => set("age", e.target.value)} placeholder="38"/></div>
              <div><label className="field-label">Phone</label><input className="input" value={form.phone} onChange={e => set("phone", e.target.value)}/></div>
              <div><label className="field-label">Email</label><input className="input" value={form.email} onChange={e => set("email", e.target.value)}/></div>
            </div>
          </div>
          <div style={{fontSize: 11.5, color: "var(--ink-4)", padding: "0 4px"}}>
            Renaming a patient is handled at the next encounter — the directory is keyed by the recorded name.
          </div>
          {error && (
            <div style={{padding: "10px 12px", borderRadius: 10, background: "color-mix(in oklch, var(--accent-danger) 10%, white)", border: "1px solid color-mix(in oklch, var(--accent-danger) 30%, white)", color: "var(--accent-danger)", fontSize: 12.5}}>{error}</div>
          )}
        </div>
        <div className="ms-edit-foot">
          <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary" disabled={pending} onClick={submit}>
            {pending ? "Saving…" : "Save changes"}
          </button>
        </div>
      </div>
    </div>
  );
}

function VitalsEditDrawer({ patient, vitals, onClose, onSave }) {
  const [form, setForm] = usePSt({
    bp: vitals.bp || "",
    hr: vitals.hr || "",
    temp: vitals.temp || "",
    spo2: vitals.spo2 || "",
    weight: vitals.weight || "",
  });
  const [pending, setPending] = usePSt(false);
  const [error, setError] = usePSt("");
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  async function submit() {
    setPending(true); setError("");
    try {
      await onSave(form);
      onClose();
    } catch (e) {
      setError(e && e.message || "Could not save vitals.");
    } finally {
      setPending(false);
    }
  }
  return (
    <div className="ms-edit-overlay" onClick={e => e.target === e.currentTarget && onClose()}>
      <div className="ms-edit-drawer slide-up">
        <div className="ms-edit-head">
          <span style={{fontWeight: 600, fontSize: 15}}>Edit vitals</span>
          <button className="btn btn-ghost btn-icon btn-sm" onClick={onClose}><Icon.X size={15}/></button>
        </div>
        <div className="ms-edit-body scroll">
          <div className="ms-edit-section">
            <div className="eyebrow" style={{marginBottom: 12}}>{patient.first} {patient.last}</div>
            <div className="ms-form-grid-2">
              <div><label className="field-label">BP</label><input className="input" value={form.bp} onChange={e => set("bp", e.target.value)} placeholder="120/80"/></div>
              <div><label className="field-label">HR</label><input className="input" value={form.hr} onChange={e => set("hr", e.target.value)} placeholder="72"/></div>
              <div><label className="field-label">Temp</label><input className="input" value={form.temp} onChange={e => set("temp", e.target.value)} placeholder="98.6 F"/></div>
              <div><label className="field-label">SpO2</label><input className="input" value={form.spo2} onChange={e => set("spo2", e.target.value)} placeholder="98"/></div>
              <div><label className="field-label">Weight</label><input className="input" value={form.weight} onChange={e => set("weight", e.target.value)} placeholder="160 lb"/></div>
            </div>
          </div>
          {!vitals.session_id && <div style={{padding: "0 20px", color: "var(--ink-4)", fontSize: 12.5}}>Vitals can be saved after the patient has at least one real encounter.</div>}
          {error && <div style={{padding: "10px 20px", color: "var(--accent-danger)", fontSize: 12.5}}>{error}</div>}
        </div>
        <div className="ms-edit-foot">
          <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary" disabled={pending || !vitals.session_id} onClick={submit} style={{opacity: pending || !vitals.session_id ? 0.6 : 1}}>
            {pending ? "Saving…" : "Save vitals"}
          </button>
        </div>
      </div>
    </div>
  );
}

// ── PatientChart (full-page) ────────────────────────────────────────────────

function buildVitalTrend(history) {
  const points = [];
  for (const h of (history || []).slice().reverse()) {
    const bp = h.vitals && h.vitals.bp;
    if (bp) {
      const sys = parseInt(String(bp).split("/")[0], 10);
      if (!isNaN(sys)) points.push(sys);
    }
  }
  if (points.length >= 2) {
    return { label: "BP (sys)", values: points, unit: "mmHg sys", warn: false };
  }
  return null;
}

function PatientChart({ patient, onBack, onOpenEncounter, onSchedule, isFavorite, onToggleFavorite }) {
  const store = window.MSStore.useStore();
  const t = window.MSStore.useT();
  const [tab, setTab] = usePSt("overview");
  const [editing, setEditing] = usePSt(false);
  const [editingVitals, setEditingVitals] = usePSt(false);
  const [deleting, setDeleting] = usePSt(false);
  const [deleteError, setDeleteError] = usePSt("");
  const [profile, setProfile] = usePSt(null);
  const [profileError, setProfileError] = usePSt(null);
  const [loading, setLoading] = usePSt(true);

  usePEf(() => {
    let cancelled = false;
    setLoading(true);
    setProfileError(null);
    store.getPatientProfile(patient.id).then(data => {
      if (cancelled) return;
      setProfile(data);
      setLoading(false);
    }).catch(e => {
      if (cancelled) return;
      setProfileError(e && e.message || "Could not load patient");
      setLoading(false);
    });
    return () => { cancelled = true; };
  }, [patient.id]);

  const upcoming = (store.appointments || []).filter(a => a.patientName && a.patientName.toLowerCase() === (`${patient.first} ${patient.last}`).toLowerCase());

  const vitals = (profile && profile.latest_vitals) || {};
  const aggregated = (profile && profile.aggregated) || { diagnoses: [], medications: [], allergies: [] };
  const history = (profile && profile.history) || [];
  const vitalTrend = buildVitalTrend(history);

  async function handleSave(form) {
    await store.updatePatient(patient.id, {
      age: form.age || "",
      phone: form.phone || "",
      email: form.email || "",
    });
    const fresh = await store.getPatientProfile(patient.id);
    setProfile(fresh);
  }

  async function handleSaveVitals(form) {
    await store.updateSessionVitals(vitals.session_id, form);
    const fresh = await store.getPatientProfile(patient.id);
    setProfile(fresh);
  }

  async function handleDelete() {
    if (!window.confirm(`Delete ${patient.first} ${patient.last}'s patient record and visit history?`)) return;
    setDeleting(true); setDeleteError("");
    try {
      await store.deletePatient(patient.id);
      onBack();
    } catch (e) {
      setDeleteError(e && e.message || "Could not delete patient.");
    } finally {
      setDeleting(false);
    }
  }

  return (
    <div className="ms-chart fade-in">
      {editing && <PatientEditDrawer p={patient} onClose={() => setEditing(false)} onSave={handleSave}/>}
      {editingVitals && <VitalsEditDrawer patient={patient} vitals={vitals} onClose={() => setEditingVitals(false)} onSave={handleSaveVitals}/>}
      {/* Banner */}
      <div className="ms-chart-banner">
        <button className="btn btn-ghost btn-sm" onClick={onBack} style={{gap: 6}}>
          <Icon.ChevronRight size={14} style={{transform: "rotate(180deg)"}}/> {t("pat.title")}
        </button>
        <div className="ms-chart-banner-pat">
          <div className="avatar avatar-lg">{patient.avatar}</div>
          <div>
            <div className="row" style={{gap: 10, alignItems: "baseline"}}>
              <h2 className="h2" style={{fontSize: 20}}>{patient.first} {patient.last}</h2>
              {(aggregated.allergies || []).map(f => <span key={f} className="badge badge-warn" style={{fontSize: 11}}>⚠ {f}</span>)}
              {(aggregated.diagnoses || []).slice(0, 3).map(c => <span key={c} className="badge" style={{fontSize: 11}}>{c}</span>)}
            </div>
            <div className="dim" style={{fontSize: 12.5, marginTop: 3}}>
              {patient.age ? `${patient.age} yrs` : "Age unknown"} · {patient.phone || "—"} · {patient.email || "—"}
            </div>
          </div>
        </div>
        <div className="spacer"/>
        <div className="row" style={{gap: 6}}>
          <button className={"btn btn-sm ms-favorite-action" + (isFavorite ? " is-active" : "")} onClick={() => onToggleFavorite(patient.id)}>
            <Icon.Star size={13} fill={isFavorite ? "currentColor" : "none"}/>{isFavorite ? t("pat.favorite") : t("pat.addFavorite")}
          </button>
          <button className="btn btn-sm" onClick={() => setEditing(true)}><Icon.Edit size={13}/>{t("common.edit")}</button>
          <button className="btn btn-sm" onClick={() => setEditingVitals(true)}><Icon.Pulse size={13}/>{t("chart.rail.vitals")}</button>
          {patient.phone && <a className="btn btn-sm" href={`tel:${patient.phone}`}><Icon.Phone size={13}/></a>}
          {patient.email && <a className="btn btn-sm" href={`mailto:${patient.email}`}><Icon.Mail size={13}/></a>}
          {upcoming.length > 0 && (
            <button className="btn btn-sm btn-primary" onClick={() => onOpenEncounter(upcoming[0].id)}>
              <Icon.Pulse size={13}/>{t("chart.openEncounter")}
            </button>
          )}
          {upcoming.length === 0 && (
            <button className="btn btn-sm btn-primary" onClick={() => onSchedule && onSchedule(patient)}><Icon.CalendarPlus size={13}/>{t("chart.schedule")}</button>
          )}
          <button className="btn btn-sm" disabled={deleting} onClick={handleDelete} style={{color: "var(--accent-danger)"}}><Icon.Trash size={13}/>{deleting ? t("common.loading") : t("common.delete")}</button>
        </div>
      </div>
      {deleteError && <div style={{padding: "10px 20px", color: "var(--accent-danger)", fontSize: 12.5}}>{deleteError}</div>}

      {/* Body */}
      <div className="ms-chart-body">
        {/* Left rail */}
        <div className="ms-chart-rail scroll">
          <div className="ms-rail-section">
            <div className="ms-rail-title">{t("chart.rail.vitals")} {vitals && vitals.session_id && <span className="dim" style={{fontSize: 11, fontWeight: 400}}>· {t("chart.rail.latestVisit")}</span>}</div>
            <div className="ms-vitals-grid">
              {[
                { label: "BP", val: vitals.bp || "—" },
                { label: "HR", val: vitals.hr ? vitals.hr + " bpm" : "—" },
                { label: "Temp", val: vitals.temp || "—" },
                { label: "SpO₂", val: vitals.spo2 || "—" },
                { label: "Weight", val: vitals.weight || "—" },
              ].map(v => (
                <div key={v.label} className="ms-vital">
                  <div style={{fontSize: 10.5, color: "var(--ink-4)", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.04em"}}>{v.label}</div>
                  <div style={{fontFamily: "var(--font-display)", fontSize: 15, fontWeight: 500, marginTop: 2}}>{v.val}</div>
                </div>
              ))}
            </div>
          </div>

          {(aggregated.diagnoses || []).length > 0 && (
            <div className="ms-rail-section">
              <div className="ms-rail-title">{t("chart.rail.conditions")}</div>
              {aggregated.diagnoses.map(c => (
                <div key={c} className="ms-rail-item"><Icon.Pulse size={13} style={{color: "var(--ink-4)"}}/>{c}</div>
              ))}
            </div>
          )}

          {(aggregated.allergies || []).length > 0 && (
            <div className="ms-rail-section">
              <div className="ms-rail-title">{t("chart.rail.alerts")}</div>
              {aggregated.allergies.map(f => (
                <div key={f} className="ms-rail-item" style={{color: "oklch(0.45 0.14 75)"}}><Icon.Bell size={13}/>{f}</div>
              ))}
            </div>
          )}

          <div className="ms-rail-section">
            <div className="ms-rail-title">{t("chart.rail.medications")}</div>
            {(aggregated.medications || []).length === 0 && <div className="dim" style={{fontSize: 12, padding: "4px 8px"}}>{t("chart.rail.noMeds")}</div>}
            {(aggregated.medications || []).map(m => (
              <div key={m} className="ms-rail-item"><Icon.Pill size={13}/><span style={{fontWeight: 500, fontSize: 12.5}}>{m}</span></div>
            ))}
          </div>

          <div className="ms-rail-section">
            <div className="ms-rail-title">{t("chart.rail.contact")}</div>
            <div className="ms-rail-item" style={{flexDirection: "column", alignItems: "flex-start", gap: 1}}>
              <span className="dim" style={{fontSize: 11}}>{t("chart.rail.phone")}</span>
              <span style={{fontSize: 12.5}}>{patient.phone || "—"}</span>
            </div>
            <div className="ms-rail-item" style={{flexDirection: "column", alignItems: "flex-start", gap: 1}}>
              <span className="dim" style={{fontSize: 11}}>{t("chart.rail.email")}</span>
              <span style={{fontSize: 12.5}}>{patient.email || "—"}</span>
            </div>
          </div>
        </div>

        {/* Main content */}
        <div className="ms-chart-main scroll">
          <div className="ms-enc-tabs" style={{marginBottom: 24, paddingBottom: 0}}>
            {["overview", "notes", "medications", "labs", "documents"].map(tabId => (
              <button key={tabId} className={"ms-tab" + (tab === tabId ? " is-active" : "")} onClick={() => setTab(tabId)} style={{textTransform: "capitalize"}}>{t("chart.tab." + tabId)}</button>
            ))}
          </div>

          {loading && (
            <div className="card" style={{padding: 48, textAlign: "center", color: "var(--ink-4)"}}>
              <Icon.Sparkle size={28}/>
              <div style={{marginTop: 10, fontSize: 13}}>{t("chart.loading")}</div>
            </div>
          )}

          {!loading && profileError && (
            <div className="card" style={{padding: 24, color: "var(--accent-danger)", fontSize: 13}}>{profileError}</div>
          )}

          {!loading && !profileError && tab === "overview" && (
            <div className="col" style={{gap: 20}}>
              {vitalTrend && (
                <div className="card">
                  <div className="card-header">
                    <span className="card-title">{t("chart.trendLabel", { label: vitalTrend.label })}</span>
                    <span className="dim" style={{fontSize: 12}}>{t("chart.trendSub", { n: vitalTrend.values.length })}</span>
                  </div>
                  <div className="card-body" style={{paddingTop: 8}}>
                    <div className="row" style={{gap: 24, alignItems: "flex-end"}}>
                      <div>
                        <div style={{fontFamily: "var(--font-display)", fontSize: 36, fontWeight: 500, letterSpacing: "-0.02em", color: "var(--ink)", lineHeight: 1}}>
                          {vitalTrend.values[vitalTrend.values.length - 1]}
                          <span style={{fontSize: 14, color: "var(--ink-4)", fontWeight: 400, marginLeft: 4}}>{vitalTrend.unit}</span>
                        </div>
                      </div>
                      <VitalSparkline values={vitalTrend.values} width={160} height={48}/>
                    </div>
                  </div>
                </div>
              )}

              <div className="card">
                <div className="card-header">
                  <span className="card-title">{t("chart.history")}</span>
                  <span className="dim" style={{fontSize: 12}}>{t("chart.historyCount", { n: history.length })}</span>
                </div>
                <div style={{padding: "0 4px 8px"}}>
                  {history.length === 0 && (
                    <div style={{padding: 32, textAlign: "center", color: "var(--ink-4)", fontSize: 13}}>{t("chart.noVisits")}</div>
                  )}
                  {history.map((v, i) => {
                    const date = (v.started_at || v.date || "").slice(0, 10);
                    const reason = (v.diagnoses && v.diagnoses[0]) || v.chief_complaint || "Visit";
                    return (
                      <button key={v.session_id || i} className="ms-chart-visit-row" onClick={() => v.session_id && onOpenEncounter(v.session_id)}>
                        <div className="ms-chart-visit-date">
                          <div style={{fontFamily: "var(--font-display)", fontSize: 15, fontWeight: 500}}>
                            {date ? new Date(date).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "—"}
                          </div>
                        </div>
                        <div className="ms-chart-visit-line"/>
                        <div className="ms-chart-visit-content">
                          <div style={{fontWeight: 500, fontSize: 13.5}}>{reason}</div>
                          {v.duration_seconds ? <div className="dim" style={{fontSize: 12.5, marginTop: 2}}>{Math.round(v.duration_seconds / 60)} min</div> : null}
                        </div>
                        <Icon.ChevronRight size={14} style={{color: "var(--ink-5)", marginLeft: "auto", flexShrink: 0}}/>
                      </button>
                    );
                  })}
                </div>
              </div>
            </div>
          )}

          {!loading && !profileError && tab === "notes" && (
            <div className="col" style={{gap: 12}}>
              {history.length === 0 && (
                <div className="card" style={{padding: 48, textAlign: "center", color: "var(--ink-4)"}}>
                  <Icon.Document size={28}/>
                  <div style={{marginTop: 10, fontSize: 13}}>{t("chart.noNotes")}</div>
                </div>
              )}
              {history.map((v, i) => (
                <div key={v.session_id || i} className="card" style={{padding: 0, overflow: "hidden"}}>
                  <div className="card-header" style={{background: "var(--bg-soft)", borderBottom: "1px solid var(--line)"}}>
                    <div>
                      <span className="card-title" style={{fontSize: 13.5}}>{(v.diagnoses && v.diagnoses[0]) || "Visit"}</span>
                      <span className="dim" style={{fontSize: 12, marginLeft: 10}}>{(v.started_at || "").slice(0, 10)}</span>
                    </div>
                    {v.session_id && <button className="btn btn-sm btn-ghost" onClick={() => onOpenEncounter(v.session_id)}>Open</button>}
                  </div>
                  <div style={{padding: "14px 20px", fontSize: 13.5, lineHeight: 1.65, color: "var(--ink-2)"}}>
                    {v.chief_complaint
                      ? <><span className="dim" style={{fontWeight: 600, marginRight: 8, fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em"}}>{t("chart.chiefComplaint")}</span>{v.chief_complaint}</>
                      : <span className="dim">{t("chart.noChiefComplaint")}</span>}
                  </div>
                </div>
              ))}
            </div>
          )}

          {!loading && !profileError && tab === "medications" && (
            (aggregated.medications || []).length === 0 ? (
              <div className="card" style={{padding: 48, textAlign: "center", color: "var(--ink-4)"}}>
                <Icon.Pill size={28}/>
                <div style={{marginTop: 10, fontSize: 13}}>{t("chart.rail.noMeds")}</div>
              </div>
            ) : (
              <div className="col" style={{gap: 10}}>
                {(aggregated.medications || []).map(m => (
                  <div key={m} className="ms-order-row">
                    <div style={{width: 36, height: 36, borderRadius: 10, background: "var(--primary-soft)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0}}>
                      <Icon.Pill size={16} style={{color: "var(--primary-ink)"}}/>
                    </div>
                    <div style={{flex: 1}}>
                      <div style={{fontWeight: 600, fontSize: 13.5}}>{m}</div>
                    </div>
                  </div>
                ))}
              </div>
            )
          )}

          {!loading && !profileError && tab === "labs" && (
            <div className="card" style={{padding: 48, textAlign: "center", color: "var(--ink-4)"}}>
              <Icon.Document size={28}/>
              <div style={{marginTop: 10, fontSize: 13}}>{t("chart.noLabs")}</div>
            </div>
          )}

          {!loading && !profileError && tab === "documents" && (
            <div className="card" style={{padding: 48, textAlign: "center", color: "var(--ink-4)"}}>
              <Icon.Document size={28}/>
              <div style={{marginTop: 10, fontSize: 13}}>{t("chart.noDocs")}</div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ── Patients (main component) ────────────────────────────────────────────────

function Patients({ onOpenEncounter, onSchedulePatient, focusId }) {
  const store = window.MSStore.useStore();
  const t = window.MSStore.useT();
  const [adding, setAdding] = usePSt(false);
  const [q, setQ] = usePSt("");
  const [chartId, setChartId] = usePSt(focusId || null);
  const [sortFilter, setSortFilter] = usePSt("all");
  const [favoriteIds, setFavoriteIds] = usePSt(() => {
    try { return JSON.parse(localStorage.getItem("medsync-favorite-patients") || "[]"); }
    catch (_) { return []; }
  });
  const favoriteSet = usePMemo(() => new Set(favoriteIds), [favoriteIds]);
  const toggleFavorite = usePCb((id) => {
    setFavoriteIds(prev => {
      const next = prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id];
      try { localStorage.setItem("medsync-favorite-patients", JSON.stringify(next)); } catch (_) {}
      return next;
    });
  }, []);

  const todayAppointments = usePMemo(() => {
    const map = {};
    const today = new Date(); today.setHours(0, 0, 0, 0);
    const tomorrow = new Date(today.getTime() + 86400000);
    for (const a of (store.appointments || [])) {
      const t = new Date(a.scheduledAt);
      if (isNaN(t)) continue;
      if (t >= today && t < tomorrow && a.patientName) {
        const k = a.patientName.toLowerCase();
        if (!map[k] || t < new Date(map[k].scheduledAt)) map[k] = a;
      }
    }
    return map;
  }, [store.appointments]);

  const filtered = usePMemo(() => {
    let list = [...(store.patients || [])];
    if (q) {
      const ql = q.toLowerCase();
      list = list.filter(p =>
        `${p.first} ${p.last}`.toLowerCase().includes(ql) ||
        (p.phone || "").includes(q) ||
        (p.email || "").toLowerCase().includes(ql)
      );
    }
    if (sortFilter === "favorites") list = list.filter(p => favoriteSet.has(p.id));
    if (sortFilter === "today") list = list.filter(p => todayAppointments[(`${p.first} ${p.last}`).toLowerCase()]);
    return list;
  }, [q, sortFilter, store.patients, todayAppointments, favoriteSet]);

  const grouped = usePMemo(() => {
    const groups = [[], [], []];
    for (const p of filtered) {
      const todayAppt = todayAppointments[(`${p.first} ${p.last}`).toLowerCase()];
      let g;
      if (todayAppt) g = 0;
      else g = daysSince(p.lastVisit) <= 30 ? 1 : 2;
      groups[g].push(p);
    }
    return groups;
  }, [filtered, todayAppointments]);

  const openChart = usePCb((id) => setChartId(id), []);
  const backToList = usePCb(() => setChartId(null), []);

  if (chartId) {
    const patient = (store.patients || []).find(p => p.id === chartId);
    if (!patient) {
      return (
        <div className="ms-page fade-in">
          <div className="ms-page-head">
            <button className="btn btn-ghost btn-sm" onClick={backToList}><Icon.ChevronLeft size={14}/>Patients</button>
          </div>
          <div className="card" style={{padding: 48, textAlign: "center", color: "var(--ink-4)"}}>Patient not found</div>
        </div>
      );
    }
    return <PatientChart patient={patient} onBack={backToList} onOpenEncounter={onOpenEncounter} onSchedule={onSchedulePatient} isFavorite={favoriteSet.has(patient.id)} onToggleFavorite={toggleFavorite}/>;
  }

  async function handleAdd(form) {
    await store.createPatient(form);
  }

  const totalPatients = (store.patients || []).length;
  const isLoading = store.loading && store.loading.patients;
  const groupLabels = [t("pat.groupToday"), t("pat.groupRecent"), t("pat.groupEarlier")];

  return (
    <div className="ms-page fade-in">
      {adding && <AddPatientModal onClose={() => setAdding(false)} onAdd={handleAdd}/>}
      <div className="ms-page-head">
        <div>
          <h1 className="h1">{t("pat.title")}</h1>
          <div style={{color: "var(--ink-3)", marginTop: 4, fontSize: 14}}>
            {isLoading ? t("pat.loading") : t("pat.count", { n: totalPatients })}
            {(store.errors && store.errors.patients) && <span style={{color: "var(--accent-danger)", marginLeft: 8}}>{store.errors.patients}</span>}
          </div>
        </div>
        <div className="row" style={{gap: 8}}>
          <button className="btn btn-primary" onClick={() => setAdding(true)}><Icon.Plus size={16}/>{t("pat.add")}</button>
        </div>
      </div>

      {/* Toolbar */}
      <div className="row" style={{gap: 10, marginBottom: 16}}>
        <div className="ms-search-input" style={{flex: 1, maxWidth: 380}}>
          <Icon.Search size={15}/>
          <input value={q} onChange={e => setQ(e.target.value)} placeholder={t("pat.searchPh")}/>
        </div>
        <div className="ms-segmented">
          {[["all", t("common.all")], ["today", t("common.today")], ["favorites", t("pat.favorites")]].map(([v, label]) => (
            <button key={v} className={sortFilter === v ? "is-active" : ""} onClick={() => setSortFilter(v)}>{label}</button>
          ))}
        </div>
      </div>

      {/* Column headers */}
      <div className="ms-prow-header">
        <div className="ms-prow-id" style={{paddingLeft: 10}}>{t("pat.col.patient")}</div>
        <div className="ms-prow-cell">{t("pat.col.lastVisit")}</div>
        <div style={{width: 28}}></div>
      </div>

      {/* Grouped rows */}
      <div className="col" style={{gap: 24}}>
        {grouped.map((group, gi) => group.length === 0 ? null : (
          <div key={gi}>
            <div className="ms-plist-group-label">{groupLabels[gi]}</div>
            <div className="ms-plist">
              {group.map(p => {
                const todayAppt = todayAppointments[(`${p.first} ${p.last}`).toLowerCase()];
                const lastReason = (p.raw && p.raw.diagnoses && p.raw.diagnoses[0]) || (p.total_visits ? `${p.total_visits} visit${p.total_visits === 1 ? "" : "s"}` : null);
                return <PatientRow key={p.id} p={p} onOpen={openChart} todayAppt={todayAppt} lastReason={lastReason} isFavorite={favoriteSet.has(p.id)} onToggleFavorite={toggleFavorite}/>;
              })}
            </div>
          </div>
        ))}
        {filtered.length === 0 && !isLoading && (
          <div className="card" style={{padding: 48, textAlign: "center", color: "var(--ink-4)"}}>
            <Icon.Search size={28}/>
            <div style={{marginTop: 10, fontSize: 13}}>{q ? "No patients match your search" : "No patients yet — click Add patient to create one."}</div>
          </div>
        )}
      </div>
    </div>
  );
}

window.Patients = Patients;
