/*
  Ecosystem Scene — square version, optimized for small display.
  Circular flywheel layout. No headline / chrome / masthead.
  Designed for 1080×1080; legible down to ~280px.
*/

const ink    = '#171717';
const ink3   = '#555555';
const ink4   = '#777777';
const accent = '#026203';
const accentDk = '#024203';
const rule   = '#d8d8d0';
const paper  = '#ffffff';

/* Draws an SVG path on via stroke-dashoffset. */
function Stroke({
  d, color = ink, width = 3,
  drawStart = 0, drawEnd = 1, ease = Easing.easeInOutCubic,
  cap = 'round', join = 'round',
  fill = 'none', opacity = 1,
}) {
  const ref = React.useRef(null);
  const [len, setLen] = React.useState(null);
  React.useEffect(() => {
    if (ref.current && ref.current.getTotalLength) {
      try { setLen(ref.current.getTotalLength() || 1); } catch {}
    }
  }, [d]);

  const t = useTime();
  const span = Math.max(0.001, drawEnd - drawStart);
  const raw  = (t - drawStart) / span;
  const p    = ease(clamp(raw, 0, 1));
  const hidden = (raw <= 0) || len == null;

  return (
    <path
      ref={ref} d={d}
      stroke={color} strokeWidth={width}
      strokeLinecap={cap} strokeLinejoin={join}
      fill={fill}
      opacity={hidden ? 0 : opacity}
      strokeDasharray={len == null ? '0 99999' : `${len}`}
      strokeDashoffset={len == null ? 0 : len * (1 - p)}
    />
  );
}

function FadeInSvg({ at, dur = 0.5, y = 6, children }) {
  const t = useTime();
  const p = Easing.easeOutCubic(clamp((t - at) / dur, 0, 1));
  return (
    <g opacity={p} transform={`translate(0, ${(1 - p) * y})`}>
      {children}
    </g>
  );
}

function DotAt({ cx, cy, at, color = '#024203', r0 = 4 }) {
  const t = useTime();
  const p = Easing.easeOutBack(clamp((t - at) / 0.35, 0, 1));
  return <circle cx={cx} cy={cy} r={r0 * p} fill={color}/>;
}

/* ── Node icon components — drawn from local origin (0,0) ── */

function ResearchIcon({ start }) {
  // document: 220 × 260
  return (
    <g filter="url(#ink)">
      <Stroke d="M -110 -130 L 70 -130 L 110 -90 L 110 130 L -110 130 Z"
              width={4}
              drawStart={start} drawEnd={start + 1.1}/>
      <Stroke d="M 70 -130 L 70 -90 L 110 -90"
              width={4}
              drawStart={start + 0.55} drawEnd={start + 0.85}/>
      {/* lines */}
      <Stroke d="M -78 -62 L 78 -62" width={3} color={ink3}
              drawStart={start + 0.85} drawEnd={start + 1.0}/>
      <Stroke d="M -78 -28 L 60 -28" width={3} color={ink3}
              drawStart={start + 0.95} drawEnd={start + 1.10}/>
      <Stroke d="M -78   6 L 82   6" width={3} color={ink3}
              drawStart={start + 1.05} drawEnd={start + 1.20}/>
      <Stroke d="M -78  40 L 46  40" width={3} color={ink3}
              drawStart={start + 1.15} drawEnd={start + 1.30}/>
      {/* green highlight */}
      <Stroke d="M -78  76 L 24  76" width={8} color={accent} opacity={0.4}
              drawStart={start + 1.25} drawEnd={start + 1.45}/>
      <Stroke d="M -78  76 L 24  76" width={3} color={accent}
              drawStart={start + 1.30} drawEnd={start + 1.50}/>
    </g>
  );
}

function MicIcon({ start }) {
  return (
    <g filter="url(#ink)">
      {/* capsule */}
      <Stroke d="M -50 -130 a 50 50 0 0 1 100 0 v 90 a 50 50 0 0 1 -100 0 z"
              width={4}
              drawStart={start} drawEnd={start + 1.0}/>
      {/* grille lines */}
      <Stroke d="M -34 -100 L 34 -100" width={3} color={ink3}
              drawStart={start + 0.65} drawEnd={start + 0.82}/>
      <Stroke d="M -34 -76 L 34 -76" width={3} color={ink3}
              drawStart={start + 0.72} drawEnd={start + 0.89}/>
      <Stroke d="M -34 -52 L 34 -52" width={3} color={ink3}
              drawStart={start + 0.79} drawEnd={start + 0.96}/>
      {/* U-stand */}
      <Stroke d="M -82 -30 a 82 82 0 0 0 164 0"
              width={4}
              drawStart={start + 0.40} drawEnd={start + 1.0}/>
      {/* stem */}
      <Stroke d="M 0 52 L 0 110" width={4}
              drawStart={start + 0.85} drawEnd={start + 1.05}/>
      {/* base */}
      <Stroke d="M -52 110 L 52 110" width={4}
              drawStart={start + 1.0} drawEnd={start + 1.15}/>
      {/* waves */}
      <Stroke d="M -120 -90 a 50 50 0 0 0 0 70" width={3} color={accent}
              drawStart={start + 1.05} drawEnd={start + 1.40}/>
      <Stroke d="M -150 -110 a 78 78 0 0 0 0 110" width={3} color={accent}
              drawStart={start + 1.20} drawEnd={start + 1.55}/>
      <Stroke d="M  120 -90 a 50 50 0 0 1 0 70" width={3} color={accent}
              drawStart={start + 1.05} drawEnd={start + 1.40}/>
      <Stroke d="M  150 -110 a 78 78 0 0 1 0 110" width={3} color={accent}
              drawStart={start + 1.20} drawEnd={start + 1.55}/>
    </g>
  );
}

function AudienceIcon({ start }) {
  // 280 × 240 frame: meridian split, dots populating
  return (
    <g filter="url(#ink)">
      <Stroke d="M -140 -120 L 140 -120 L 140 120 L -140 120 Z"
              width={4} drawStart={start} drawEnd={start + 1.0}/>
      <Stroke d="M 0 -120 L 0 120"
              width={3} color={accent} opacity={0.55}
              drawStart={start + 0.75} drawEnd={start + 1.05}/>

      {/* Europe dots (left) */}
      {[
        [-104, -78], [-66, -86], [-36, -58],
        [-114, -36], [-78, -44], [-44, -20],
        [-96,    4], [-60,   -4], [-28,  12],
        [-104,  38], [-70,  50], [-36,  36],
        [-90,   78], [-44,  86],
      ].map(([cx, cy], i) => (
        <DotAt key={'eu'+i} cx={cx} cy={cy}
               at={start + 0.55 + i * 0.05}
               color={accentDk}/>
      ))}

      {/* Africa dots (right) */}
      {[
        [ 36, -80], [ 74, -58], [108, -68],
        [ 24, -36], [ 62, -20], [104, -34],
        [ 32,   8], [ 74,   0], [112,  22],
        [ 46,  42], [ 86,  46], [122,  56],
        [ 54,  86], [ 96,  92], [ 28,  92],
      ].map(([cx, cy], i) => (
        <DotAt key={'af'+i} cx={cx} cy={cy}
               at={start + 0.70 + i * 0.05}
               color={accentDk}/>
      ))}
    </g>
  );
}

function BubbleIcon({ start }) {
  return (
    <g filter="url(#ink)">
      <Stroke d="M -110 -110 L 110 -110 L 110 76 L 24 76 L -4 110 L -8 76 L -110 76 Z"
              width={4} drawStart={start} drawEnd={start + 1.05}/>
      {/* ? */}
      <Stroke d="M -18 -62 a 28 28 0 1 1 32 44 v 14"
              width={5}
              drawStart={start + 0.75} drawEnd={start + 1.15}/>
      <Stroke d="M 14 14 L 14 24" width={8}
              drawStart={start + 1.10} drawEnd={start + 1.22}/>
    </g>
  );
}

/* Pulse dot that runs around the orbit forever from `start`. */
function OrbitPulse({ start, cx, cy, r, period = 6, color = accent }) {
  const t = useTime();
  if (t < start) return null;
  const phase = ((t - start) / period) % 1;
  const angle = -Math.PI / 2 + phase * Math.PI * 2; // start at top, clockwise
  const x = cx + Math.cos(angle) * r;
  const y = cy + Math.sin(angle) * r;
  return (
    <g>
      <circle cx={x} cy={y} r={10} fill={color}/>
      <circle cx={x} cy={y} r={20} fill="none" stroke={color} strokeWidth="2" opacity="0.4"/>
    </g>
  );
}

/* Arc between two angles (in degrees) around (cx, cy, r), with arrowhead at end. */
function OrbitArc({ start, drawStart, drawEnd, fromDeg, toDeg, cx, cy, r, color = ink, width = 4 }) {
  // path from fromDeg to toDeg (clockwise)
  const toRad = d => (d * Math.PI) / 180;
  const ax = cx + Math.cos(toRad(fromDeg)) * r;
  const ay = cy + Math.sin(toRad(fromDeg)) * r;
  const bx = cx + Math.cos(toRad(toDeg)) * r;
  const by = cy + Math.sin(toRad(toDeg)) * r;
  // sweep flag: 1 for clockwise (since SVG y is flipped relative to math)
  const sweep = 1;
  const large = (((toDeg - fromDeg) % 360) + 360) % 360 > 180 ? 1 : 0;
  const d = `M ${ax} ${ay} A ${r} ${r} 0 ${large} ${sweep} ${bx} ${by}`;

  // arrowhead: tangent at end angle, pointing along clockwise tangent
  const tanAngle = toRad(toDeg) + Math.PI / 2; // tangent perpendicular to radius (clockwise)
  const aLen = 18;
  const aWide = 10;
  const tipX = bx;
  const tipY = by;
  const baseX = tipX - Math.cos(tanAngle) * aLen;
  const baseY = tipY - Math.sin(tanAngle) * aLen;
  const leftX  = baseX + Math.cos(tanAngle + Math.PI / 2) * aWide;
  const leftY  = baseY + Math.sin(tanAngle + Math.PI / 2) * aWide;
  const rightX = baseX + Math.cos(tanAngle - Math.PI / 2) * aWide;
  const rightY = baseY + Math.sin(tanAngle - Math.PI / 2) * aWide;
  const head = `M ${leftX} ${leftY} L ${tipX} ${tipY} L ${rightX} ${rightY}`;

  return (
    <g filter="url(#ink)">
      <Stroke d={d} color={color} width={width}
              drawStart={drawStart} drawEnd={drawEnd}/>
      <Stroke d={head} color={color} width={width}
              drawStart={drawEnd - 0.2} drawEnd={drawEnd + 0.05}/>
    </g>
  );
}

/* ────────────────────────────────────────────────
   THE SCENE — square 1080×1080
   ──────────────────────────────────────────────── */
function EcosystemScene() {
  const cx = 540, cy = 540, R = 240;

  /* node positions (clock face, clockwise) */
  // top = -90, right = 0, bottom = 90, left = 180
  const node = (deg) => ({
    x: cx + Math.cos((deg * Math.PI) / 180) * R,
    y: cy + Math.sin((deg * Math.PI) / 180) * R,
    deg,
  });
  const N1 = node(-90);  // research — top
  const N2 = node(0);    // podcast — right
  const N3 = node(90);   // audience — bottom
  const N4 = node(180);  // questions — left

  /* timing (total 9s) */
  const T = {
    n1:        0.10,   // research draws
    n1lbl:     0.70,
    a1:        0.95,   // arc research→podcast
    n2:        1.55,   // podcast draws
    n2lbl:     2.15,
    a2:        2.40,   // arc podcast→audience
    n3:        3.00,   // audience draws
    n3lbl:     3.60,
    a3:        3.85,   // arc audience→questions
    n4:        4.45,   // questions draws
    n4lbl:     5.05,
    a4:        5.30,   // arc questions→research (closes loop, slower & green)
    pulse:     6.70,   // orbit pulse begins once loop is closed
  };

  // Arc gap: shrink the arc so it doesn't overlap the icons
  const gap = 18; // degrees of padding on each end

  return (
    <React.Fragment>
      <div style={{ position: 'absolute', inset: 0, background: paper }}/>

      <svg
        viewBox="0 0 1080 1080"
        width="1080" height="1080"
        style={{position:'absolute', inset:0}}
        xmlns="http://www.w3.org/2000/svg"
      >
        <defs>
          <filter id="ink" x="-5%" y="-5%" width="110%" height="110%">
            <feTurbulence type="fractalNoise" baseFrequency="0.018" numOctaves="2" seed="4" result="t"/>
            <feDisplacementMap in="SourceGraphic" in2="t" scale="2.6"/>
          </filter>
        </defs>

        {/* faint guide ring — drawn very softly so you sense the orbit */}
        <FadeInSvg at={T.a1 - 0.4} dur={1.0}>
          <circle cx={cx} cy={cy} r={R}
                  fill="none" stroke={rule} strokeWidth="1"
                  strokeDasharray="4 8" opacity="0.7"/>
        </FadeInSvg>

        {/* ────── Nodes ────── */}
        <g transform={`translate(${N1.x}, ${N1.y})`}>
          <ResearchIcon start={T.n1}/>
        </g>
        <g transform={`translate(${N2.x}, ${N2.y})`}>
          <MicIcon start={T.n2}/>
        </g>
        <g transform={`translate(${N3.x}, ${N3.y})`}>
          <AudienceIcon start={T.n3}/>
        </g>
        <g transform={`translate(${N4.x}, ${N4.y})`}>
          <BubbleIcon start={T.n4}/>
        </g>

        {/* ────── Node labels — all placed radially outward, kept well inside the 1080×1080 frame ────── */}
        {/* Research — above top icon */}
        <FadeInSvg at={T.n1lbl} dur={0.5}>
          <text x={N1.x} y={120} textAnchor="middle"
                fontFamily="Heebo, sans-serif" fontSize="30" fontWeight="700"
                letterSpacing="-0.015em" fill={ink}>
            Research
          </text>
          <text x={N1.x} y={146} textAnchor="middle"
                fontFamily="JetBrains Mono, monospace" fontSize="13"
                letterSpacing="2" fill={ink4}
                style={{textTransform:'uppercase'}}>
            findings &amp; papers
          </text>
        </FadeInSvg>

        {/* Podcast — to the right of right icon */}
        <FadeInSvg at={T.n2lbl} dur={0.5}>
          <text x={940} y={N2.y + 4} textAnchor="start"
                fontFamily="Heebo, sans-serif" fontSize="30" fontWeight="700"
                letterSpacing="-0.015em" fill={ink}>
            Podcast
          </text>
          <text x={940} y={N2.y + 30} textAnchor="start"
                fontFamily="JetBrains Mono, monospace" fontSize="13"
                letterSpacing="2" fill={ink4}
                style={{textTransform:'uppercase'}}>
            conversations
          </text>
        </FadeInSvg>

        {/* Audience — below bottom icon */}
        <FadeInSvg at={T.n3lbl} dur={0.5}>
          <text x={N3.x} y={970} textAnchor="middle"
                fontFamily="Heebo, sans-serif" fontSize="30" fontWeight="700"
                letterSpacing="-0.015em" fill={ink}>
            Audience
          </text>
          <text x={N3.x} y={996} textAnchor="middle"
                fontFamily="JetBrains Mono, monospace" fontSize="13"
                letterSpacing="2" fill={ink4}
                style={{textTransform:'uppercase'}}>
            two continents
          </text>
        </FadeInSvg>

        {/* Questions — to the left of left icon */}
        <FadeInSvg at={T.n4lbl} dur={0.5}>
          <text x={140} y={N4.y + 4} textAnchor="end"
                fontFamily="Heebo, sans-serif" fontSize="30" fontWeight="700"
                letterSpacing="-0.015em" fill={ink}>
            Questions
          </text>
          <text x={140} y={N4.y + 30} textAnchor="end"
                fontFamily="JetBrains Mono, monospace" fontSize="13"
                letterSpacing="2" fill={ink4}
                style={{textTransform:'uppercase'}}>
            &amp; connections
          </text>
        </FadeInSvg>

        {/* ────── Connecting arcs (clockwise around the orbit) ────── */}
        {/* a1: top → right */}
        <OrbitArc
          drawStart={T.a1} drawEnd={T.a1 + 0.9}
          fromDeg={-90 + gap} toDeg={0 - gap}
          cx={cx} cy={cy} r={R}
          color={ink} width={3.5}/>
        {/* a2: right → bottom */}
        <OrbitArc
          drawStart={T.a2} drawEnd={T.a2 + 0.9}
          fromDeg={0 + gap} toDeg={90 - gap}
          cx={cx} cy={cy} r={R}
          color={ink} width={3.5}/>
        {/* a3: bottom → left */}
        <OrbitArc
          drawStart={T.a3} drawEnd={T.a3 + 0.9}
          fromDeg={90 + gap} toDeg={180 - gap}
          cx={cx} cy={cy} r={R}
          color={ink} width={3.5}/>
        {/* a4: left → top (closes loop) — green! */}
        <OrbitArc
          drawStart={T.a4} drawEnd={T.a4 + 1.1}
          fromDeg={180 + gap} toDeg={270 - gap}
          cx={cx} cy={cy} r={R}
          color={accent} width={4.5}/>

        {/* ────── Orbiting pulse — runs continuously after the loop closes ────── */}
        <OrbitPulse start={T.pulse} cx={cx} cy={cy} r={R} period={2.4} color={accent}/>
      </svg>
    </React.Fragment>
  );
}

Object.assign(window, { EcosystemSceneSquare: EcosystemScene });
