/* ============================================================
   PainTrack App — core: icons, mock data, chart helpers
   ============================================================ */
const { useState, useEffect, useRef, useMemo } = React;

/* ---------------- Icons ---------------- */
function Icon({ name, size = 20, stroke = 2, style, className }) {
  const P = {
    home:      <path d="M3 11l9-8 9 8M5 10v10h5v-6h4v6h5V10" strokeLinejoin="round" strokeLinecap="round" />,
    pulse:     <path d="M3 12h4l2-6 4 12 2-6h6" strokeLinejoin="round" strokeLinecap="round" />,
    timeline:  <path d="M4 5v14M4 8h6m-6 8h10M4 12h14" strokeLinecap="round" />,
    book:      <path d="M4 5a2 2 0 0 1 2-2h12v16H6a2 2 0 0 0-2 2zM18 3v16" strokeLinejoin="round" strokeLinecap="round" />,
    user:      <path d="M4 20a8 8 0 0 1 16 0M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" strokeLinejoin="round" strokeLinecap="round" />,
    heart:     <path d="M12 21s-7-4.5-9-9a5 5 0 0 1 9-3 5 5 0 0 1 9 3c-2 4.5-9 9-9 9z" strokeLinejoin="round" />,
    moon:      <path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z" strokeLinejoin="round" />,
    walk:      <path d="M12 5a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0 3v6m0 0l-3 6m3-6l3 6M7 11l5 1 5-1" strokeLinecap="round" strokeLinejoin="round" />,
    pill:      <path d="M3 9h18v6H3zM9 9v6" strokeLinejoin="round" />,
    check:     <path d="M5 13l4 4L19 7" strokeLinecap="round" strokeLinejoin="round" />,
    arrowR:    <path d="M5 12h14M13 6l6 6-6 6" strokeLinecap="round" strokeLinejoin="round" />,
    arrowL:    <path d="M19 12H5M11 18l-6-6 6-6" strokeLinecap="round" strokeLinejoin="round" />,
    bell:      <path d="M6 9a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6M10 20a2 2 0 0 0 4 0" strokeLinejoin="round" strokeLinecap="round" />,
    chart:     <path d="M3 17l5-5 4 3 6-7M16 8h4v4" strokeLinecap="round" strokeLinejoin="round" />,
    flag:      <path d="M5 21V4m0 0h11l-2 4 2 4H5" strokeLinejoin="round" strokeLinecap="round" />,
    alert:     <path d="M12 9v4m0 4h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z" strokeLinejoin="round" strokeLinecap="round" />,
    clock:     <g><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" strokeLinecap="round" /></g>,
    shield:    <path d="M12 3l7 3v6c0 5-3.5 7.5-7 9-3.5-1.5-7-4-7-9V6l7-3z" strokeLinejoin="round" />,
    search:    <g><circle cx="11" cy="11" r="7" /><path d="M21 21l-4-4" strokeLinecap="round" /></g>,
    play:      <path d="M7 5v14l11-7z" strokeLinejoin="round" />,
    logout:    <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9" strokeLinecap="round" strokeLinejoin="round" />,
    plus:      <path d="M12 5v14M5 12h14" strokeLinecap="round" />,
    sparkle:   <path d="M12 3v3m0 12v3m9-9h-3M6 12H3m13.5-6.5L14 8M8 16l-2.5 2.5m13 0L16 16M8 8 5.5 5.5" strokeLinecap="round" />,
    chevR:     <path d="M9 6l6 6-6 6" strokeLinecap="round" strokeLinejoin="round" />,
    dots:      <g><circle cx="5" cy="12" r="1.6" /><circle cx="12" cy="12" r="1.6" /><circle cx="19" cy="12" r="1.6" /></g>,
    calendar:  <g><rect x="3" y="5" width="18" height="16" rx="2" /><path d="M3 9h18M8 3v4m8-4v4" strokeLinecap="round" /></g>,
    brain:     <path d="M12 4a3 3 0 0 0-3 3 3 3 0 0 0 0 6 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0 0-6 3 3 0 0 0-3-3zM12 4v12" strokeLinejoin="round" />,
    dumbbell:  <path d="M4 20v-6a8 8 0 0 1 16 0v6M8 20v-5m8 5v-5" strokeLinecap="round" />,
    needle:    <path d="M12 2v6m0 0a4 4 0 0 0 4 4m-4-4a4 4 0 0 1-4 4m8 0v3a4 4 0 0 1-8 0v-3" strokeLinecap="round" />,
    download:  <path d="M12 3v12m0 0l-4-4m4 4l4-4M4 21h16" strokeLinecap="round" strokeLinejoin="round" />,
    eye:       <g><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12z" strokeLinejoin="round" /><circle cx="12" cy="12" r="3" /></g>,
    lock:      <g><rect x="5" y="11" width="14" height="9" rx="2" /><path d="M8 11V8a4 4 0 0 1 8 0v3" strokeLinecap="round" /></g>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth={stroke} style={style} className={className} aria-hidden="true">
      {P[name] || null}
    </svg>
  );
}

/* ---------------- Brand mark ---------------- */
function Logo({ size = 30 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 30 30" fill="none" aria-hidden="true">
      <rect width="30" height="30" rx="8" fill="#11705C" />
      <path d="M5 19 C9 19 9 9 13 9 C16 9 16 15 19 15 C22 15 23 11 25 11" stroke="#fff" strokeWidth="2.4" strokeLinecap="round" fill="none" />
      <circle cx="13" cy="9" r="2.4" fill="#D75A3E" stroke="#11705C" strokeWidth="1.4" />
    </svg>
  );
}

/* ---------------- Full brand lockup (raster logo) ---------------- */
// Horizontal PainTrack lockup (figure + wordmark + tagline). Transparent PNG;
// `h` sets the rendered height in px, width scales automatically.
function Brand({ h = 30, className = "" }) {
  return (
    <img
      src="assets/paintrack-logo.png"
      alt="PainTrack"
      className={"pt-logo" + (className ? " " + className : "")}
      style={{ height: h + "px", width: "auto", display: "block" }}
    />
  );
}

/* ---------------- Chart helpers ---------------- */
// Build a smooth-ish path from {x,y} arrays inside a box.
function smoothPath(pts) {
  if (pts.length < 2) return "";
  let d = `M${pts[0].x},${pts[0].y}`;
  for (let i = 1; i < pts.length; i++) {
    const p0 = pts[i - 1], p1 = pts[i];
    const cx = (p0.x + p1.x) / 2;
    d += ` C${cx},${p0.y} ${cx},${p1.y} ${p1.x},${p1.y}`;
  }
  return d;
}
function painColor(v) {
  if (v >= 7) return "#D75A3E";
  if (v >= 4) return "#C9952E";
  return "#2BA17E";
}

// series: array of {day, pain}. procedureDay: x marker. width/height in px viewBox.
function ReliefChart({ series, procedureDay = 0, w = 520, h = 230, showBand = true, retreatDay = null }) {
  const padL = 34, padR = 16, padT = 16, padB = 26;
  const maxDay = Math.max(...series.map(s => s.day), 1);
  const X = d => padL + (d / maxDay) * (w - padL - padR);
  const Y = p => padT + (1 - p / 10) * (h - padT - padB);
  const pts = series.map(s => ({ x: X(s.day), y: Y(s.pain) }));
  const line = smoothPath(pts);
  const area = line + ` L${pts[pts.length - 1].x},${h - padB} L${pts[0].x},${h - padB} Z`;
  const gid = "rg" + Math.round(procedureDay * 97 + maxDay);
  return (
    <svg viewBox={`0 0 ${w} ${h}`} className="chart-svg" role="img" aria-label="Relief curve">
      {[0, 2.5, 5, 7.5, 10].map((v, i) => (
        <line key={i} x1={padL} x2={w - padR} y1={Y(v)} y2={Y(v)} stroke="#EEE8DC" strokeWidth="1" />
      ))}
      {[0, 5, 10].map((v, i) => (
        <text key={"t" + i} x={padL - 8} y={Y(v) + 3} textAnchor="end"
              fontFamily="IBM Plex Mono" fontSize="10" fill="#A39A88">{v}</text>
      ))}
      {showBand && procedureDay != null && (
        <rect x={X(procedureDay)} y={padT} width={(retreatDay ? X(retreatDay) : w - padR) - X(procedureDay)}
              height={h - padT - padB} fill="rgba(17,112,92,0.05)" />
      )}
      {retreatDay && (
        <rect x={X(retreatDay)} y={padT} width={w - padR - X(retreatDay)} height={h - padT - padB}
              fill="rgba(197,138,46,0.08)" />
      )}
      {procedureDay != null && (
        <line x1={X(procedureDay)} x2={X(procedureDay)} y1={padT} y2={h - padB}
              stroke="#D75A3E" strokeWidth="1.4" strokeDasharray="4 4" />
      )}
      <path d={area} fill={`url(#${gid})`} opacity="0.5" />
      <path d={line} fill="none" stroke={`url(#${gid}line)`} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
      {series.map((s, i) => (i % Math.ceil(series.length / 7) === 0 || i === series.length - 1) && (
        <circle key={"d" + i} cx={pts[i].x} cy={pts[i].y} r="3.5" fill="#fff" stroke={painColor(s.pain)} strokeWidth="2.4" />
      ))}
      <defs>
        <linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="rgba(17,112,92,0.22)" />
          <stop offset="100%" stopColor="rgba(17,112,92,0)" />
        </linearGradient>
        <linearGradient id={gid + "line"} x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stopColor="#D75A3E" />
          <stop offset="40%" stopColor="#2BA17E" />
          <stop offset="70%" stopColor="#11705C" />
          <stop offset="100%" stopColor="#C58A2E" />
        </linearGradient>
      </defs>
    </svg>
  );
}

// tiny sparkline from array of numbers (pain 0-10)
function Spark({ data, w = 96, h = 30, color = "#11705C" }) {
  const max = 10;
  const pts = data.map((v, i) => ({
    x: 2 + (i / (data.length - 1)) * (w - 4),
    y: 3 + (1 - v / max) * (h - 6),
  }));
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} aria-hidden="true">
      <polyline points={pts.map(p => `${p.x},${p.y}`).join(" ")} fill="none"
                stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

/* ---------------- Mock data ---------------- */
// weekly pain readings; procedure anchored
function curve(start, points) {
  return points.map((pain, i) => ({ day: i * 7, pain }));
}

const PATIENTS = [
  {
    id: "okonkwo", name: "Maya Okonkwo", first: "Maya", initials: "MO", age: 64,
    condition: "Lumbar RFA · L4–L5", proc: { type: "Radiofrequency ablation", level: "L4–L5", date: "Dec 2, 2025", day: 14 },
    status: "responding", adherence: 92, last: "2h ago", meds: "None", phone: "patient",
    series: curve(0, [8, 8, 7, 3, 1, 1, 1, 2, 1, 2, 2, 3, 3, 4]),
    retreatDay: 98,
    summary: "Strong responder. Pain fell from 8 to 1 within 11 days of L4–L5 RFA and has held at 1–2/10 for 6 months. Adherence 92%, no medication escalation. Relief curve consistent with durable benefit; next re-treatment window forecast ~Q1.",
  },
  {
    id: "delgado", name: "Rafael Delgado", first: "Rafael", initials: "RD", age: 51,
    condition: "Facet injection · cervical", proc: { type: "Facet injection", level: "Cervical", date: "Jan 18, 2026", day: 0 },
    status: "nonresponder", adherence: 74, last: "1d ago", meds: "Naproxen",
    series: curve(0, [7, 7, 6, 7, 6, 7, 6, 7, 6, 6]),
    retreatDay: null,
    summary: "Limited response. Cervical facet injection produced no meaningful change — pain steady at 6–7/10 across 21 days, onset never detected. Consider diagnostic medial branch block before repeating. Flagged for case review.",
  },
  {
    id: "bauer", name: "Lena Bauer", first: "Lena", initials: "LB", age: 58,
    condition: "Lumbar RFA · L3–L4", proc: { type: "Radiofrequency ablation", level: "L3–L4", date: "Jun 30, 2025", day: 0 },
    status: "retreat", adherence: 88, last: "5h ago", meds: "None",
    series: curve(0, [8, 2, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6]),
    retreatDay: 56,
    summary: "Relief fading — re-treatment due. Excellent benefit for ~7 months; pain now climbing from 2 back toward 6/10 over the last 5 weeks. Curve shape matches prior RFA. Recommend booking repeat RFA within the forecast window.",
  },
  {
    id: "nilsson", name: "Anders Nilsson", first: "Anders", initials: "AN", age: 47,
    condition: "Epidural · L5–S1", proc: { type: "Transforaminal epidural", level: "L5–S1", date: "Jan 5, 2026", day: 7 },
    status: "responding", adherence: 88, last: "3h ago", meds: "Gabapentin",
    series: curve(0, [7, 6, 2, 2, 3, 2, 3, 3, 3]),
    retreatDay: null,
    summary: "Responding, early plateau. Transforaminal epidural cut radicular pain from 7 to 2 within a week. Holding at 2–3/10. Adherence 88%. Continue physio; re-assess durability at the 8-week check-in.",
  },
  {
    id: "haddad", name: "Sara Haddad", first: "Sara", initials: "SH", age: 62,
    condition: "Medial branch block", proc: { type: "Medial branch block", level: "L4–L5", date: "Jan 22, 2026", day: 0 },
    status: "nonresponder", adherence: 69, last: "6d ago", meds: "Acetaminophen",
    series: curve(0, [6, 6, 5, 6, 6, 5, 6]),
    retreatDay: null,
    summary: "Diagnostic block negative. <50% relief reported after medial branch block — does not meet threshold for RFA candidacy. Pain unchanged at 6/10. Revisit diagnosis; consider alternate pain generator.",
  },
];

const STATUS_META = {
  responding:  { label: "Responding",    cls: "good",  dot: "#11705C" },
  retreat:     { label: "Re-treat due",  cls: "watch", dot: "#C58A2E" },
  nonresponder:{ label: "Non-responder", cls: "flag",  dot: "#D75A3E" },
};

const BODY_REGIONS = [
  { id: "neck", label: "Head / neck", d: null, cx: 60, cy: 20, r: 15 },
  { id: "shoulders", label: "Shoulders", x: 30, y: 42, w: 60, h: 16 },
  { id: "midback", label: "Mid back", x: 34, y: 60, w: 52, h: 36 },
  { id: "lowback", label: "Lower back", x: 34, y: 98, w: 52, h: 34 },
  { id: "lhip", label: "Left hip", x: 30, y: 134, w: 26, h: 22 },
  { id: "rhip", label: "Right hip", x: 64, y: 134, w: 26, h: 22 },
  { id: "lknee", label: "Left knee", x: 34, y: 178, w: 22, h: 20 },
  { id: "rknee", label: "Right knee", x: 64, y: 178, w: 22, h: 20 },
];

const EDUCATION = [
  { tag: "Procedure", title: "What is radiofrequency ablation?", desc: "How RFA quiets the nerves carrying your pain signal — and why relief takes a couple of weeks to arrive.", meta: "4 min read", grad: "linear-gradient(135deg,#E2EFE9,#C9E2D6)", dot: "#11705C", body: "Radiofrequency ablation (RFA) uses heat from a precise radio-wave current to interrupt the small medial-branch nerves that carry pain signals from arthritic facet joints. It does not damage muscle or the spinal cord. Because the nerve is quieted rather than removed, you may notice relief build gradually over 1–3 weeks rather than immediately. Most people feel mild soreness at the needle sites for a few days. Relief commonly lasts 6–12 months; nerves can slowly regrow, which is why your relief curve helps your team time any repeat." },
  { tag: "After care", title: "What to expect after an epidural", desc: "The normal timeline of soreness, onset and relief — so day-three discomfort doesn't feel like failure.", meta: "3 min read", grad: "linear-gradient(135deg,#F6E2DA,#EFCBBC)", dot: "#D75A3E", body: "After a transforaminal epidural steroid injection, it is normal to feel a temporary flare for 24–72 hours before the steroid takes effect. Onset of relief typically begins between day 2 and day 7. Keep logging daily — a brief rise before the dip is expected and tells your clinician the medication is settling in. Call the clinic for fever, severe headache, or new weakness." },
  { tag: "Living with pain", title: "Why tracking beats remembering", desc: "The science of recall bias in chronic pain, and how 30 seconds a day changes your next appointment.", meta: "5 min read", grad: "linear-gradient(135deg,#F3E7CF,#E8D2A6)", dot: "#C58A2E", body: "Human memory compresses weeks of fluctuating pain into a single fuzzy impression, heavily weighted toward how you feel right now. That recall bias makes it hard to judge whether a procedure truly worked. A 30-second daily check-in captures the real shape of your relief — when it started, how deep it went, and when it began to return — so decisions about repeat treatment rest on evidence, not guesswork." },
];

Object.assign(window, { React, useState, useEffect, useRef, useMemo, Icon, Logo, Brand, ReliefChart, Spark, smoothPath, painColor, PATIENTS, STATUS_META, BODY_REGIONS, EDUCATION });
