// body.jsx — the holographic "energy body": segmented wireframe figure,
// tappable regions, Goenka-style scan sweep, and glowing sensation markers.

// viewBox 300 x 660. Each region: shape + a `point` where markers land + scan order y.
const MT_REGIONS = [
  { id: 'head',     point: [150, 60],  shape: { t: 'ell', cx: 150, cy: 60,  rx: 38, ry: 45 } },
  { id: 'throat',   point: [150, 114], shape: { t: 'rr',  x: 132, y: 100, w: 36, h: 28, r: 13 } },
  { id: 'armR',     point: [222, 200], shape: { t: 'cap', x1: 206, y1: 152, x2: 240, y2: 250, w: 34 } },
  { id: 'forearmR', point: [248, 298], shape: { t: 'cap', x1: 240, y1: 252, x2: 252, y2: 340, w: 25 } },
  { id: 'handR',    point: [256, 364], shape: { t: 'ell', cx: 256, cy: 364, rx: 16, ry: 21 } },
  { id: 'armL',     point: [78, 200],  shape: { t: 'cap', x1: 94,  y1: 152, x2: 60,  y2: 250, w: 34 } },
  { id: 'forearmL', point: [52, 298],  shape: { t: 'cap', x1: 60,  y1: 252, x2: 48,  y2: 340, w: 25 } },
  { id: 'handL',    point: [44, 364],  shape: { t: 'ell', cx: 44,  cy: 364, rx: 16, ry: 21 } },
  { id: 'chest',    point: [150, 172], shape: { t: 'rr',  x: 84,  y: 126, w: 132, h: 100, r: 32 } },
  { id: 'abdomen',  point: [150, 264], shape: { t: 'rr',  x: 95,  y: 230, w: 110, h: 74,  r: 26 } },
  { id: 'pelvis',   point: [150, 340], shape: { t: 'rr',  x: 90,  y: 308, w: 120, h: 70,  r: 30 } },
  { id: 'thighR',   point: [180, 432], shape: { t: 'cap', x1: 174, y1: 380, x2: 186, y2: 488, w: 44 } },
  { id: 'calfR',    point: [188, 536], shape: { t: 'cap', x1: 186, y1: 490, x2: 192, y2: 584, w: 34 } },
  { id: 'footR',    point: [196, 606], shape: { t: 'ell', cx: 196, cy: 606, rx: 23, ry: 15 } },
  { id: 'thighL',   point: [120, 432], shape: { t: 'cap', x1: 126, y1: 380, x2: 114, y2: 488, w: 44 } },
  { id: 'calfL',    point: [112, 536], shape: { t: 'cap', x1: 114, y1: 490, x2: 108, y2: 584, w: 34 } },
  { id: 'footL',    point: [104, 606], shape: { t: 'ell', cx: 104, cy: 606, rx: 23, ry: 15 } },
];
const MT_REGION_BY_ID = Object.fromEntries(MT_REGIONS.map(r => [r.id, r]));

// scan order: crown → face → arms → torso → hips → legs → feet (top-to-bottom sweep)
const MT_SCAN_ORDER = ['head','throat','chest','armR','forearmR','handR','armL','forearmL','handL',
  'abdomen','pelvis','thighR','calfR','footR','thighL','calfL','footL'];

// ── seated meditation posture (cross-legged / lotus) ──────────────
// same region ids so markers / heat / scan all carry over. viewBox 0 0 360 500.
const MT_REGIONS_SEATED = [
  { id: 'head',     point: [180, 74],  shape: { t: 'ell', cx: 180, cy: 74,  rx: 34, ry: 40 } },
  { id: 'throat',   point: [180, 124], shape: { t: 'rr',  x: 162, y: 112, w: 36, h: 26, r: 12 } },
  { id: 'chest',    point: [180, 172], shape: { t: 'rr',  x: 124, y: 136, w: 112, h: 80, r: 30 } },
  { id: 'abdomen',  point: [180, 238], shape: { t: 'rr',  x: 132, y: 214, w: 96,  h: 60, r: 24 } },
  { id: 'pelvis',   point: [180, 300], shape: { t: 'rr',  x: 116, y: 272, w: 128, h: 62, r: 28 } },
  { id: 'armR',     point: [246, 192], shape: { t: 'cap', x1: 228, y1: 150, x2: 262, y2: 232, w: 30 } },
  { id: 'forearmR', point: [224, 280], shape: { t: 'cap', x1: 262, y1: 232, x2: 196, y2: 318, w: 26 } },
  { id: 'handR',    point: [192, 326], shape: { t: 'ell', cx: 192, cy: 326, rx: 18, ry: 14 } },
  { id: 'armL',     point: [114, 192], shape: { t: 'cap', x1: 132, y1: 150, x2: 98,  y2: 232, w: 30 } },
  { id: 'forearmL', point: [136, 280], shape: { t: 'cap', x1: 98,  y1: 232, x2: 164, y2: 318, w: 26 } },
  { id: 'handL',    point: [168, 326], shape: { t: 'ell', cx: 168, cy: 326, rx: 18, ry: 14 } },
  { id: 'thighR',   point: [250, 358], shape: { t: 'cap', x1: 216, y1: 326, x2: 304, y2: 392, w: 42 } },
  { id: 'calfR',    point: [236, 420], shape: { t: 'cap', x1: 304, y1: 392, x2: 188, y2: 432, w: 30 } },
  { id: 'footR',    point: [196, 432], shape: { t: 'ell', cx: 196, cy: 432, rx: 20, ry: 13 } },
  { id: 'thighL',   point: [110, 358], shape: { t: 'cap', x1: 144, y1: 326, x2: 56,  y2: 392, w: 42 } },
  { id: 'calfL',    point: [124, 420], shape: { t: 'cap', x1: 56,  y1: 392, x2: 172, y2: 432, w: 30 } },
  { id: 'footL',    point: [164, 432], shape: { t: 'ell', cx: 164, cy: 432, rx: 20, ry: 13 } },
];
const MT_REGION_SEATED_BY_ID = Object.fromEntries(MT_REGIONS_SEATED.map(r => [r.id, r]));

// pose registry — geometry + scan range + decorative scaffold/aura
const MT_POSES = {
  standing: {
    vb: [0, 0, 300, 660], regions: MT_REGIONS, byId: MT_REGION_BY_ID,
    aura: { cx: 150, cy: 300, rx: 180, ry: 320 }, headId: 'head', breatheOrigin: '150px 320px',
    scanY: [40, 620], scanX: [34, 266],
    scaffold: (C) => (
      <g stroke={C.tealLine} strokeWidth="0.7" fill="none" opacity="0.5">
        <line x1="150" y1="106" x2="150" y2="378" />
        <line x1="150" y1="378" x2="120" y2="490" />
        <line x1="150" y1="378" x2="180" y2="490" />
        <ellipse cx="150" cy="172" rx="66" ry="14" />
        <ellipse cx="150" cy="264" rx="55" ry="11" />
        <ellipse cx="150" cy="340" rx="60" ry="12" />
      </g>
    ),
  },
  seated: {
    vb: [0, 0, 360, 500], regions: MT_REGIONS_SEATED, byId: MT_REGION_SEATED_BY_ID,
    aura: { cx: 180, cy: 250, rx: 210, ry: 220 }, headId: 'head', breatheOrigin: '180px 300px',
    scanY: [40, 446], scanX: [48, 312],
    scaffold: (C) => (
      <g stroke={C.tealLine} strokeWidth="0.7" fill="none" opacity="0.5">
        <line x1="180" y1="116" x2="180" y2="300" />
        <ellipse cx="180" cy="170" rx="58" ry="13" />
        <ellipse cx="180" cy="300" rx="64" ry="12" />
        <path d="M180 300 L70 400 M180 300 L290 400 M70 400 Q180 460 290 400" />
        <ellipse cx="180" cy="420" rx="118" ry="22" opacity="0.4" />
      </g>
    ),
  },
};
function mtPose(p) { return MT_POSES[p] || MT_POSES.standing; }

function mtShapeBBox(s) {
  if (s.t === 'ell') return [s.cy - s.ry, s.cy + s.ry];
  if (s.t === 'rr') return [s.y, s.y + s.h];
  if (s.t === 'cap') return [Math.min(s.y1, s.y2) - s.w / 2, Math.max(s.y1, s.y2) + s.w / 2];
  return [0, 0];
}

// Render one region's geometry. `mode`: 'idle' | 'active' | 'dim'
function MTRegionShape({ s, stroke, fill, sw = 1.4, opacity = 1, dash }) {
  const common = { fill, stroke, strokeWidth: sw, opacity, strokeDasharray: dash };
  if (s.t === 'ell') return <ellipse cx={s.cx} cy={s.cy} rx={s.rx} ry={s.ry} {...common} />;
  if (s.t === 'rr') return <rect x={s.x} y={s.y} width={s.w} height={s.h} rx={s.r} {...common} />;
  if (s.t === 'cap') return <line x1={s.x1} y1={s.y1} x2={s.x2} y2={s.y2}
    stroke={stroke === 'none' ? fill : stroke} strokeWidth={s.w} strokeLinecap="round"
    fill="none" opacity={opacity} />;
  return null;
}

function BodyFigure({
  pose: poseProp = null,     // 'standing' | 'seated' (falls back to context)
  scanRegion = null,         // id of region currently under the scan sweep
  markers = [],              // [{region, sensationId, intensity, i}]
  onRegionTap,               // (id) => void
  selected = null,           // selected region id (during noting)
  breathing = false,         // gentle scale pulse
  heat = null,               // { regionId: {hue, weight 0..1} } for Atlas heatmap
  dim = false,               // dim figure (e.g. on complete card)
  scanY = null,              // absolute Y of sweep line (in pose viewBox units)
  scanAxis = 'y',            // 'y' = horizontal line moving vertically; 'x' = vertical line moving horizontally
  scanPos = null,            // absolute coord along the active axis (overrides scanY)
  showScanLine = false,
  interactive = true,
  tint = null,               // hex hue to recolor the figure (per method/phase); null = teal
  glow = false,              // soft whole-body aura (e.g. mettā phase)
  anchor = null,             // {x,y} breath-focus glow in viewBox coords (e.g. Ānāpāna at nostrils)
  naam = null,               // { regions:[{id, fresh}], word, hue } — Name placed on body parts (Hybrid)
}) {
  const C = MT_COLORS;
  const ctxPose = React.useContext(MTPoseContext);
  const P = mtPose(poseProp || ctxPose);
  const tintHue = tint || C.teal;
  const tintSoft = hexA(tintHue, 0.10);
  const tintLine = hexA(tintHue, 0.30);
  const tintBright = hexA(tintHue, 0.95);
  const [vx, vy, vw, vh] = P.vb;
  const regions = P.regions, byId = P.byId;
  const sx = (frac) => vx + vw * frac; // helper for generic scan-line geometry
  return (
    <svg viewBox={P.vb.join(' ')} style={{ width: '100%', height: '100%', overflow: 'visible' }}>
      <defs>
        <radialGradient id="auraG" cx="50%" cy="42%" r="60%">
          <stop offset="0%" stopColor="rgba(86,180,255,0.35)" />
          <stop offset="45%" stopColor="rgba(54,232,210,0.10)" />
          <stop offset="100%" stopColor="rgba(54,232,210,0)" />
        </radialGradient>
        <radialGradient id="headG" cx="50%" cy="42%" r="62%">
          <stop offset="0%" stopColor="rgba(120,205,255,0.85)" />
          <stop offset="55%" stopColor="rgba(56,150,220,0.35)" />
          <stop offset="100%" stopColor="rgba(40,110,170,0.05)" />
        </radialGradient>
        <linearGradient id="scanG" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="rgba(120,240,255,0)" />
          <stop offset="50%" stopColor="rgba(150,255,245,0.9)" />
          <stop offset="100%" stopColor="rgba(120,240,255,0)" />
        </linearGradient>
        <linearGradient id="scanGX" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stopColor="rgba(120,240,255,0)" />
          <stop offset="50%" stopColor="rgba(150,255,245,0.9)" />
          <stop offset="100%" stopColor="rgba(120,240,255,0)" />
        </linearGradient>
        <filter id="soft" x="-60%" y="-60%" width="220%" height="220%">
          <feGaussianBlur stdDeviation="3.4" />
        </filter>
        <filter id="softBig" x="-80%" y="-80%" width="260%" height="260%">
          <feGaussianBlur stdDeviation="8" />
        </filter>
      </defs>

      {/* ambient aura */}
      <ellipse cx={P.aura.cx} cy={P.aura.cy} rx={P.aura.rx} ry={P.aura.ry} fill="url(#auraG)" opacity={dim ? 0.5 : 1} />
      {/* mettā / phase glow — soft tinted whole-body radiance */}
      {glow && (
        <ellipse cx={P.aura.cx} cy={P.aura.cy} rx={P.aura.rx * 0.78} ry={P.aura.ry * 0.7}
          fill={hexA(tintHue, 0.16)} filter="url(#softBig)"
          style={{ transformOrigin: `${P.aura.cx}px ${P.aura.cy}px`, animation: 'mtGlowPulse 4s ease-in-out infinite' }} />
      )}

      <g style={{
        transformOrigin: P.breatheOrigin,
        animation: breathing ? 'mtBreathe 9s ease-in-out infinite' : 'none',
        opacity: dim ? 0.62 : 1,
      }}>
        {/* spine + scaffold lines for wireframe feel */}
        {P.scaffold(C)}

        {/* segments */}
        {regions.map(r => {
          const isHead = r.id === P.headId;
          const active = scanRegion === r.id || selected === r.id;
          const h = heat && heat[r.id];
          let fill = tintSoft, stroke = tintLine, sw = 1.3, op = 0.92;
          if (isHead) { fill = 'url(#headG)'; stroke = 'rgba(140,210,255,0.7)'; }
          if (h) { fill = hexA(h.hue, 0.10 + h.weight * 0.34); stroke = hexA(h.hue, 0.55 + h.weight * 0.4); sw = 1.4; }
          if (active) { fill = isHead ? 'url(#headG)' : hexA(tintHue, 0.24); stroke = tintBright; sw = 2; }
          return (
            <g key={r.id}
              onClick={interactive ? () => onRegionTap && onRegionTap(r.id) : undefined}
              style={{ cursor: interactive ? 'pointer' : 'default' }}>
              {active && (
                <g filter="url(#soft)" opacity="0.9">
                  <MTRegionShape s={r.shape} stroke="none" fill={isHead ? 'rgba(120,210,255,0.5)' : hexA(tintHue, 0.4)} />
                </g>
              )}
              <MTRegionShape s={r.shape} stroke={stroke} fill={fill} sw={sw} opacity={op} />
              {/* faint latitude ring inside torso blocks for wireframe depth */}
              {r.shape.t === 'rr' && (
                <line x1={r.shape.x + 8} y1={r.shape.y + r.shape.h / 2}
                  x2={r.shape.x + r.shape.w - 8} y2={r.shape.y + r.shape.h / 2}
                  stroke={active ? tintBright : tintLine} strokeWidth="0.7" opacity="0.5" />
              )}
              {/* invisible fat hit area for capsules */}
              {interactive && r.shape.t === 'cap' && (
                <line x1={r.shape.x1} y1={r.shape.y1} x2={r.shape.x2} y2={r.shape.y2}
                  stroke="transparent" strokeWidth={r.shape.w + 14} strokeLinecap="round" />
              )}
            </g>
          );
        })}

        {/* Name placed on body parts (Hybrid Naam-scan) */}
        {naam && naam.regions && naam.regions.map((nr, i) => {
          const reg = byId[nr.id]; if (!reg) return null;
          const [x, y] = reg.point;
          const hue = naam.hue || '#C9A0FF';
          return (
            <g key={nr.id + '-' + i} style={{ pointerEvents: 'none' }}>
              <circle cx={x} cy={y} r={nr.fresh ? 16 : 11} fill={hexA(hue, nr.fresh ? 0.28 : 0.14)} filter="url(#soft)" />
              <text x={x} y={y} textAnchor="middle" dominantBaseline="central"
                style={{ fontFamily: 'var(--serif)', fontSize: nr.fresh ? 18 : 13, fill: hue,
                  opacity: nr.fresh ? 1 : 0.72, fontStyle: 'normal',
                  filter: `drop-shadow(0 0 6px ${hexA(hue, 0.7)})`,
                  transformOrigin: `${x}px ${y}px`,
                  animation: nr.fresh ? 'mtNaamPop .6s ease-out' : 'none' }}>
                {naam.word}
              </text>
            </g>
          );
        })}

        {/* sensation markers */}
        {markers.map((m, idx) => {
          const reg = byId[m.region]; if (!reg) return null;
          const sens = MT_SENS_MAP[m.sensationId] || { hue: '#36E8D2' };
          const jx = ((m.i || 0) % 3 - 1) * 11 + (idx % 2 ? 4 : -4);
          const jy = (Math.floor((m.i || 0) / 3)) * 12 - 4;
          const [x, y] = [reg.point[0] + jx, reg.point[1] + jy];
          const rad = 4 + (m.intensity || 0) * 2.4;
          return (
            <g key={idx}>
              <circle cx={x} cy={y} r={rad * 2.6} fill={hexA(sens.hue, 0.22)} filter="url(#soft)" />
              <circle cx={x} cy={y} r={rad} fill={sens.hue}
                style={{ transformOrigin: `${x}px ${y}px`, animation: `mtPulse ${2.4 + (idx % 3) * 0.5}s ease-in-out infinite` }} />
              <circle cx={x} cy={y} r={rad + 2.5} fill="none" stroke={hexA(sens.hue, 0.6)} strokeWidth="1" />
            </g>
          );
        })}
      </g>

      {/* scan sweep line — horizontal (axis y) or vertical (axis x) */}
      {showScanLine && (scanPos != null || scanY != null) && (() => {
        const pos = scanPos != null ? scanPos : scanY;
        const sy = (frac) => vy + vh * frac;
        if (scanAxis === 'x') {
          return (
            <g style={{ pointerEvents: 'none' }}>
              <rect x={pos - 26} y={sy(0.02)} width="52" height={vh * 0.96} fill="url(#scanGX)" opacity="0.55" filter="url(#softBig)" />
              <line x1={pos} y1={sy(0.066)} x2={pos} y2={sy(0.934)} stroke="#CFFFF8" strokeWidth="1.4" opacity="0.9" />
              <line x1={pos} y1={sy(0.066)} x2={pos} y2={sy(0.934)} stroke="#CFFFF8" strokeWidth="4" opacity="0.25" filter="url(#soft)" />
              {[0.13,0.29,0.43,0.5,0.57,0.71,0.87].map((f,i)=>(
                <circle key={i} cx={pos + (i%2?-3:3)} cy={sy(f)} r="1.3" fill="#EAFFFA" opacity="0.8" />
              ))}
            </g>
          );
        }
        return (
          <g style={{ pointerEvents: 'none' }}>
            <rect x={sx(0.02)} y={pos - 26} width={vw * 0.96} height="52" fill="url(#scanG)" opacity="0.55" filter="url(#softBig)" />
            <line x1={sx(0.066)} y1={pos} x2={sx(0.934)} y2={pos} stroke="#CFFFF8" strokeWidth="1.4" opacity="0.9" />
            <line x1={sx(0.066)} y1={pos} x2={sx(0.934)} y2={pos} stroke="#CFFFF8" strokeWidth="4" opacity="0.25" filter="url(#soft)" />
            {[0.13,0.29,0.43,0.5,0.57,0.71,0.87].map((f,i)=>(
              <circle key={i} cx={sx(f)} cy={pos + (i%2?-3:3)} r="1.3" fill="#EAFFFA" opacity="0.8" />
            ))}
          </g>
        );
      })()}

      {/* breath-focus anchor glow (Ānāpāna) */}
      {anchor && (
        <g style={{ pointerEvents: 'none' }}>
          <circle cx={anchor.x} cy={anchor.y} r="30" fill={hexA(tintHue, 0.16)} filter="url(#softBig)"
            style={{ transformOrigin: `${anchor.x}px ${anchor.y}px`, animation: 'mtGlowPulse 3.4s ease-in-out infinite' }} />
          <circle cx={anchor.x} cy={anchor.y} r="6.5" fill={tintBright}
            style={{ transformOrigin: `${anchor.x}px ${anchor.y}px`, animation: 'mtPulse 3.4s ease-in-out infinite' }} />
          <circle cx={anchor.x} cy={anchor.y} r="11" fill="none" stroke={hexA(tintHue, 0.6)} strokeWidth="1" />
        </g>
      )}
    </svg>
  );
}

// hex (#RRGGBB) + alpha → rgba()
function hexA(hex, a) {
  const h = hex.replace('#', '');
  const r = parseInt(h.slice(0, 2), 16), g = parseInt(h.slice(2, 4), 16), b = parseInt(h.slice(4, 6), 16);
  return `rgba(${r},${g},${b},${a})`;
}

// drifting particle field background (the "scanner dust" from the reference)
function ParticleField({ count = 60, style = {} }) {
  const dots = React.useMemo(() => Array.from({ length: count }, (_, i) => ({
    x: Math.random() * 100, y: Math.random() * 100,
    s: Math.random() * 1.6 + 0.4, d: Math.random() * 8 + 6, delay: -Math.random() * 10,
    o: Math.random() * 0.4 + 0.08,
  })), [count]);
  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', pointerEvents: 'none', ...style }}>
      {dots.map((p, i) => (
        <span key={i} style={{
          position: 'absolute', left: `${p.x}%`, top: `${p.y}%`,
          width: p.s, height: p.s, borderRadius: 9, background: '#7CF0DC',
          opacity: p.o, boxShadow: '0 0 4px rgba(124,240,220,0.8)',
          animation: `mtFloat ${p.d}s ease-in-out ${p.delay}s infinite`,
        }} />
      ))}
    </div>
  );
}

Object.assign(window, {
  MT_REGIONS, MT_REGION_BY_ID, MT_SCAN_ORDER, mtShapeBBox,
  MT_REGIONS_SEATED, MT_REGION_SEATED_BY_ID, MT_POSES, mtPose,
  BodyFigure, ParticleField, hexA,
});
