/* ── Anatomy SVG ──────────────────────────────────────────────────── */
/* Side profile, facing left. ViewBox 360 × 640. Hip pivot (180, 390). */

const HIP = { x: 180, y: 390 };

/* Helper: rotate a point around hip pivot by angle (deg) */
function rot(x, y, deg, cx = HIP.x, cy = HIP.y) {
  const r = (deg * Math.PI) / 180;
  const dx = x - cx, dy = y - cy;
  return { x: cx + dx * Math.cos(r) - dy * Math.sin(r),
           y: cy + dx * Math.sin(r) + dy * Math.cos(r) };
}

/* Lumbar spine path: morphs from gentle to hyperlordotic */
function lumbarPath(curveK) {
  // start at sacrum top, end at T12. Anterior = lower x (left)
  const x0 = 178, y0 = 380;
  const x1 = 175, y1 = 195;
  const cxA = 178 - 22 * curveK;   // mid anterior bow
  const cyA = 320;
  const cxB = 178 - 18 * curveK;
  const cyB = 240;
  return `M ${x0} ${y0} C ${cxA} ${cyA}, ${cxB} ${cyB}, ${x1} ${y1}`;
}

/* Vertebrae positions sampled along the lumbar curve */
function lumbarVerts(curveK) {
  const offset = 22 * curveK;
  return [
    { x: 175,         y: 200, label: 'L1' },
    { x: 175 - offset*0.55, y: 240, label: 'L2' },
    { x: 175 - offset*0.95, y: 280, label: 'L3' },
    { x: 175 - offset*0.85, y: 320, label: 'L4' },
    { x: 175 - offset*0.45, y: 358, label: 'L5' }
  ];
}

/* Pelvis profile (innominate side view), drawn around hip joint (180,390).
   This entire group rotates by the tilt angle. */
function PelvisGroup({ tilt, highlight }) {
  return (
    <g style={{ transform: `rotate(${tilt}deg)`, transformOrigin: `${HIP.x}px ${HIP.y}px`, transition: 'transform .9s cubic-bezier(.4,.1,.2,1)' }}>
      {/* Iliac wing — large flat bone */}
      <path d="
        M 178 380
        C 165 360 145 350 130 358
        C 120 322 130 285 175 270
        C 215 270 235 305 232 345
        C 232 370 210 380 195 384
        Z"
        fill="var(--bone)" stroke="var(--bone-deep)" strokeWidth="1.5" strokeLinejoin="round" />
      {/* iliac crest highlight */}
      <path d="M 130 358 C 145 295 195 268 232 308" fill="none" stroke="var(--bone-deep)" strokeWidth="1.2" opacity=".75"/>
      {/* Pubic ramus */}
      <path d="M 178 392 C 168 408 150 416 138 414 C 130 412 132 422 142 426 L 168 422 C 178 418 182 408 182 398 Z"
        fill="var(--bone)" stroke="var(--bone-deep)" strokeWidth="1.4" strokeLinejoin="round"/>
      {/* Ischium */}
      <path d="M 192 398 C 210 410 215 432 205 444 C 195 446 188 432 188 418 Z"
        fill="var(--bone)" stroke="var(--bone-deep)" strokeWidth="1.4" strokeLinejoin="round"/>
      {/* Acetabulum hint */}
      <circle cx={HIP.x} cy={HIP.y} r="9" fill="none" stroke="var(--bone-deep)" strokeWidth="1.2" opacity=".7"/>
      {/* ASIS marker — anterior superior iliac spine */}
      <circle cx="130" cy="358" r="3.2" fill="var(--rust)" />
      {/* PSIS marker — posterior superior iliac spine */}
      <circle cx="232" cy="308" r="3.2" fill="var(--plum)" />
      {/* Labels (rotate-counter so they read upright? leave rotated for now, with tilt small) */}
      <g fontFamily="JetBrains Mono, monospace" fontSize="9" fontWeight="500">
        <text x="108" y="356" textAnchor="end" fill="var(--rust)">ASIS</text>
        <text x="240" y="304" fill="var(--plum)">PSIS</text>
      </g>
    </g>
  );
}

/* Femur — fixed (vertical) under hip joint; doesn't rotate with pelvis */
function Femur() {
  return (
    <g>
      {/* head + neck */}
      <circle cx={HIP.x} cy={HIP.y} r="11" fill="var(--bone)" stroke="var(--bone-deep)" strokeWidth="1.5"/>
      {/* greater trochanter */}
      <path d="M 195 396 C 210 398 218 408 215 418 C 210 422 198 416 192 408 Z"
        fill="var(--bone)" stroke="var(--bone-deep)" strokeWidth="1.3"/>
      {/* shaft */}
      <path d="M 178 398 C 178 460 184 530 188 620 L 200 620 C 198 530 196 460 198 405 Z"
        fill="var(--bone)" stroke="var(--bone-deep)" strokeWidth="1.4" strokeLinejoin="round"/>
    </g>
  );
}

/* Vertebrae stack — drawn from interpolated positions */
function Spine({ curveK }) {
  const verts = lumbarVerts(curveK);
  return (
    <g>
      {/* sacrum (rotates with pelvis but drawn fixed-ish here for simplicity) */}
      <path d={`M 176 378 L 198 388 L 200 412 L 178 405 Z`}
        fill="var(--bone)" stroke="var(--bone-deep)" strokeWidth="1.4" strokeLinejoin="round"/>
      {/* spinal ligament line (curve) */}
      <path d={lumbarPath(curveK)} fill="none" stroke="var(--bone-deep)" strokeWidth="1" opacity=".4"
        style={{ transition: 'd .9s' }}/>
      {/* vertebrae */}
      {verts.map((v, i) => (
        <g key={i} style={{ transition: 'transform .9s cubic-bezier(.4,.1,.2,1)' }}>
          <rect x={v.x - 11} y={v.y - 7} width="22" height="14" rx="3"
            fill="var(--bone)" stroke="var(--bone-deep)" strokeWidth="1.2"
            style={{ transition: 'all .9s' }}/>
          {/* spinous process (back-pointing) */}
          <path d={`M ${v.x + 11} ${v.y} L ${v.x + 22} ${v.y - 2} L ${v.x + 22} ${v.y + 2} Z`}
            fill="var(--bone-deep)" opacity=".7"/>
          {/* label */}
          <text x={v.x - 26} y={v.y + 3} fontFamily="JetBrains Mono, monospace" fontSize="8"
            fill="var(--muted)" textAnchor="end">{v.label}</text>
        </g>
      ))}
      {/* T12 stub above */}
      <rect x={164} y={185} width="22" height="12" rx="3"
        fill="var(--bone)" stroke="var(--bone-deep)" strokeWidth="1.1" opacity=".7"/>
    </g>
  );
}

/* ── Muscles ──────────────────────────────────────────────────────── */
/* Each muscle is a thick stroked path. Color/glow depend on its current state. */

function muscleStyleProps(stateName) {
  const s = STATE_STYLE[stateName] || STATE_STYLE.neutral;
  return {
    fill: s.fill,
    glow: s.glow,
    ring: s.ring
  };
}

function MuscleBand({ id, d, stateName, width=14, selected, onClick }) {
  const { fill, glow, ring } = muscleStyleProps(stateName);
  const animation = glow !== 'none' ? `${glow} 1.6s ease-in-out infinite` : 'none';
  return (
    <g onClick={onClick} style={{ cursor: 'pointer' }}>
      {/* fat invisible hit area */}
      <path d={d} stroke="transparent" strokeWidth={width + 18} fill="none"/>
      {/* outer ring (selection) */}
      {selected && <path d={d} stroke={ring} strokeWidth={width + 8} fill="none" strokeLinecap="round" opacity=".55"/>}
      {/* main muscle band */}
      <path d={d}
        stroke={fill}
        strokeWidth={width}
        strokeLinecap="round"
        strokeLinejoin="round"
        fill="none"
        style={{ transition: 'stroke .6s, d .9s', animation }}/>
      {/* striations: thin lighter line */}
      <path d={d} stroke="rgba(255,255,255,.18)" strokeWidth={width * 0.35}
        strokeLinecap="round" fill="none"/>
    </g>
  );
}

/* Compute muscle paths given current pelvis tilt and lumbar curvature */
function buildMusclePaths(tilt, curveK) {
  // Static origins on spine (interpolate by curve)
  const verts = lumbarVerts(curveK);
  const L2 = verts[1], L4 = verts[3];

  // Pelvis-bound attachment points (rotate with pelvis)
  const asisRaw = { x: 130, y: 358 };
  const psisRaw = { x: 232, y: 308 };
  const iliacCrestPostRaw = { x: 222, y: 285 };
  const iliacCrestAntRaw = { x: 152, y: 282 };
  const aiisRaw = { x: 138, y: 372 };
  const ischialRaw = { x: 200, y: 442 };
  const pubicRaw = { x: 142, y: 425 };

  const asis = rot(asisRaw.x, asisRaw.y, tilt);
  const psis = rot(psisRaw.x, psisRaw.y, tilt);
  const iliacP = rot(iliacCrestPostRaw.x, iliacCrestPostRaw.y, tilt);
  const iliacA = rot(iliacCrestAntRaw.x, iliacCrestAntRaw.y, tilt);
  const aiis = rot(aiisRaw.x, aiisRaw.y, tilt);
  const ischial = rot(ischialRaw.x, ischialRaw.y, tilt);
  const pubic = rot(pubicRaw.x, pubicRaw.y, tilt);

  // Femur attachment (fixed, doesn't rotate)
  const lesserTroch = { x: 192, y: 412 };
  const itBand = { x: 200, y: 470 };
  const tibia = { x: 192, y: 615 };
  const patella = { x: 175, y: 600 };
  const ribs = { x: 170, y: 175 };

  return {
    iliopsoas: `M ${L2.x} ${L2.y} Q ${(L4.x+asis.x)/2 - 4} ${(L4.y+360)/2} ${asis.x + 22} ${asis.y + 18} T ${lesserTroch.x} ${lesserTroch.y}`,
    rectusFemoris: `M ${aiis.x - 2} ${aiis.y + 4} Q ${175} ${500} ${patella.x} ${patella.y}`,
    erectorSpinae: `M ${iliacP.x - 4} ${iliacP.y + 8} C ${iliacP.x + 6} ${320} ${190} ${250} ${182} ${ribs.y}`,
    glutes: `M ${iliacP.x} ${iliacP.y + 4} C ${iliacP.x + 18} ${360} ${230} ${440} ${itBand.x + 18} ${itBand.y}`,
    abs: `M ${pubic.x - 4} ${pubic.y - 18} C ${145} ${300} ${150} ${230} ${ribs.x - 18} ${ribs.y + 10}`,
    hamstrings: `M ${ischial.x + 2} ${ischial.y - 4} Q ${210} ${520} ${tibia.x + 6} ${tibia.y}`,
  };
}

/* Force-vector arrow overlay per muscle (only shows in tilted/compensated state) */
function ForceArrow({ from, to, color, animate }) {
  const dx = to.x - from.x, dy = to.y - from.y;
  const len = Math.hypot(dx, dy);
  const ux = dx / len, uy = dy / len;
  // arrow head
  const hx = to.x, hy = to.y;
  const px = -uy, py = ux; // perpendicular
  const a1x = hx - ux*8 + px*4, a1y = hy - uy*8 + py*4;
  const a2x = hx - ux*8 - px*4, a2y = hy - uy*8 - py*4;
  return (
    <g style={{ pointerEvents: 'none' }}>
      <line x1={from.x} y1={from.y} x2={hx - ux*4} y2={hy - uy*4}
        stroke={color} strokeWidth="1.6" strokeDasharray="3 4"
        style={{ animation: animate ? 'flow 1.4s linear infinite' : 'none' }}/>
      <polygon points={`${hx},${hy} ${a1x},${a1y} ${a2x},${a2y}`} fill={color}/>
    </g>
  );
}

/* Background body silhouette — soft tan blob */
function BodySilhouette({ tilt, curveK }) {
  const offset = 22 * curveK;
  // Front of trunk anterior bow follows lumbar
  return (
    <path d={`
      M 142 130
      C 110 180 ${108 - offset*0.3} 280 ${122 - offset*0.4} 360
      C ${118 - offset*0.2} 380 124 405 138 420
      C 130 470 130 540 142 625
      L 232 625
      C 240 530 240 470 235 425
      C 252 410 260 375 256 340
      C 262 280 260 200 240 145
      C 232 128 220 122 200 122
      L 165 122 Z
    `}
      fill="var(--paper-2)"
      stroke="var(--line)"
      strokeWidth="1"
      style={{ transition: 'd .9s' }}
    />
  );
}

/* The full anatomy figure */
function AnatomyFigure({ phase, selected, onSelect }) {
  // Side profile faces LEFT (anterior = low x). Anterior pelvic tilt = ASIS goes
  // forward+down, PSIS goes back+up → in SVG (Y-down) that's a COUNTER-CLOCKWISE
  // rotation around the hip pivot, i.e. a NEGATIVE rotation angle.
  const tilt = phase === 'normal' ? -4 : -16;      // rotation degrees (negative = anterior tilt)
  const curveK = phase === 'normal' ? 1.0 : 1.65;  // lumbar lordosis multiplier
  const paths = buildMusclePaths(tilt, curveK);

  // Force arrows per phase
  const showForce = phase !== 'normal';
  const compMode = phase === 'compensated';

  return (
    <svg viewBox="0 0 360 660" width="100%" style={{ display: 'block' }}>
      {/* paper grid */}
      <defs>
        <pattern id="dotgrid" width="14" height="14" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r="0.6" fill="rgba(140,123,98,.18)"/>
        </pattern>
        <linearGradient id="paperFade" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor="rgba(255,251,240,0)"/>
          <stop offset="1" stopColor="rgba(255,251,240,.9)"/>
        </linearGradient>
      </defs>
      <rect x="0" y="0" width="360" height="660" fill="url(#dotgrid)" opacity=".55"/>

      {/* Silhouette layer */}
      <BodySilhouette tilt={tilt} curveK={curveK}/>

      {/* Skeleton */}
      <Femur/>
      <Spine curveK={curveK}/>
      <PelvisGroup tilt={tilt}/>

      {/* Muscle bands — back muscles drawn behind front for layering */}
      <g style={{ transition: 'all .6s' }}>
        <MuscleBand id="erectorSpinae" d={paths.erectorSpinae} width="14"
          stateName={MUSCLES.erectorSpinae.states[phase]}
          selected={selected === 'erectorSpinae'}
          onClick={() => onSelect('erectorSpinae')}/>
        <MuscleBand id="glutes" d={paths.glutes} width="22"
          stateName={MUSCLES.glutes.states[phase]}
          selected={selected === 'glutes'}
          onClick={() => onSelect('glutes')}/>
        <MuscleBand id="hamstrings" d={paths.hamstrings} width="16"
          stateName={MUSCLES.hamstrings.states[phase]}
          selected={selected === 'hamstrings'}
          onClick={() => onSelect('hamstrings')}/>
        <MuscleBand id="iliopsoas" d={paths.iliopsoas} width="14"
          stateName={MUSCLES.iliopsoas.states[phase]}
          selected={selected === 'iliopsoas'}
          onClick={() => onSelect('iliopsoas')}/>
        <MuscleBand id="rectusFemoris" d={paths.rectusFemoris} width="14"
          stateName={MUSCLES.rectusFemoris.states[phase]}
          selected={selected === 'rectusFemoris'}
          onClick={() => onSelect('rectusFemoris')}/>
        <MuscleBand id="abs" d={paths.abs} width="13"
          stateName={MUSCLES.abs.states[phase]}
          selected={selected === 'abs'}
          onClick={() => onSelect('abs')}/>
      </g>

      {/* Force-line overlays */}
      {showForce && (
        <g>
          {/* Iliopsoas pulls ASIS forward-down — ASIS in tilted state ≈ (123, 373) */}
          <ForceArrow
            from={{ x: 160, y: 340 }} to={{ x: 122, y: 376 }}
            color="var(--rust-deep)" animate={true}/>
          {/* Rectus femoris pulls AIIS down toward thigh */}
          <ForceArrow
            from={{ x: 132, y: 380 }} to={{ x: 138, y: 412 }}
            color="var(--rust-deep)" animate={true}/>
          {/* Compensation: erector spinae pulls upper trunk back-up */}
          {compMode && (
            <ForceArrow
              from={{ x: 222, y: 280 }} to={{ x: 218, y: 215 }}
              color="var(--rust-deep)" animate={true}/>
          )}
          {/* Inhibition glutes — PSIS in tilted state moved up to ~(207,297), gluteal mass behind */}
          {compMode && (
            <g transform="translate(258, 380)">
              <circle r="11" fill="var(--paper)" stroke="var(--slate)" strokeWidth="1.6"/>
              <path d="M -5 -5 L 5 5 M 5 -5 L -5 5" stroke="var(--slate-deep)" strokeWidth="2" strokeLinecap="round"/>
            </g>
          )}
          {compMode && (
            <g transform="translate(96, 340)">
              <circle r="11" fill="var(--paper)" stroke="var(--slate)" strokeWidth="1.6"/>
              <path d="M -5 -5 L 5 5 M 5 -5 L -5 5" stroke="var(--slate-deep)" strokeWidth="2" strokeLinecap="round"/>
            </g>
          )}
        </g>
      )}

      {/* Direction labels */}
      <g fontFamily="Newsreader, serif" fontSize="10" fontStyle="italic" fill="var(--muted)">
        <text x="20" y="142">前 / Anterior</text>
        <text x="295" y="142">后 / Posterior</text>
      </g>

      {/* Tilt angle wedge — visualizes ASIS-PSIS angle */}
      <TiltAngleWedge tilt={tilt} displayDeg={Math.abs(tilt)}/>

      {/* Muscle name + status labels (drawn last so they sit on top) */}
      <MuscleLabels phase={phase} selected={selected} onSelect={onSelect}/>
    </svg>
  );
}

/* Tilt-angle wedge — shows the angle between the horizontal and the ASIS-PSIS line */
function TiltAngleWedge({ tilt, displayDeg }) {
  // ASIS rotated, PSIS rotated; draw a small ghost showing horizontal reference
  const asis = rot(130, 358, tilt);
  const psis = rot(232, 308, tilt);
  const midX = (asis.x + psis.x) / 2;
  const midY = (asis.y + psis.y) / 2;
  return (
    <g style={{ pointerEvents: 'none' }}>
      {/* Horizontal reference (dashed) */}
      <line x1={midX - 70} y1={midY + 20} x2={midX + 70} y2={midY + 20}
        stroke="var(--muted)" strokeWidth="1" strokeDasharray="3 3" opacity=".55"/>
      {/* ASIS-PSIS line */}
      <line x1={asis.x} y1={asis.y} x2={psis.x} y2={psis.y}
        stroke="var(--ink-2)" strokeWidth="1.4" strokeDasharray="4 3" opacity=".7"
        style={{ transition: 'all .9s' }}/>
      {/* Angle label */}
      <g transform={`translate(${midX + 80}, ${midY + 25})`}>
        <rect x="-32" y="-13" width="64" height="22" rx="4" fill="var(--ink)"/>
        <text x="0" y="2" fontFamily="JetBrains Mono, monospace" fontSize="11" fontWeight="700"
          fill="var(--paper)" textAnchor="middle">
          {Math.round(displayDeg)}°
        </text>
      </g>
    </g>
  );
}

/* ── Muscle labels overlay ──────────────────────────────────────── */
/* Always show muscle name; in non-neutral states show status badge
   (紧张 / 代偿 / 弱化 / 拉长). Clicking the label selects that muscle. */

const STATUS_LABEL = {
  tight:        { cn: '紧张',   en: 'TIGHT' },
  overworking:  { cn: '代偿',   en: 'OVER' },
  weak:         { cn: '弱化',   en: 'WEAK' },
  lengthened:   { cn: '拉长',   en: 'LENG' },
  neutral:      null
};

function MuscleLabels({ phase, selected, onSelect }) {
  // anchor = small dot landing on the muscle band
  // label side / position chosen to avoid overlap
  const labels = [
    { id: 'abs',           side: 'L', lx: 88,  ly: 240, ax: 142, ay: 268 },
    { id: 'iliopsoas',     side: 'L', lx: 88,  ly: 348, ax: 152, ay: 358 },
    { id: 'rectusFemoris', side: 'L', lx: 88,  ly: 510, ax: 162, ay: 525 },
    { id: 'erectorSpinae', side: 'R', lx: 272, ly: 220, ax: 215, ay: 256 },
    { id: 'glutes',        side: 'R', lx: 272, ly: 405, ax: 240, ay: 408 },
    { id: 'hamstrings',    side: 'R', lx: 272, ly: 542, ax: 218, ay: 538 },
  ];

  return (
    <g>
      {labels.map(l => {
        const m = MUSCLES[l.id];
        const stateName = m.states[phase];
        const sty = STATE_STYLE[stateName];
        const isSelected = selected === l.id;
        const status = STATUS_LABEL[stateName];
        const onLeft = l.side === 'L';
        const txAnchor = onLeft ? 'end' : 'start';
        // leader endpoint near label
        const leadX = onLeft ? l.lx + 4 : l.lx - 4;
        // status pill geometry
        const pillW = 36, pillH = 14;
        const pillX = onLeft ? l.lx - pillW : l.lx;
        const pillTextX = onLeft ? l.lx - pillW / 2 : l.lx + pillW / 2;

        return (
          <g key={l.id} onClick={() => onSelect(l.id)} style={{ cursor: 'pointer' }}>
            {/* leader line */}
            <path d={`M ${l.ax} ${l.ay} L ${leadX} ${l.ly}`}
              stroke={sty.fill}
              strokeWidth={isSelected ? 1.4 : 0.9}
              fill="none"
              opacity={isSelected ? 0.95 : 0.55}
              style={{ transition: 'all .4s' }}/>
            {/* anchor dot on the muscle */}
            <circle cx={l.ax} cy={l.ay} r={isSelected ? 3.5 : 2.4}
              fill={sty.fill} stroke="var(--paper)" strokeWidth="1"/>
            {/* dot at label end */}
            <circle cx={leadX} cy={l.ly} r="1.8" fill={sty.fill}/>

            {/* muscle name */}
            <text
              x={l.lx} y={l.ly - 2}
              textAnchor={txAnchor}
              fontFamily="Noto Sans SC, sans-serif"
              fontSize="11"
              fontWeight={isSelected ? 700 : 600}
              fill="var(--ink)">
              {m.cn}
            </text>

            {/* status pill (only in non-neutral states) */}
            {status && (
              <g style={{ transition: 'opacity .4s' }}>
                <rect x={pillX} y={l.ly + 4} width={pillW} height={pillH} rx="3"
                  fill={sty.fill}/>
                <text x={pillTextX} y={l.ly + 14}
                  textAnchor="middle"
                  fontFamily="Noto Sans SC"
                  fontSize="10" fontWeight="700"
                  fill="var(--paper)"
                  letterSpacing=".05em">
                  {status.cn}
                </text>
              </g>
            )}
          </g>
        );
      })}
    </g>
  );
}

Object.assign(window, { AnatomyFigure, HIP, MuscleLabels });
