// TitratePlan — Daily Log component
// Tracks GLP-1-relevant metrics: weight, glucose, BP, appetite, energy, mood, side effects.
// Persists to localStorage. Exposes Save-as-PDF (print) and CSV export.

const { useState: _useState, useEffect: _useEffect, useMemo: _useMemo } = React;

const LOG_STORAGE_KEY = "titrateplan_log_v1";
const UNIT_STORAGE_KEY = "titrateplan_log_units_v1";

const SIDE_EFFECT_OPTIONS = [
  "Nausea", "Vomiting", "Diarrhea", "Constipation",
  "Heartburn", "Bloating", "Burping", "Fatigue",
  "Headache", "Dizziness", "Insomnia", "Inj. site reaction",
];

const SCALE_LABELS = {
  appetite: ["Very low", "Low", "Normal", "High", "Very high"],
  energy:   ["Drained", "Tired", "OK", "Energized", "Buzzing"],
  mood:     ["Low", "Down", "OK", "Good", "Great"],
};

function loadLog() {
  try {
    const raw = localStorage.getItem(LOG_STORAGE_KEY);
    if (!raw) return [];
    const arr = JSON.parse(raw);
    return Array.isArray(arr) ? arr : [];
  } catch { return []; }
}

function saveLog(entries) {
  try { localStorage.setItem(LOG_STORAGE_KEY, JSON.stringify(entries)); } catch {}
  try { window.dispatchEvent(new CustomEvent("titrateplan-log-updated")); } catch {}
}

// ---------- Sample data generator (demo only) ----------
function generateSampleEntries(days = 90, unit = "lb") {
  // Realistic GLP-1 journey: gradual weight loss, glucose dropping then stabilizing,
  // BP slowly improving, appetite dropping early then recovering, side effects clustering
  // around dose escalations (weeks 5, 9, 13).
  const SE_POOL = ["Nausea", "Fatigue", "Constipation", "Headache", "Heartburn", "Bloating"];
  const startWeight = unit === "kg" ? 95 : 210;        // baseline
  const totalLoss  = unit === "kg" ? 9  : 20;          // 90-day target loss
  const out = [];
  const today = new Date();
  for (let i = 0; i < days; i++) {
    const d = new Date(today);
    d.setDate(d.getDate() - (days - 1 - i));
    const t = i / (days - 1);                          // 0 → 1 progress
    // S-curve loss, plus small daily noise
    const sCurve = 1 / (1 + Math.exp(-6 * (t - 0.5)));
    const noise = (Math.sin(i * 1.7) + Math.cos(i * 0.9)) * 0.4;
    const weight = +(startWeight - totalLoss * sCurve + noise).toFixed(1);

    // Glucose drops from ~135 to ~98
    const glucose = Math.round(135 - 37 * sCurve + (Math.sin(i * 0.7) * 4));

    // BP improves: 138/86 → 122/78
    const bp_sys = Math.round(138 - 16 * t + (Math.sin(i * 1.1) * 2));
    const bp_dia = Math.round(86 - 8 * t + (Math.cos(i * 1.3) * 1.5));

    // Appetite dives early (3→1) then recovers slightly to 2
    let appetite = 3;
    if (t < 0.2) appetite = 3;
    else if (t < 0.4) appetite = 2;
    else if (t < 0.85) appetite = 1;
    else appetite = 2;

    // Energy: dip in early weeks while body adjusts, then recovers
    let energy = 3;
    if (t < 0.15) energy = 3;
    else if (t < 0.35) energy = 2;
    else if (t < 0.6) energy = 3;
    else energy = 4;

    // Mood: improves with progress
    const mood = t < 0.25 ? 3 : t < 0.5 ? 3 : t < 0.75 ? 4 : 4;

    // Side effects cluster after escalations (weeks 5, 9, 13 = days 28, 56, 84)
    const week = Math.floor(i / 7) + 1;
    const justEscalated = [5, 9, 13].includes(week) && (i % 7) < 4;
    const sideEffects = [];
    if (justEscalated) {
      sideEffects.push("Nausea");
      if (i % 2 === 0) sideEffects.push("Fatigue");
      if (i % 3 === 0) sideEffects.push("Heartburn");
    } else if (i % 9 === 0 && t > 0.1) {
      sideEffects.push(SE_POOL[i % SE_POOL.length]);
    }

    const notes = justEscalated
      ? (i % 7 === 0 ? "Stepped up dose this week — taking it easy." : "")
      : (i % 14 === 0 ? "Feeling good, sticking with the routine." : "");

    out.push({
      id: Date.now() + i,
      date: window.isoDate(d),
      weight,
      weightUnit: unit,
      glucose,
      bp_sys,
      bp_dia,
      appetite,
      energy,
      mood,
      sideEffects,
      notes,
    });
  }
  // Most recent first (matches existing list ordering)
  return out.sort((a, b) => b.date.localeCompare(a.date));
}

function makeEmptyDraft() {
  return {
    date: window.isoDate(new Date()),
    weight: "", glucose: "",
    bp_sys: "", bp_dia: "",
    appetite: 0, energy: 0, mood: 0,
    sideEffects: [],
    notes: "",
  };
}

// ---------- Sparkline ----------
function Sparkline({ data, color, height = 44 }) {
  // data: array of {x: ISO date, y: number}
  if (!data || data.length === 0) {
    return (
      <svg className="spark-svg" viewBox="0 0 100 44" preserveAspectRatio="none" style={{ height }}>
        <line x1="0" y1="22" x2="100" y2="22" stroke="var(--line-strong)" strokeWidth="0.5" strokeDasharray="2 2" />
      </svg>
    );
  }
  const ys = data.map(d => d.y);
  const yMin = Math.min(...ys);
  const yMax = Math.max(...ys);
  const span = yMax - yMin || 1;
  const w = 100, h = 44, pad = 4;
  const xs = data.map((_, i) => pad + (i / Math.max(1, data.length - 1)) * (w - 2 * pad));
  const ysn = data.map(d => h - pad - ((d.y - yMin) / span) * (h - 2 * pad));
  const path = xs.map((x, i) => `${i === 0 ? "M" : "L"} ${x.toFixed(2)} ${ysn[i].toFixed(2)}`).join(" ");
  const last = data.length - 1;
  return (
    <svg className="spark-svg" viewBox="0 0 100 44" preserveAspectRatio="none" style={{ height }}>
      <path d={path} fill="none" stroke={color} strokeWidth="1.2" strokeLinejoin="round" strokeLinecap="round" />
      <circle cx={xs[last]} cy={ysn[last]} r="1.6" fill={color} />
    </svg>
  );
}

// ---------- Sparkline card ----------
function SparkCard({ label, unit, entries, accessor, color, fmt }) {
  const points = entries
    .filter(e => accessor(e) != null && !isNaN(Number(accessor(e))))
    .map(e => ({ x: e.date, y: Number(accessor(e)) }))
    .sort((a, b) => a.x.localeCompare(b.x));

  const last = points[points.length - 1];
  const prev = points[points.length - 2];
  let delta = null;
  let dCls = "flat";
  if (last && prev) {
    const d = last.y - prev.y;
    if (Math.abs(d) > 0.01) {
      delta = (d > 0 ? "↑" : "↓") + " " + Math.abs(d).toFixed(d % 1 === 0 ? 0 : 1);
      dCls = d > 0 ? "up" : "down";
    } else {
      delta = "—";
    }
  }

  return (
    <div className="spark-card">
      <div className="lab">{label}</div>
      <div className="v">
        {last ? (fmt ? fmt(last.y) : last.y) : <span style={{ color: "var(--muted-2)" }}>—</span>}
        {last && unit ? <span className="unit">{unit}</span> : null}
      </div>
      <div className={`delta ${dCls}`}>
        {delta ? `${delta} since last entry` : (last ? "first entry" : "no entries yet")}
      </div>
      <Sparkline data={points} color={color} />
    </div>
  );
}

// ---------- Side-effect chip ----------
function SideEffectChips({ value, onChange }) {
  return (
    <div className="se-grid">
      {SIDE_EFFECT_OPTIONS.map(opt => {
        const on = value.includes(opt);
        return (
          <button
            key={opt}
            type="button"
            className={`se-chip ${on ? "selected" : ""}`}
            onClick={() => onChange(on ? value.filter(v => v !== opt) : [...value, opt])}>
            {opt}
          </button>
        );
      })}
    </div>
  );
}

// ---------- Scale chips ----------
function ScaleChips({ kind, value, onChange }) {
  const labs = SCALE_LABELS[kind];
  return (
    <>
      <div className="scale-chips">
        {[1,2,3,4,5].map(n => (
          <button
            key={n}
            type="button"
            className={`scale-chip ${value === n ? "selected" : ""}`}
            onClick={() => onChange(value === n ? 0 : n)}>
            {n}
          </button>
        ))}
      </div>
      <div className="scale-row">
        <span>{labs[0]}</span>
        <span>{labs[4]}</span>
      </div>
    </>
  );
}

// ---------- CSV export ----------
function exportCsv(entries, weightUnit) {
  const cols = ["date","weight_"+weightUnit,"glucose_mgdl","bp_systolic","bp_diastolic","appetite_1_5","energy_1_5","mood_1_5","side_effects","notes"];
  const rows = [cols.join(",")];
  const sorted = [...entries].sort((a,b) => a.date.localeCompare(b.date));
  for (const e of sorted) {
    const r = [
      e.date,
      e.weight ?? "",
      e.glucose ?? "",
      e.bp_sys ?? "",
      e.bp_dia ?? "",
      e.appetite || "",
      e.energy || "",
      e.mood || "",
      `"${(e.sideEffects || []).join("; ")}"`,
      `"${(e.notes || "").replace(/"/g,'""')}"`,
    ];
    rows.push(r.join(","));
  }
  const blob = new Blob([rows.join("\n")], { type: "text/csv;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = `titrateplan-log-${window.isoDate(new Date())}.csv`;
  document.body.appendChild(a); a.click(); document.body.removeChild(a);
  URL.revokeObjectURL(url);
}

// ---------- Print region (hidden, populated on print) ----------
function PrintChart({ label, unit, color, entries, accessor }) {
  const points = entries
    .map(e => ({ x: e.date, y: accessor(e) }))
    .filter(p => p.y !== null && p.y !== undefined && !isNaN(p.y));
  if (points.length === 0) {
    return (
      <div style={{ flex: 1, border: "1px solid #ddd", padding: 10, minWidth: 0 }}>
        <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "#666", textTransform: "uppercase", letterSpacing: "0.06em" }}>{label}{unit ? ` (${unit})` : ""}</div>
        <div style={{ fontFamily: "var(--mono)", fontSize: 10, color: "#999", marginTop: 18 }}>No data</div>
      </div>
    );
  }
  const ys = points.map(p => p.y);
  const min = Math.min(...ys), max = Math.max(...ys);
  const range = max - min || 1;
  const W = 200, H = 60;
  const xs = points.map((_, i) => points.length === 1 ? W/2 : (i / (points.length - 1)) * W);
  const ysn = ys.map(y => H - 8 - ((y - min) / range) * (H - 16));
  const path = xs.map((x, i) => `${i === 0 ? "M" : "L"} ${x.toFixed(1)} ${ysn[i].toFixed(1)}`).join(" ");
  const first = ys[0], last = ys[ys.length - 1];
  const delta = (last - first).toFixed(1);
  return (
    <div style={{ flex: 1, border: "1px solid #ddd", padding: 10, minWidth: 0 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
        <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "#666", textTransform: "uppercase", letterSpacing: "0.06em" }}>{label}{unit ? ` (${unit})` : ""}</span>
        <span style={{ fontFamily: "var(--mono)", fontSize: 10, color: "#666" }}>{first} → {last} ({delta > 0 ? "+" : ""}{delta})</span>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{ width: "100%", height: 60, marginTop: 6 }}>
        <path d={path} fill="none" stroke={color} strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round" />
        <circle cx={xs[xs.length-1]} cy={ysn[ysn.length-1]} r="2" fill={color} />
      </svg>
    </div>
  );
}

function PrintRegion({ entries, weightUnit }) {
  const sorted = [...entries].sort((a,b) => a.date.localeCompare(b.date));
  return (
    <div id="print-region" style={{ display: "none" }}>
      <h1 style={{ fontFamily: "var(--serif)", fontWeight: 400, fontSize: 28, marginBottom: 4 }}>Daily log report</h1>
      <div style={{ fontFamily: "var(--mono)", fontSize: 11, color: "#666", marginBottom: 20 }}>
        Generated {window.isoDate(new Date())} · TitratePlan · {sorted.length} entries
      </div>

      {sorted.length > 0 && (
        <div style={{ display: "flex", gap: 10, marginBottom: 20, flexWrap: "wrap" }}>
          <PrintChart label="Weight" unit={weightUnit} color="#2f7b6e" entries={sorted} accessor={e => e.weight} />
          <PrintChart label="Glucose" unit="mg/dL" color="#b15a2a" entries={sorted} accessor={e => e.glucose} />
          <PrintChart label="BP Sys" unit="mmHg" color="#7a5a8b" entries={sorted} accessor={e => e.bp_sys} />
          <PrintChart label="Appetite" unit="1–5" color="#2f7b6e" entries={sorted} accessor={e => e.appetite} />
        </div>
      )}
      <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 11, fontFamily: "var(--mono)" }}>
        <thead>
          <tr style={{ borderBottom: "1px solid #999", textAlign: "left" }}>
            <th style={{ padding: "6px 8px" }}>Date</th>
            <th style={{ padding: "6px 8px" }}>Weight ({weightUnit})</th>
            <th style={{ padding: "6px 8px" }}>Glucose</th>
            <th style={{ padding: "6px 8px" }}>BP</th>
            <th style={{ padding: "6px 8px" }}>Appet.</th>
            <th style={{ padding: "6px 8px" }}>Energy</th>
            <th style={{ padding: "6px 8px" }}>Mood</th>
            <th style={{ padding: "6px 8px" }}>Side effects / notes</th>
          </tr>
        </thead>
        <tbody>
          {sorted.map(e => (
            <tr key={e.id} style={{ borderBottom: "1px solid #ddd" }}>
              <td style={{ padding: "6px 8px" }}>{e.date}</td>
              <td style={{ padding: "6px 8px" }}>{e.weight || "—"}</td>
              <td style={{ padding: "6px 8px" }}>{e.glucose || "—"}</td>
              <td style={{ padding: "6px 8px" }}>{e.bp_sys && e.bp_dia ? `${e.bp_sys}/${e.bp_dia}` : "—"}</td>
              <td style={{ padding: "6px 8px" }}>{e.appetite || "—"}</td>
              <td style={{ padding: "6px 8px" }}>{e.energy || "—"}</td>
              <td style={{ padding: "6px 8px" }}>{e.mood || "—"}</td>
              <td style={{ padding: "6px 8px", fontFamily: "var(--sans)" }}>
                {(e.sideEffects || []).join(", ")}
                {e.notes ? <div style={{ fontStyle: "italic", color: "#555", marginTop: 2 }}>{e.notes}</div> : null}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      <div style={{ marginTop: 32, fontSize: 10, color: "#666", fontStyle: "italic" }}>
        TitratePlan is an educational scheduling tool. This report is generated locally in your browser and is intended for personal reference or to share with your clinician. Always follow your prescriber's guidance.
      </div>
    </div>
  );
}

// ---------- Quick log entry card (top of page, beside the schedule builder) ----------
function QuickLogCard() {
  const [unit, setUnit] = _useState(() => {
    try { return localStorage.getItem(UNIT_STORAGE_KEY) || "lb"; }
    catch { return "lb"; }
  });
  const [draft, setDraft] = _useState(() => makeEmptyDraft());
  const [entries, setEntries] = _useState(() => loadLog());
  const [savedFlash, setSavedFlash] = _useState(false);

  _useEffect(() => {
    try { localStorage.setItem(UNIT_STORAGE_KEY, unit); } catch {}
    try { window.dispatchEvent(new CustomEvent("titrateplan-unit-changed", { detail: unit })); } catch {}
  }, [unit]);

  _useEffect(() => {
    const handler = () => setEntries(loadLog());
    window.addEventListener("titrateplan-log-updated", handler);
    return () => window.removeEventListener("titrateplan-log-updated", handler);
  }, []);

  _useEffect(() => {
    const handler = (e) => {
      const d = e.detail || {};
      setDraft({
        date: d.date,
        weight: d.weight ?? "",
        glucose: d.glucose ?? "",
        bp_sys: d.bp_sys ?? "",
        bp_dia: d.bp_dia ?? "",
        appetite: d.appetite || 0,
        energy: d.energy || 0,
        mood: d.mood || 0,
        sideEffects: d.sideEffects || [],
        notes: d.notes || "",
      });
      const card = document.querySelector(".quick-log-card");
      if (card) {
        const top = card.getBoundingClientRect().top + window.scrollY - 80;
        window.scrollTo({ top, behavior: "smooth" });
      }
    };
    window.addEventListener("titrateplan-log-edit", handler);
    return () => window.removeEventListener("titrateplan-log-edit", handler);
  }, []);

  function update(patch) { setDraft({ ...draft, ...patch }); }

  function handleSave() {
    if (!draft.date) return;
    const cleanWeight = draft.weight !== "" ? Number(draft.weight) : null;
    const cleanGlucose = draft.glucose !== "" ? Number(draft.glucose) : null;
    const cleanBpSys = draft.bp_sys !== "" ? Number(draft.bp_sys) : null;
    const cleanBpDia = draft.bp_dia !== "" ? Number(draft.bp_dia) : null;
    const entry = {
      id: Date.now(),
      date: draft.date,
      weight: cleanWeight,
      weightUnit: unit,
      glucose: cleanGlucose,
      bp_sys: cleanBpSys,
      bp_dia: cleanBpDia,
      appetite: draft.appetite || null,
      energy: draft.energy || null,
      mood: draft.mood || null,
      sideEffects: draft.sideEffects,
      notes: draft.notes.trim(),
    };
    const next = [entry, ...entries.filter(e => e.date !== draft.date)]
      .sort((a, b) => b.date.localeCompare(a.date));
    setEntries(next);
    saveLog(next);
    setDraft(makeEmptyDraft());
    setSavedFlash(true);
    setTimeout(() => setSavedFlash(false), 1500);
  }

  const todayStr = window.isoDate(new Date());
  const todayEntry = entries.find(e => e.date === todayStr);
  const editingExisting = entries.some(e => e.date === draft.date);

  return (
    <div className="card card-pad quick-log-card">
      <div className="row-between" style={{ marginBottom: 18 }}>
        <div>
          <div className="label-mono">Daily log</div>
          <h2 className="serif" style={{ fontSize: 24, fontWeight: 400, margin: "6px 0 4px" }}>
            How are you feeling today?
          </h2>
          <div className="small muted">
            {editingExisting
              ? "Editing an existing entry — saving will replace it."
              : todayEntry
                ? "You've already logged today. Save again to overwrite."
                : "Every field is optional. Stored privately in your browser."}
          </div>
        </div>
        <div className="unit-toggle">
          <button className={unit === "lb" ? "on" : ""} onClick={() => setUnit("lb")}>lb</button>
          <button className={unit === "kg" ? "on" : ""} onClick={() => setUnit("kg")}>kg</button>
        </div>
      </div>

      <div className="stack-md">
        <div className="log-field">
          <label htmlFor="qlog-date">Date</label>
          <input id="qlog-date" type="date" className="input" value={draft.date} onChange={e => update({ date: e.target.value })} />
        </div>

        <div className="log-row-2">
          <div className="log-field">
            <label htmlFor="qlog-weight">Weight ({unit})</label>
            <input id="qlog-weight" type="number" step="0.1" className="input" placeholder={unit === "lb" ? "e.g. 184.2" : "e.g. 83.5"} value={draft.weight} onChange={e => update({ weight: e.target.value })} />
          </div>
          <div className="log-field">
            <label htmlFor="qlog-glucose">Fasting glucose (mg/dL)</label>
            <input id="qlog-glucose" type="number" step="1" className="input" placeholder="e.g. 102" value={draft.glucose} onChange={e => update({ glucose: e.target.value })} />
          </div>
        </div>

        <div className="log-field">
          <label>Blood pressure (mmHg)</label>
          <div className="log-row-2">
            <input type="number" className="input" placeholder="Systolic" value={draft.bp_sys} onChange={e => update({ bp_sys: e.target.value })} />
            <input type="number" className="input" placeholder="Diastolic" value={draft.bp_dia} onChange={e => update({ bp_dia: e.target.value })} />
          </div>
        </div>

        <div className="log-field">
          <label>Appetite</label>
          <ScaleChips kind="appetite" value={draft.appetite} onChange={v => update({ appetite: v })} />
        </div>

        <div className="log-field">
          <label>Energy</label>
          <ScaleChips kind="energy" value={draft.energy} onChange={v => update({ energy: v })} />
        </div>

        <div className="log-field">
          <label>Mood</label>
          <ScaleChips kind="mood" value={draft.mood} onChange={v => update({ mood: v })} />
        </div>

        <div className="log-field">
          <label>Side effects today</label>
          <SideEffectChips value={draft.sideEffects} onChange={v => update({ sideEffects: v })} />
        </div>

        <div className="log-field">
          <label htmlFor="qlog-notes">Notes</label>
          <textarea id="qlog-notes" className="log-textarea" placeholder="Anything else to remember — meals, sleep, the dose you took…" value={draft.notes} onChange={e => update({ notes: e.target.value })}></textarea>
        </div>

        <div className="row" style={{ marginTop: 4, gap: 12 }}>
          <button className="btn btn-primary" onClick={handleSave} disabled={!draft.date}>
            {savedFlash ? "✓ Saved" : "Save entry"}
          </button>
          <button className="btn btn-ghost" onClick={() => setDraft(makeEmptyDraft())}>Clear</button>
        </div>
      </div>
    </div>
  );
}

// ---------- Main DailyLog component ----------
function DailyLog() {
  const [entries, setEntries] = _useState(() => loadLog());
  const [page, setPage] = _useState(0);
  const PAGE_SIZE = 20;
  const [unit, setUnit] = _useState(() => {
    try { return localStorage.getItem(UNIT_STORAGE_KEY) || "lb"; }
    catch { return "lb"; }
  });

  // Keep in sync with quick-log saves + unit changes up top
  _useEffect(() => {
    const onLog = () => setEntries(loadLog());
    const onUnit = (e) => setUnit(e.detail || "lb");
    window.addEventListener("titrateplan-log-updated", onLog);
    window.addEventListener("titrateplan-unit-changed", onUnit);
    return () => {
      window.removeEventListener("titrateplan-log-updated", onLog);
      window.removeEventListener("titrateplan-unit-changed", onUnit);
    };
  }, []);

  function handleDelete(id) {
    const e = entries.find(x => x.id === id);
    const dateStr = e ? window.fmtDate(new Date(e.date + "T00:00:00")) : "this entry";
    if (!confirm(`Delete the entry for ${dateStr}? This can't be undone.`)) return;
    const next = entries.filter(x => x.id !== id);
    setEntries(next);
    saveLog(next);
  }

  function handlePrint() {
    const region = document.getElementById("print-region");
    if (region) {
      region.style.display = "block";
      // Move print-region to be a direct child of body so it survives `body > * { display: none }`
      if (region.parentNode !== document.body) document.body.appendChild(region);
    }
    const cleanup = () => {
      if (region) region.style.display = "none";
      window.removeEventListener("afterprint", cleanup);
    };
    window.addEventListener("afterprint", cleanup);
    setTimeout(() => window.print(), 50);
  }

  const hasAny = entries.length > 0;

  return (
    <>
      <div className="section-h" id="log">
        <h2>Daily log</h2>
        <span className="meta">{entries.length} {entries.length === 1 ? "entry" : "entries"} · stored in your browser</span>
      </div>

      {/* Charts + actions */}
      <div className="log-charts-row">
        <SparkCard
          label={`Weight (${unit})`}
          unit={unit}
          entries={entries.filter(e => !e.weightUnit || e.weightUnit === unit)}
          accessor={e => e.weight}
          color="var(--accent)"
          fmt={v => v.toFixed(1)}
        />
        <SparkCard
          label="Fasting glucose"
          unit="mg/dL"
          entries={entries}
          accessor={e => e.glucose}
          color="var(--maint)"
          fmt={v => Math.round(v)}
        />
        <SparkCard
          label="BP (systolic)"
          unit="mmHg"
          entries={entries}
          accessor={e => e.bp_sys}
          color="var(--warn)"
          fmt={v => Math.round(v)}
        />
        <SparkCard
          label="Appetite"
          unit="/ 5"
          entries={entries}
          accessor={e => e.appetite}
          color="var(--accent)"
          fmt={v => v.toFixed(0)}
        />
      </div>

      <div className="row no-print" style={{ flexWrap: "wrap", gap: 10, marginTop: 14 }}>
        <button className="btn btn-ghost" onClick={handlePrint} disabled={!hasAny} title="Use your browser's 'Save as PDF' option">
          Save as PDF
        </button>
        <button className="btn btn-ghost" onClick={() => exportCsv(entries, unit)} disabled={!hasAny}>
          Export CSV
        </button>
        <button
          className="btn btn-ghost"
          onClick={() => {
            const msg = hasAny
              ? "Replace your current entries with 90 days of realistic sample data? Your real entries will be lost."
              : "Load 90 days of realistic sample data?";
            if (confirm(msg)) {
              const sample = generateSampleEntries(90, unit);
              setEntries(sample);
              saveLog(sample);
            }
          }}
          title="Fills the log with 90 days of realistic mock data so you can see how the trend charts and PDF look with a full plan logged.">
          Load sample data
        </button>
      </div>

      {/* Entry list */}
      <div className="section-h" style={{ marginTop: 32 }}>
        <h2 style={{ fontSize: 22 }}>Recent entries</h2>
        <span className="meta" style={{ display: "flex", alignItems: "center", gap: 14 }}>
          {hasAny ? "Most recent first" : ""}
          {hasAny && (
            <button
              className="btn btn-link no-print"
              onClick={() => {
                if (confirm(`Delete every saved entry (${entries.length} total)? This cannot be undone.`)) {
                  setEntries([]); saveLog([]); setPage(0);
                }
              }}>
              Delete all
            </button>
          )}
        </span>
      </div>

      {!hasAny && (
        <div className="log-empty">
          No entries yet. Log your first one above — even just a weight is enough to start a trend line.
        </div>
      )}

      {hasAny && (() => {
        const totalPages = Math.max(1, Math.ceil(entries.length / PAGE_SIZE));
        const safePage = Math.min(page, totalPages - 1);
        const start = safePage * PAGE_SIZE;
        const pageEntries = entries.slice(start, start + PAGE_SIZE);
        return (
        <>
        <div className="log-entries">
          {pageEntries.map(e => {
            const d = new Date(e.date + "T00:00:00");
            return (
              <div key={e.id} className="log-entry">
                <div className="date-block">
                  {window.fmtDate(d)}
                  <div className="day">{window.DOW_NAMES[d.getDay()]}</div>
                </div>
                <div className="metric-block">
                  {e.weight != null && <div className="metric"><span className="lab">Wt</span>{e.weight}{e.weightUnit || unit}</div>}
                  {e.glucose != null && <div className="metric"><span className="lab">Glu</span>{e.glucose}</div>}
                  {e.bp_sys != null && e.bp_dia != null && <div className="metric"><span className="lab">BP</span>{e.bp_sys}/{e.bp_dia}</div>}
                  {e.appetite && <div className="metric"><span className="lab">App</span>{e.appetite}/5</div>}
                  {e.energy && <div className="metric"><span className="lab">Eng</span>{e.energy}/5</div>}
                  {e.mood && <div className="metric"><span className="lab">Mood</span>{e.mood}/5</div>}
                  {(e.sideEffects && e.sideEffects.length > 0) && (
                    <div className="se-list">⊘ {e.sideEffects.join(" · ")}</div>
                  )}
                  {e.notes && <div className="notes">"{e.notes}"</div>}
                </div>
                <div className="entry-actions">
                  <button
                    className="edit-btn"
                    onClick={() => {
                      window.dispatchEvent(new CustomEvent("titrateplan-log-edit", { detail: e }));
                    }}
                    aria-label="Edit entry"
                    title="Edit entry">✎</button>
                  <button className="del-btn" onClick={() => handleDelete(e.id)} aria-label="Delete entry" title="Delete entry">×</button>
                </div>
              </div>
            );
          })}
        </div>
        {totalPages > 1 && (
          <div className="pagination no-print">
            <button className="btn btn-ghost" onClick={() => setPage(0)} disabled={safePage === 0} aria-label="First page">«</button>
            <button className="btn btn-ghost" onClick={() => setPage(safePage - 1)} disabled={safePage === 0}>Previous</button>
            <span className="page-info">Page {safePage + 1} of {totalPages} · {entries.length} entries</span>
            <button className="btn btn-ghost" onClick={() => setPage(safePage + 1)} disabled={safePage >= totalPages - 1}>Next</button>
            <button className="btn btn-ghost" onClick={() => setPage(totalPages - 1)} disabled={safePage >= totalPages - 1} aria-label="Last page">»</button>
          </div>
        )}
        </>
        );
      })()}

      <PrintRegion entries={entries} weightUnit={unit} />
    </>
  );
}

Object.assign(window, { DailyLog, QuickLogCard });
