/* diagram.jsx — the rotatable cosmic-center figure + per-chapter motifs.
   Exposed to window: CosmicCenter, HeroDiagram, Motif. */

const GOLD = "#d4af37", GOLD3 = "#e9cf73", ROSE = "#b85c7c", CREAM = "#f2ecda";
const prefersReduced = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;

/* Site markers placed around the augur ring (angles in degrees from north). */
const SITE_ANGLES = { salt: -90, dendera: 0, stonehenge: 90, sumer: 180 };
const sitePos = (k, r = 120) => {
  const a = ((SITE_ANGLES[k] ?? 0) - 90) * Math.PI / 180;
  return [Math.cos(a) * r, Math.sin(a) * r];
};

/* ── The cosmic center: concentric rings, cardo/decumanus, cardinal points.
   Rotation is driven straight to the DOM (a ref) — NEVER through React state —
   so the per-frame spin can't trigger re-renders that interrupt page
   transitions. Interactive variant rotates on drag and selects sites. ── */
function CosmicCenter({ size = 360, interactive = false, sites = [], selected, onSelect }) {
  const svgRef = React.useRef(null);
  const gRef = React.useRef(null);
  const rot = React.useRef(0);
  const drag = React.useRef(null);
  const apply = () => { if (gRef.current) gRef.current.setAttribute("transform", `rotate(${rot.current})`); };

  React.useEffect(() => {
    apply();
    if (prefersReduced || interactive) return;   // explorable diagram stays put; only the hero idles
    let last = performance.now(), raf;
    const speed = 2.0;
    const tick = (t) => {
      const dt = (t - last) / 1000; last = t;
      if (!drag.current) { rot.current = (rot.current + speed * dt) % 360; apply(); }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [interactive]);

  const angleAt = (e) => {
    const r = svgRef.current.getBoundingClientRect();
    return Math.atan2(e.clientY - (r.top + r.height / 2), e.clientX - (r.left + r.width / 2)) * 180 / Math.PI;
  };
  const onDown = (e) => { if (!interactive) return; drag.current = { start: angleAt(e), base: rot.current }; svgRef.current.setPointerCapture(e.pointerId); };
  const onMove = (e) => { if (!drag.current) return; rot.current = drag.current.base + (angleAt(e) - drag.current.start); apply(); };
  const onUp = (e) => { if (drag.current) { drag.current = null; try { svgRef.current.releasePointerCapture(e.pointerId); } catch (_) {} } };

  return (
    <svg ref={svgRef} width={size} height={size} viewBox="-150 -150 300 300"
      style={{ touchAction: "none", cursor: interactive ? "grab" : "default", overflow: "visible" }}
      onPointerDown={onDown} onPointerMove={onMove} onPointerUp={onUp} onPointerCancel={onUp} aria-hidden="true">
      <circle cx="0" cy="0" r="132" fill="none" stroke="rgba(212,175,55,0.10)" strokeWidth="1" />
      <g ref={gRef}>
        <g fill="none" stroke={GOLD} strokeWidth="1">
          <circle r="120" opacity="0.85" />
          <circle r="88" opacity="0.5" />
          <circle r="54" opacity="0.34" />
          <line x1="0" y1="-132" x2="0" y2="132" strokeWidth="1.4" />
          <line x1="-132" y1="0" x2="132" y2="0" strokeWidth="1.4" />
          <line x1="-85" y1="-85" x2="85" y2="85" opacity="0.32" />
          <line x1="-85" y1="85" x2="85" y2="-85" opacity="0.32" />
          {Array.from({ length: 24 }).map((_, i) => {
            const a = (i / 24) * Math.PI * 2, r1 = 120, r2 = i % 6 === 0 ? 110 : 115;
            return <line key={i} x1={Math.cos(a) * r1} y1={Math.sin(a) * r1} x2={Math.cos(a) * r2} y2={Math.sin(a) * r2} opacity="0.5" />;
          })}
        </g>
        <g fontFamily="Cormorant Garamond, Georgia, serif" fontStyle="italic" fontSize="17" fill={GOLD} textAnchor="middle" dominantBaseline="middle">
          <text x="0" y="-138">N</text><text x="138" y="0">E</text><text x="0" y="140">S</text><text x="-138" y="0">W</text>
        </g>
        {interactive && sites.map((s) => {
          const [x, y] = sitePos(s.k);
          const on = selected === s.k;
          return (
            <circle key={s.k} cx={x} cy={y} r={on ? 9 : 6} fill={on ? GOLD3 : "#05060f"} stroke={GOLD} strokeWidth="1.4"
              style={{ cursor: "pointer", transition: "r .2s", filter: on ? "drop-shadow(0 0 8px rgba(233,207,115,0.9))" : "none" }}
              onPointerDown={(e) => e.stopPropagation()} onClick={() => onSelect && onSelect(s.k)} />
          );
        })}
      </g>
      <circle r="3" fill={GOLD3} />
    </svg>
  );
}

function HeroDiagram() {
  return <CosmicCenter size={272} interactive={false} />;
}

/* ───────────────── per-chapter motifs ───────────────── */
function PentadMotif({ pentad }) {
  return (
    <div style={{ display: "flex", gap: 18, flexWrap: "wrap", justifyContent: "center", maxWidth: 760 }}>
      {pentad.map((p, i) => (
        <div key={p.n} style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 10, width: 132 }}>
          <div style={{
            width: 92, height: 92, borderRadius: "50%",
            background: "radial-gradient(circle at 32% 26%, #2a3870 0%, #1e2952 55%, #14193a 100%)",
            border: "2px solid " + GOLD, display: "flex", alignItems: "center", justifyContent: "center",
            fontFamily: "Cormorant Garamond, serif", fontStyle: "italic", fontSize: 36, color: GOLD,
            boxShadow: i === 4 ? "0 0 0 3px rgba(212,175,55,0.3), 0 0 38px rgba(212,175,55,0.5)" : "0 8px 22px rgba(0,0,0,0.5)",
          }}>{p.n}</div>
          <div style={{ fontFamily: "Spectral, serif", fontSize: 16, color: CREAM, textAlign: "center", lineHeight: 1.2 }}>{p.name}</div>
          <div style={{ fontFamily: "Cormorant Garamond, serif", fontStyle: "italic", fontSize: 17, color: ROSE }}>{p.g}</div>
        </div>
      ))}
    </div>
  );
}

function DegreesMotif({ glories }) {
  return (
    <div style={{ display: "flex", gap: 48, alignItems: "center", flexWrap: "wrap", justifyContent: "center" }}>
      <svg width="220" height="220" viewBox="-115 -115 230 230" aria-hidden="true">
        <g fill="none" stroke={GOLD} strokeWidth="1.4">
          <rect x="-100" y="-100" width="200" height="200" />
          <rect x="-64" y="-64" width="128" height="128" strokeOpacity="0.7" />
          <rect x="-30" y="-30" width="60" height="60" strokeOpacity="0.5" />
        </g>
        <g fontFamily="IBM Plex Mono, monospace" fontSize="9" fill={GOLD3} textAnchor="middle" letterSpacing="1">
          <text x="0" y="-104">TELESTIAL</text>
          <text x="0" y="-68">TERRESTRIAL</text>
          <text x="0" y="-34">CELESTIAL</text>
        </g>
        <circle r="3" fill={GOLD3} />
      </svg>
      <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
        {glories.map((g) => (
          <div key={g.name} style={{ display: "flex", alignItems: "baseline", gap: 16 }}>
            <span style={{ fontFamily: "Cormorant Garamond, serif", fontStyle: "italic", fontSize: 30, color: GOLD, minWidth: 56 }}>{g.glyph}</span>
            <span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 12, letterSpacing: "0.18em", textTransform: "uppercase", color: CREAM }}>{g.name}</span>
            <span style={{ fontFamily: "Spectral, serif", fontStyle: "italic", fontSize: 16, color: ROSE }}>{g.which}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

function CircleMotif() {
  const N = 12, R = 96;
  const pts = Array.from({ length: N }, (_, i) => {
    const a = (i / N) * Math.PI * 2 - Math.PI / 2;
    return [Math.cos(a) * R, Math.sin(a) * R];
  });
  return (
    <svg width="260" height="260" viewBox="-130 -130 260 260" aria-hidden="true" style={{ overflow: "visible" }}>
      <circle r="96" fill="none" stroke={GOLD} strokeWidth="1" opacity="0.45" />
      <g stroke={GOLD} strokeWidth="0.6" opacity="0.3">
        {pts.map((p, i) => { const q = pts[(i + 5) % N]; return <line key={i} x1={p[0]} y1={p[1]} x2={q[0]} y2={q[1]} />; })}
      </g>
      {pts.map((p, i) => <circle key={i} cx={p[0]} cy={p[1]} r="6" fill={GOLD} />)}
      <g fontFamily="Cormorant Garamond, serif" fontStyle="italic" fill={GOLD3} textAnchor="middle">
        <text x="0" y="-4" fontSize="22">Jesus</text>
        <text x="0" y="18" fontSize="14" fill={CREAM}>&amp; the twelve</text>
      </g>
    </svg>
  );
}

function GarmentMotif() {
  const marks = [[-46, -40], [46, -40], [-48, 16], [0, 16], [48, 16], [-34, 72], [34, 72]];
  return (
    <svg width="280" height="240" viewBox="-140 -130 280 250" aria-hidden="true">
      <g fill="none" stroke={GOLD} strokeWidth="1.6">
        <path d="M-78 -96 L78 -96 L104 -70 L78 -46 L78 104 L-78 104 L-78 -46 L-104 -70 Z" />
        <line x1="-40" y1="-96" x2="40" y2="-96" strokeWidth="2.4" />
      </g>
      <g fill={GOLD3} fontFamily="Cormorant Garamond, serif" fontStyle="italic" fontSize="22" textAnchor="middle">
        {marks.map((m, i) => <text key={i} x={m[0]} y={m[1] + 8}>✦</text>)}
      </g>
    </svg>
  );
}

function AnointMotif() {
  return (
    <svg width="240" height="220" viewBox="-120 -110 240 220" aria-hidden="true">
      <g fill="none" stroke={GOLD} strokeWidth="1">
        <ellipse cx="0" cy="56" rx="92" ry="20" opacity="0.3" />
        <ellipse cx="0" cy="56" rx="62" ry="13" opacity="0.45" />
        <ellipse cx="0" cy="56" rx="32" ry="7" opacity="0.6" />
      </g>
      {/* horn of oil */}
      <g transform="rotate(-24)">
        <path d="M-44 -64 Q40 -78 54 -20 Q40 -34 -10 -30 Q-40 -28 -44 -64 Z" fill="none" stroke={GOLD} strokeWidth="1.6" />
      </g>
      <g fill={GOLD3}>
        <circle cx="0" cy="6" r="3.5" />
        <circle cx="0" cy="26" r="2.6" opacity="0.7" />
        <circle cx="0" cy="42" r="2" opacity="0.5" />
      </g>
    </svg>
  );
}

function PlatesMotif() {
  return (
    <svg width="220" height="220" viewBox="-110 -110 220 220" aria-hidden="true">
      <g fill="none" stroke={GOLD} strokeWidth="1.4">
        {[0, 1, 2, 3].map((i) => (
          <rect key={i} x={-64 + i * 3} y={-84 + i * 6} width="120" height="150" rx="2" opacity={0.4 + i * 0.18} />
        ))}
      </g>
      <g stroke={GOLD3} strokeWidth="0.8" opacity="0.55">
        {Array.from({ length: 9 }).map((_, i) => <line key={i} x1="-44" y1={-58 + i * 13} x2="50" y2={-58 + i * 13} />)}
      </g>
      <circle cx="-58" cy="-9" r="3" fill={GOLD} />
    </svg>
  );
}

function FontMotif() {
  const oxen = Array.from({ length: 6 }, (_, i) => {
    const a = (i / 12) * Math.PI * 2 - Math.PI / 2 - 0.5;
    return [Math.cos(a) * 70, Math.sin(a) * 36 + 10];
  });
  return (
    <svg width="260" height="200" viewBox="-130 -90 260 200" aria-hidden="true">
      <ellipse cx="0" cy="10" rx="86" ry="42" fill="none" stroke={GOLD} strokeWidth="1.6" />
      <ellipse cx="0" cy="6" rx="64" ry="30" fill="none" stroke={GOLD} strokeWidth="0.8" opacity="0.5" />
      <ellipse cx="0" cy="2" rx="40" ry="18" fill="none" stroke={GOLD3} strokeWidth="0.8" opacity="0.6" />
      {oxen.map((o, i) => <circle key={i} cx={o[0]} cy={o[1]} r="5" fill={GOLD} opacity="0.7" />)}
    </svg>
  );
}

/* dispatcher */
function Motif({ chapter, selected, onSelect }) {
  const t = chapter.diagram.type;
  if (t === "augur") return <CosmicCenter size={400} interactive sites={chapter.sites} selected={selected} onSelect={onSelect} />;
  if (t === "pentad") return <PentadMotif pentad={chapter.pentad} />;
  if (t === "degrees") return <DegreesMotif glories={chapter.glories} />;
  if (t === "circle") return <CircleMotif />;
  if (t === "garment") return <GarmentMotif />;
  if (t === "anoint") return <AnointMotif />;
  if (t === "plates") return <PlatesMotif />;
  if (t === "font") return <FontMotif />;
  return null;
}

Object.assign(window, { CosmicCenter, HeroDiagram, Motif });
