// living-lab-scene.jsx — the Evidence Engine, told like a professor drawing it
// out on a chalkboard: every element strokes on in sequence, lettering writes in
// letter by letter, and the flows only begin once their roads exist.
//
// Two highways of information (gray/white multi-line, in the gaps, stopping at
// the frame borders — the orbs inform the phase of work and never enter a box):
//   TOP    (runs right): blue  basic → oriented   ·   green oriented → applied
//   BOTTOM (runs left) : purple applied → oriented ·  green oriented → basic
const { Easing, clamp } = window;
const {
  LAB, rng, frac, lerp, seg, dashDraw, HandText, makeLine, sampleLine, Pulse, Line, ZoneFrame,
  AgentCell, SolutionCell, ThesisBox, ThoughtCloud, TRCard, boxPath,
  FRAMES, CENTER, HIGHWAY, LABEL_Y, THOUGHT_Y, WMI_SMALL, FOUNDATION, SOLUTIONS, GROUPS, TR_IDS, layoutAgents,
} = window;

// ── the lecture schedule (seconds) — no rigid beats, just the telling ────────
const T = {
  title: 0.3, sub: 2.0,
  fL: 3.4, fM: 5.4, fR: 7.4,           // the three stages, drawn one at a time
  agents: 9.6,                          // the research field, sketched in
  wmi: 14.6,                            // the current thesis
  found: 17.2,                          // the protocol foundation
  hwT: 20.0, hwB: 21.4,                 // the two highways, drawn in travel direction
  blue: 22.8, green: 24.4, purple: 26.0, fund: 27.6,   // the flows begin
  pack: 30.6, deal: 31.4,               // WMI consolidates; the TRs deal out
  sols: 32.8,                           // solutions built as the reports publish
  gem: 36.4,                            // a thought forms above
  desc: 39.6, descEnd: 43.6,            // GEM descends; WMI settles beneath
  late: 44.2,                           // three more solutions, barely started
  next: 47.0,                           // the next thought — the cycle turns
  erase: 50.5,          // the whole diagram fades away
  fly: 52.6,            // the flywheel draws — second-to-last beat
};
const SEQ_END = 64;
const LGAP = [FRAMES.left.x + FRAMES.left.w, FRAMES.mid.x];
const RGAP = [FRAMES.mid.x + FRAMES.mid.w, FRAMES.right.x];

function buildGeometry(n) {
  const agents = layoutAgents(n);
  const mk = (x0, y, x1, s) => makeLine(x0, y, x1, y, { amp: 1.0, seed: s });
  // top highway drawn left→right; bottom highway built right→left so it draws
  // (and flows) from the applied side back
  const ltop = HIGHWAY.topYs.map((y, k) => mk(LGAP[0], y, LGAP[1], 300 + k));
  const rtop = HIGHWAY.topYs.map((y, k) => mk(RGAP[0], y, RGAP[1], 310 + k));
  const rbot = HIGHWAY.botYs.map((y, k) => mk(RGAP[1], y, RGAP[0], 320 + k));
  const lbot = HIGHWAY.botYs.map((y, k) => mk(LGAP[1], y, LGAP[0], 330 + k));
  const upLine = makeLine(WMI_SMALL.x - 4, WMI_SMALL.y - 46, CENTER.x - 4, CENTER.y + 78, { amp: 2, seed: 99 });
  return { agents, ltop, rtop, rbot, lbot, upLine };
}

function Scene({ mt = 29, tweaks }) {
  const { agents: agentN = 5, labels = true, pulses = 2 } = tweaks || {};
  const L = labels;
  const g = React.useMemo(() => buildGeometry(agentN), [agentN]);
  const EO = Easing.easeOutCubic, EIO = Easing.easeInOutCubic;

  const descP = seg(mt, T.desc, T.descEnd, EIO);
  const packP = seg(mt, T.pack, T.pack + 2.2, EO);
  const coreAngle = mt * 46;
  const outDim = 1 - 0.5 * Math.sin(Math.PI * descP);

  // WMI: drawn as the current thesis, later shrinks + settles beneath GEM
  const wmiDraw = seg(mt, T.wmi, T.wmi + 1.6);
  const wmiW = lerp(176, 112, descP), wmiH = lerp(188, 120, descP);
  const wmiPos = { x: lerp(CENTER.x, WMI_SMALL.x, descP), y: lerp(CENTER.y, WMI_SMALL.y, descP) };
  const wmiGlow = lerp(1, 0.62, descP);
  const wmiConsolidate = 1 - 0.05 * packP * (1 - descP);

  // GEM: a thought forms, then descends and is drawn in as the new thesis
  const gemForm = seg(mt, T.gem, T.gem + 2.2, EO);
  const gemY = lerp(THOUGHT_Y, CENTER.y, descP);
  const bob = Math.sin(mt * 1.5) * 4 * (1 - descP);
  const gemCloudO = gemForm * (1 - seg(mt, T.desc + 0.4, T.descEnd - 0.5));
  const gemBoxDraw = seg(mt, T.desc + 0.8, T.descEnd - 0.2);
  const upDraw = seg(mt, T.descEnd - 0.4, T.descEnd + 1.0);
  const nextForm = seg(mt, T.next, T.next + 2.4, EO);
  const newBob = Math.sin(mt * 1.4 + 1) * 4;

  // ── flows (drift, never zip) — orbs live on the highways only ───────────────
  const nP = clamp(Math.round(pulses), 1, 3);
  const evidenceIn = seg(mt, T.blue, T.blue + 1.2);
  const greenOut = seg(mt, T.green, T.green + 1.2) * outDim;
  const greenFund = seg(mt, T.fund, T.fund + 1.2) * outDim;
  const purpleBack = seg(mt, T.purple, T.purple + 1.2);
  const pulseNodes = [];
  const segOrbs = (segPts, { kind, n, speed, active, phaseSeed, key }) => {
    if (active <= 0.02) return;
    for (let k = 0; k < n; k++) {
      const f = frac(mt * speed + rng(phaseSeed + k) + k / n);
      const u = 0.04 + f * 0.92;
      const p = sampleLine(segPts, u);
      const edge = Math.min(f, 1 - f);
      pulseNodes.push(<Pulse key={key + k} kind={kind} x={p.x} y={p.y} o={active * clamp(edge / 0.09, 0, 1)} r={6} />);
    }
  };
  // dense flow: orbs ride EVERY lane of each highway — the volume is the meaning
  const denseFlow = (band, kind, active, speed, seedBase, keyBase) => {
    band.forEach((pts, li) => segOrbs(pts, { kind, n: nP + 3, speed: speed + li * 0.012, active, phaseSeed: seedBase + li * 13, key: keyBase + li }));
  };
  denseFlow(g.ltop, 'blue',   evidenceIn, 0.19, 10,  'tb');
  denseFlow(g.rtop, 'green',  greenOut,   0.19, 40,  'tg');
  denseFlow(g.rbot, 'purple', purpleBack, 0.17, 70,  'bp');
  denseFlow(g.lbot, 'green',  greenFund,  0.17, 100, 'bg');

  // ── per-solution schedule ───────────────────────────────────────────────────
  const solSchedule = (s) => {
    let drawStart, feed;
    if (s.era === 'foundation') { drawStart = T.found + 0.5 + s.i * 0.6; feed = T.green + 0.6; }
    else if (s.era === 'reports') { drawStart = T.sols + (s.i - 2) * 0.7; feed = drawStart + 1.6; }
    else { drawStart = T.late + (s.i - 6) * 0.6; feed = drawStart + 1.4; }
    const draw = seg(mt, drawStart, drawStart + 1.1);
    const progress = s.maxBar * seg(mt, feed, feed + 9);
    const dim = s.era === 'gem' ? 1 : outDim;
    const fed = seg(mt, feed, feed + 1) * dim;
    const flash = 0.5 + 0.5 * Math.sin(mt * 2.4 + s.i * 1.7);
    return { draw, progress, bright: fed * (0.45 + 0.55 * flash) };
  };

  // ── TR cards (the hero moment) ──────────────────────────────────────────────
  const trCards = [];
  for (let k = 0; k < 6; k++) {
    const deal = seg(mt, T.deal + k * 0.45, T.deal + 0.85 + k * 0.45, EO);
    if (deal <= 0.01) continue;
    const gather = seg(mt, T.desc, T.desc + 1.4, Easing.easeInCubic);
    const fanX = CENTER.x + (k - 2.5) * 60, fanY = CENTER.y + 172 + Math.abs(k - 2.5) * 6, rot = (k - 2.5) * 8;
    const x = lerp(lerp(CENTER.x, fanX, deal), wmiPos.x, gather);
    const y = lerp(lerp(CENTER.y, fanY, deal), wmiPos.y, gather);
    const sc = lerp(0.5 + 0.5 * deal, 0.25, gather), o = deal * (1 - gather);
    trCards.push(
      <g key={'tr' + k} transform={`translate(${x} ${y}) rotate(${rot * (1 - gather)}) scale(${sc})`} opacity={o}>
        <TRCard tab={TR_IDS[k]} seed={k * 3 + 1} />
      </g>);
  }
  const subO = seg(mt, T.deal + 2.2, T.deal + 3.4) * (1 - seg(mt, T.desc, T.desc + 1));
  const substrate = subO > 0.02 ? (
    <g opacity={subO * 0.5} filter="url(#ll-chalk)">
      {[0, 1, 2, 3].map((i) => (
        <rect key={i} x={CENTER.x - 92 + i * 2} y={CENTER.y + 232 - i * 3} width="184" height="8" rx="2"
              fill={LAB.panel2} stroke={LAB.chalk} strokeWidth="1" strokeOpacity="0.4" />
      ))}
    </g>
  ) : null;

  const foundDraw = seg(mt, T.found, T.found + 1.1);
  // the protocol foundation sits centred in its frame, then settles to the base
  // as the other solutions appear on top of it
  const protoDY = lerp(-284, 0, seg(mt, T.sols, T.sols + 2.6, EO));
  const agentStag = Math.min(0.55, 4.4 / agentN);

  // legend reveals — each concept written in as it enters the story
  const lgd = {
    research: seg(mt, T.hwT + 0.4, T.hwT + 1.5),
    evidence: seg(mt, T.blue, T.blue + 1.1),
    cleared: seg(mt, T.green, T.green + 1.1),
    innovation: seg(mt, T.purple, T.purple + 1.1),
    thesis: seg(mt, T.wmi + 0.9, T.wmi + 2.0),
    next: seg(mt, T.gem + 1.0, T.gem + 2.1),
  };

  const hwLine = (pts, draw, k) => (
    <Line key={k} pts={pts} w={1.15} color={LAB.chalk} opacity={0.26} draw={draw} />
  );

  const mainFade = 1 - seg(mt, T.erase, T.erase + 1.7);
  const flyDraw = seg(mt, T.fly, T.fly + 9.4, EO);

  return (
    <svg viewBox="0 0 1920 1080" width="100%" height="100%" preserveAspectRatio="xMidYMid meet"
         style={{ position: 'absolute', inset: 0, display: 'block' }}>
      <window.LabDefs grit={1.5} />
      <rect x="0" y="0" width="1920" height="1080" fill={LAB.ground} />
      <rect x="0" y="0" width="1920" height="1080" filter="url(#ll-dust)" />
      <rect x="0" y="0" width="1920" height="1080" fill="url(#ll-vign)" />

      <g opacity={mainFade}>
      {/* ── the three stages, drawn one at a time ── */}
      <ZoneFrame {...FRAMES.left}  seed={2} draw={seg(mt, T.fL, T.fL + 1.6)} glow={LAB.blue} />
      <ZoneFrame {...FRAMES.mid}   seed={5} draw={seg(mt, T.fM, T.fM + 1.6)} glow={LAB.chalk} />
      <ZoneFrame {...FRAMES.right} seed={8} draw={seg(mt, T.fR, T.fR + 1.6)} glow={LAB.purple} />
      {L ? (
        <g>
          <HandText text="BASIC RESEARCH" x={FRAMES.left.x + FRAMES.left.w / 2} y={LABEL_Y} size={21} color={LAB.chalk}
                    anchor="middle" seed={71} jr={1.5} opacity={0.72} filter="url(#ll-chalk)" reveal={seg(mt, T.fL + 0.8, T.fL + 2.1)} />
          <HandText text="ORIENTED BASIC RESEARCH" x={FRAMES.mid.x + FRAMES.mid.w / 2} y={LABEL_Y} size={21} color={LAB.chalk}
                    anchor="middle" seed={72} jr={1.5} opacity={0.72} filter="url(#ll-chalk)" reveal={seg(mt, T.fM + 0.8, T.fM + 2.1)} />
          <HandText text="APPLIED RESEARCH · SOLUTION DESIGN" x={FRAMES.right.x + FRAMES.right.w / 2} y={LABEL_Y} size={21} color={LAB.chalk}
                    anchor="middle" seed={73} jr={1.5} opacity={0.72} filter="url(#ll-chalk)" reveal={seg(mt, T.fR + 0.8, T.fR + 2.1)} />
        </g>
      ) : null}

      {/* ── the two highways — drawn in the direction their traffic runs ── */}
      <g>
        {g.ltop.map((pts, k) => hwLine(pts, seg(mt, T.hwT + k * 0.16, T.hwT + 0.9 + k * 0.16), 'lt' + k))}
        {g.rtop.map((pts, k) => hwLine(pts, seg(mt, T.hwT + 0.9 + k * 0.16, T.hwT + 1.8 + k * 0.16), 'rt' + k))}
        {g.rbot.map((pts, k) => hwLine(pts, seg(mt, T.hwB + k * 0.16, T.hwB + 0.9 + k * 0.16), 'rb' + k))}
        {g.lbot.map((pts, k) => hwLine(pts, seg(mt, T.hwB + 0.9 + k * 0.16, T.hwB + 1.8 + k * 0.16), 'lb' + k))}
      </g>

      {/* the orbs — information moving between phases of work */}
      <g>{pulseNodes}</g>

      {/* ── the protocol foundation ── */}
      {foundDraw > 0.01 ? (
        <g transform={`translate(${FOUNDATION.x + FOUNDATION.w / 2} ${FOUNDATION.y + FOUNDATION.h / 2 + protoDY})`} filter="url(#ll-chalk)">
          <path d={boxPath(FOUNDATION.w, FOUNDATION.h, 14, 61, 2.2)} fill={LAB.chalk} fillOpacity={0.02 * seg(foundDraw, 0.6, 1)}
                stroke={LAB.chalk} strokeWidth="1.6" strokeOpacity="0.34" {...dashDraw(foundDraw)} />
          <line x1={-FOUNDATION.w / 2 + 12} y1={FOUNDATION.h / 2 - 6} x2={FOUNDATION.w / 2 - 12} y2={FOUNDATION.h / 2 - 6}
                stroke={LAB.chalk} strokeWidth="2.4" strokeOpacity={0.4 * seg(foundDraw, 0.5, 1)} />
        </g>
      ) : null}
      {L ? GROUPS.map((gr) => (
        <HandText key={gr.id} text={gr.id} x={gr.x} y={gr.y + (gr.era === 'foundation' ? protoDY : 0)} size={15} color={LAB.gold}
                  anchor="middle" seed={gr.id.length * 7} jr={1.5} opacity={0.75} filter="url(#ll-chalk)"
                  reveal={gr.era === 'foundation' ? seg(mt, T.found + 0.3, T.found + 1.4) : seg(mt, T.sols - 0.3, T.sols + 0.9)} />
      )) : null}

      {/* ── the research field, sketched in ── */}
      {g.agents.map((a) => {
        const draw = seg(mt, T.agents + a.i * agentStag, T.agents + a.i * agentStag + 1.1);
        if (draw <= 0.01) return null;
        const fl = 0.75 + 0.25 * Math.sin(mt * 3 + a.i * 1.3);
        const cur = Math.sin(mt * 3.6 + a.i) > 0 ? 1 : 0.2;
        const ty = Math.sin(mt * 0.8 + a.i) * 1.3 * seg(draw, 0.9, 1);
        return (
          <g key={'ag' + a.i} transform={`translate(${a.x} ${a.y + ty})`}>
            <AgentCell w={140} h={82} flicker={fl} cursor={cur} label={`agent ${a.i + 1}`} showLabel={L} seed={a.i * 4 + 2} draw={draw} />
          </g>
        );
      })}

      {/* ── the solutions, built bottom-up as the story earns them ── */}
      {SOLUTIONS.map((s) => {
        const st = solSchedule(s);
        if (st.draw <= 0.01) return null;
        const br = Math.sin(mt * 0.7 + s.i) * 1.1 * seg(st.draw, 0.9, 1);
        return (
          <g key={'so' + s.i} transform={`translate(${s.x} ${s.y + br + (s.era === 'foundation' ? protoDY : 0)})`}>
            <SolutionCell w={s.w} h={s.h} label={s.id} showLabel={L} bright={st.bright} progress={st.progress} seed={s.i * 6 + 5} draw={st.draw} />
          </g>
        );
      })}

      {/* ── hero: the TRs deal out over their substrate ── */}
      {substrate}
      <g>{trCards}</g>

      {/* ── WMI: the current thesis, later the predecessor beneath ── */}
      {wmiDraw > 0.01 ? (
        <g transform={`translate(${wmiPos.x} ${wmiPos.y}) scale(${wmiConsolidate})`}>
          <ThesisBox w={wmiW} h={wmiH} label="WMI" showLabel={L} coreAngle={coreAngle} glow={wmiGlow} seed={7} draw={wmiDraw} />
        </g>
      ) : null}

      {/* ── GEM: thought → descent → the new thesis, drawn in ── */}
      {gemCloudO > 0.01 ? (
        <g transform={`translate(${CENTER.x} ${gemY + bob}) scale(${0.84 + 0.16 * gemForm})`} opacity={gemCloudO}>
          <ThoughtCloud label={null} showLabel={L} seed={3} />
        </g>
      ) : null}
      {gemBoxDraw > 0.01 ? (
        <g transform={`translate(${CENTER.x} ${gemY})`}>
          <ThesisBox w={176} h={188} label="GEM" showLabel={L} coreAngle={coreAngle} glow={gemBoxDraw} seed={12} draw={gemBoxDraw} />
        </g>
      ) : null}
      <Line pts={g.upLine} w={1.6} color={LAB.gold} opacity={0.5 * upDraw} draw={upDraw} />

      {/* ── the next (unnamed) thought — the cycle visibly turning ── */}
      {nextForm > 0.01 ? (
        <g transform={`translate(${CENTER.x} ${THOUGHT_Y + newBob}) scale(${0.84 + 0.16 * nextForm})`} opacity={nextForm * 0.92}>
          <ThoughtCloud w={186} h={104} label={null} showLabel={L} seed={31} spark={0.6 + 0.4 * Math.sin(mt * 2)} />
        </g>
      ) : null}

      {/* ── title + legend, written as the story introduces each idea ── */}
      {L ? (
        <g>
          <HandText text="THE LIVING LAB" x={72} y={74} size={38} color={LAB.chalk} anchor="start" seed={2} jr={2}
                    filter="url(#ll-chalk)" reveal={seg(mt, T.title, T.title + 1.7)} />
          <HandText text="how the lab turns research into governed solutions" x={74} y={106} size={17} color={LAB.chalk}
                    anchor="start" seed={8} jr={1.5} opacity={0.7} filter="url(#ll-chalk)" reveal={seg(mt, T.sub, T.sub + 1.5)} />
          <HandText text="RESEARCH" x={1158} y={42} size={12} color={LAB.chalk} anchor="middle" seed={41} jr={1} opacity={0.5} reveal={lgd.research} />
          <HandText text="DEVELOPMENT" x={1418} y={42} size={12} color={LAB.chalk} anchor="middle" seed={42} jr={1} opacity={0.5} reveal={lgd.cleared} />
          <HandText text="THESIS" x={1706} y={42} size={12} color={LAB.chalk} anchor="middle" seed={43} jr={1} opacity={0.5} reveal={lgd.thesis} />
          <g>
            <line x1={1044} y1={68} x2={1070} y2={68} stroke={LAB.chalk} strokeWidth="2" opacity={0.85 * lgd.research} />
            <HandText text="research" x={1078} y={73} size={15} color={LAB.chalk} anchor="start" seed={21} jr={1} opacity={0.78} reveal={lgd.research} />
            <circle cx={1184} cy={68} r={5} fill={LAB.blue} opacity={lgd.evidence} />
            <HandText text="evidence" x={1196} y={73} size={15} color={LAB.chalk} anchor="start" seed={22} jr={1} opacity={0.78} reveal={lgd.evidence} />
            <circle cx={1306} cy={68} r={5} fill={LAB.green} opacity={lgd.cleared} />
            <HandText text="cleared" x={1318} y={73} size={15} color={LAB.chalk} anchor="start" seed={25} jr={1} opacity={0.78} reveal={lgd.cleared} />
            <circle cx={1410} cy={68} r={5} fill={LAB.purple} opacity={lgd.innovation} />
            <HandText text="innovation" x={1422} y={73} size={15} color={LAB.chalk} anchor="start" seed={26} jr={1} opacity={0.78} reveal={lgd.innovation} />
            <rect x={1566} y={61} width={14} height={14} rx="2" fill="none" stroke={LAB.gold} strokeWidth="2" opacity={lgd.thesis} />
            <HandText text="thesis" x={1590} y={73} size={15} color={LAB.chalk} anchor="start" seed={23} jr={1} opacity={0.78} reveal={lgd.thesis} />
            <path d="M1686 70 q-5 -9 4 -10 q2 -8 10 -4 q8 -3 7 6 q6 3 -2 6 l-16 0 q-7 1 -3 -3 Z" fill="none" stroke={LAB.chalk}
                  strokeWidth="1.6" strokeDasharray="3 3" opacity={lgd.next} />
            <HandText text="next thesis" x={1716} y={73} size={15} color={LAB.chalk} anchor="start" seed={24} jr={1} opacity={0.78} reveal={lgd.next} />
          </g>
          <line x1={72} y1={128} x2={1010} y2={128} stroke={LAB.chalk} strokeOpacity="0.16" strokeWidth="1.2"
                pathLength="1" strokeDasharray="1" strokeDashoffset={1 - seg(mt, T.sub + 0.6, T.sub + 1.8)} />
        </g>
      ) : null}
      </g>

      {flyDraw > 0.001 ? <window.Flywheel draw={flyDraw} mt={mt} labels={L} /> : null}
    </svg>
  );
}

Object.assign(window, { Scene, SEQ_END_SCENE: SEQ_END });
