// scenes2.jsx — ScreenSync: recording → timeline editor → trim → annotate → pack GIF.
const { useRef, useEffect } = React;
const ease = Easing;
const interp = interpolate;

const STAGE_W = 1080, STAGE_H = 1200;
const CX = STAGE_W / 2, CYP = 560;
const PANEL_L = CX - PW / 2, PANEL_T = CYP - PH / 2;

function pulse(t, c, r, f) {
  if (t < c - r || t > c + f) return 0;
  if (t <= c) return ease.easeOutQuad((t - (c - r)) / r);
  return 1 - ease.easeInQuad((t - c) / f);
}

function Background() {
  return null;
}

function StepCaption({ text, op }) {
  if (op <= 0.01) return null;
  return (
    <div style={{ position: 'absolute', left: CX, top: 60, transform: 'translate(-50%,-50%)', opacity: op, zIndex: 20 }}>
      <div style={{ display: 'inline-flex', alignItems: 'center', gap: 9, background: '#fff', borderRadius: 999, padding: '9px 18px', boxShadow: '0 10px 30px rgba(0,0,0,0.35)', fontFamily: 'Geist, sans-serif', fontWeight: 600, fontSize: 15.5, color: '#171717', letterSpacing: '-0.01em' }}>
        <ScreenSyncMark size={18} />{text}
      </div>
    </div>
  );
}

function Movie() {
  const t = useTime();

  /* Cursor path — marker tool → card top-left → DRAG to bottom-right (draws the
     selection box) → hold during playback → export. Hold beats after each action
     let every moment register before the next move begins. */
  const ck  = [1.7, 2.45, 4.2, 4.9, 5.7, 6.7, 9.9, 10.6, 10.8, 13.6];
  // drag endpoints snap to the marquee's actual corners (cursor tip = xy + (5,3)):
  //   TL corner ≈ stage (434,403) → cursor (429,400) · BR corner ≈ (539,501) → (534,498)
  const cxv = [760, 202, 202, 429, 429, 534, 534, 540, 540, 540];
  const cyv = [360, 751, 751, 400, 400, 498, 498, 1009, 1009, 1009];
  const cur = { x: interp(ck, cxv, MEase.inOut)(t), y: interp(ck, cyv, MEase.inOut)(t) };
  const dragPress = MEase.out(clamp((t - 5.7) / 0.14, 0, 1)) * (1 - MEase.out(clamp((t - 6.72) / 0.22, 0, 1)));
  const press =
    clickPulse(t, 2.55, 0.09, 0.3) +   // click marker tool (springy release)
    dragPress +                        // mouse held while dragging the box
    clickPulse(t, 10.8, 0.09, 0.3);    // export click (springy release)

  /* scene 1 — figma canvas zoom in (slow tier, smooth in-out glide) */
  const figCam = ease.easeInOutCubic(clamp((t - 0.25) / 1.25, 0, 1));
  const figOut = ease.easeInOutCubic(clamp((t - 1.5) / 0.5, 0, 1));
  const figOp = MEase.out(clamp(t / 0.45, 0, 1)) * (1 - figOut);
  const figScale = (0.96 + 0.04 * MEase.out(clamp(t / 0.6, 0, 1))) * (1 + figCam * 0.55) * (1 + figOut * 0.25);

  /* editor — cross-dissolves in over the canvas, settles with a hint of overshoot */
  const edIn = MEase.panel(clamp((t - 1.5) / 0.8, 0, 1));
  const edOp = MEase.out(clamp((t - 1.5) / 0.45, 0, 1));
  const edScale = 0.34 + 0.66 * edIn;

  /* recording playhead — parked while the box is drawn + text typed, then plays
     forward at constant speed (content playback is intentionally linear) */
  const playT = interp([2.6, 8.2, 10.0], [2.0, 2.0, 5.6], (x) => x)(t);

  const tool = t >= 2.55 ? 'marker' : 'select';     // marker tool selected
  const annoOn = t >= 5.7;                          // selection box appears on drag start
  const annoIn = MEase.out(clamp((t - 5.7) / 0.32, 0, 1));     // marquee fades in
  const annoDraw = MEase.inOut(clamp((t - 5.7) / 1.0, 0, 1)); // box tracks the cursor's drag glide
  const annoType = clamp((t - 7.0) / 0.85, 0, 1);    // then "Click here" types onto the card
  const exportPressed = clickPulse(t, 10.8, 0.09, 0.3);

  /* Two straight camera moves, no bends:
     · move 1 (marker click @2.55→3.1): a straight pan/zoom onto the marker tool;
       the cursor waits here until the move lands before continuing.
     · move 2 (@3.2→3.75): a single straight pan up to the card's draw area as the
       cursor relocates, then LOCKS — it does not chase the marquee as it's drawn.
     A third return reveals the export button and restores the framing — paced to
     mirror the entrance: same slow ease, same dwell-at-each-landing cadence so
     the whole edit reads at one consistent, measured tempo with no abrupt beat. */
  const camKeys = [2.55, 3.5, 4.2, 4.9, 9.5, 10.5, 10.8, 12.0];
  const camS  = interp([2.55, 3.5, 4.2, 4.9, 9.5, 10.5, 10.8, 12.0], [1, 1.5, 1.5, 1.6, 1.6, 1.18, 1.18, 1], MEase.inOut)(t);
  const camFx = interp(camKeys, [540, 300, 300, 500, 500, 528, 528, 540], MEase.inOut)(t);
  const camFy = interp(camKeys, [600, 690, 690, 470, 470, 642, 642, 600], MEase.inOut)(t);
  const camT = `translate(${540 - camS * camFx}px, ${600 - camS * camFy}px) scale(${camS})`;

  /* GIF result — scrim cross-dissolves, then the card settles in */
  const gifShow = t > 10.95;
  const gifP = clamp((t - 11.1) / 1.5, 0, 1);
  const scrim = (gifShow ? 1 : 0) * MEase.out(clamp((t - 10.95) / 0.35, 0, 1)) * 0.62;

  /* closing fade-out — mirrors the fade-in at the start */
  const fadeOut = MEase.out(clamp((13.6 - t) / 0.45, 0, 1));

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: fadeOut }}>
      <div style={{ position: 'absolute', inset: 0, transformOrigin: '0 0', transform: camT, willChange: 'transform' }}>
      {figOp > 0.01 && (
        <div style={{ position: 'absolute', left: CX, top: CYP, transform: `translate(-50%,-50%) scale(${figScale})`, opacity: figOp, willChange: 'transform' }}>
          <FigmaRecWindow camAmt={figCam} />
        </div>
      )}

      {edOp > 0.01 && (
        <div style={{ position: 'absolute', left: CX, top: CYP, transform: `translate(-50%,-50%) scale(${edScale})`, opacity: edOp, willChange: 'transform' }}>
          <TimelineEditor playT={playT} tool={tool} annoOn={annoOn} annoType={annoType} annoDraw={annoDraw} annoIn={annoIn} trimRight={1} exportPressed={exportPressed} t={t} />
        </div>
      )}

      <Cursor x={cur.x} y={cur.y} pressed={press} opacity={t > 10.95 ? clamp(1 - (t - 10.95) / 0.3, 0, 1) : MEase.out(clamp((t - 1.95) / 0.4, 0, 1))} />
      </div>

      {scrim > 0.001 && <div style={{ position: 'absolute', inset: 0, background: `rgba(6,6,7,${scrim})`, zIndex: 25 }} />}
      {gifShow && (
        <div style={{ position: 'absolute', inset: 0, zIndex: 26 }}>
          <GifResult p={gifP} t={t} />
        </div>
      )}
    </div>
  );
}

function TimeLabeller({ rootRef }) {
  const time = useTime();
  useEffect(() => { if (rootRef.current) rootRef.current.setAttribute('data-screen-label', `t=${time.toFixed(0)}s`); }, [Math.floor(time)]);
  return null;
}
function DevSeek() {
  const tl = useTimeline();
  useEffect(() => { window.__seek = (x) => { tl.setPlaying(false); tl.setTime(x); }; window.__play = () => tl.setPlaying(true); }, [tl]);
  return null;
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "globalSpeed": 1
}/*EDITMODE-END*/;

function App() {
  const rootRef = useRef(null);
  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);
  return (
    <div ref={rootRef} data-screen-label="t=0s" style={{ position: 'absolute', inset: 0 }}>
      {/* speed ×1.4 → the 13.6s timeline plays in ~9.7s; relaxed pacing throughout */}
      <Stage width={STAGE_W} height={STAGE_H} duration={13.6} speed={tw.globalSpeed * 1.4} background="transparent" persistKey="screensync-gif15" chrome={false}>
        <Background />
        <TimeLabeller rootRef={rootRef} />
        <DevSeek />
        <Movie />
      </Stage>

      <TweaksPanel title="Tweaks">
        <TweakSection label="速度 · Speed" />
        <TweakSlider label="整体速度" value={tw.globalSpeed} min={0.5} max={2} step={0.05} unit="×" onChange={(v) => setTweak('globalSpeed', v)} />
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
