// crovi-scenes.jsx — individual scene components composed inside <Stage>.

// Identity passthrough for color tokens; the real palette flipper lives in
// primitives.jsx but its const isn't always reachable across <script
// type="text/babel"> boundaries (Babel TS preset can erase single-letter
// identifiers). Default to identity, which is correct for the dark theme.
const tt = (typeof window !== 'undefined' && typeof window.T === 'function')
  ? window.T
  : (s) => s;

const STAGE_W = 1920;
const STAGE_H = 1080;

// Prompt phrases — each entry: text, optional "key" flag (gets highlighted).
// "make no mistakes :)" gets the close-up smile-marker treatment.
const PROMPT_PARTS = [
  { t: 'Earliest-stage advanced adenomas', key: true, hl: 0 },
  { t: ' + ' },
  { t: 'matched plasma', key: true, hl: 1 },
  { t: ' (' },
  { t: '2 tube types', key: true, hl: 2 },
  { t: ') + ' },
  { t: 'adjacent non-adenoma tissue', key: true, hl: 3 },
  { t: '. ' },
  { t: 'Age-matched controls', key: true, hl: 4 },
  { t: ', ' },
  { t: 'make no mistakes', key: true, hl: 5, special: true },
  { t: ' :)' },
];

// Total chars (for typing animation if needed)
const PROMPT_FULL = PROMPT_PARTS.map(p => p.t).join('');

// ─── Scene 1: Prompt comprehension (0.0 – 4.0s) ─────────────────────────────
// • search bar appears
// • full prompt is already visible (no typewriter — it's a fait accompli being parsed)
// • key phrases highlight one by one as the agent "reads"
// • final highlight on "make no mistakes" with held close-up + smile glyph
function Scene1Prompt() {
  const { localTime: t, duration } = useSprite();

  // Highlight schedule: which key indices are "lit" by what time.
  // 6 highlights over ~3s, then hold ~1s.
  const HL_TIMES = [0.55, 0.95, 1.35, 1.7, 2.05, 2.5];
  // For each key, compute opacity & sweep progress (marker swipe in)
  const hlProgress = (i) => {
    const start = HL_TIMES[i];
    const dur = 0.45;
    if (t < start) return 0;
    if (t > start + dur) return 1;
    return Easing.easeOutCubic((t - start) / dur);
  };

  // Camera zoom: hold normal until ~2.4s, then slow zoom toward "make no mistakes"
  const zoomStart = 2.4;
  const zoomEnd = 3.4;
  let zoom = 1;
  let camX = 0, camY = 0;
  if (t > zoomStart) {
    const z = clamp((t - zoomStart) / (zoomEnd - zoomStart), 0, 1);
    const eased = Easing.easeInOutCubic(z);
    zoom = 1 + 0.42 * eased;
    // pan slightly down-right to center on "make no mistakes" — it sits late in the line
    camX = -260 * eased;
    camY = -40 * eased;
  }

  // Search bar entrance (first 0.5s)
  const barProg = Easing.easeOutCubic(clamp(t / 0.55, 0, 1));
  const barOpacity = barProg;
  const barTy = (1 - barProg) * 18;

  // Eyebrow "PARSING REQUEST" — fades in around 0.2s; HOLDS through end of scene
  // (no fade-out: scene 2 takes over from this exact frame and continues the camera move)
  const eyebrowOp = (() => {
    if (t < 0.25) return 0;
    if (t < 0.7) return (t - 0.25) / 0.45;
    return 1;
  })();

  // Hairline brackets that pulse around the prompt while parsing — hold to end
  const bracketOp = (() => {
    if (t < 0.4) return 0;
    return 0.55 + 0.25 * Math.sin(t * 3);
  })();

  // Smile/checkmark glyph after "make no mistakes" lights
  const smileStart = HL_TIMES[5] + 0.25;
  const smileOp = clamp((t - smileStart) / 0.4, 0, 1);
  const smileScale = 0.6 + 0.4 * Easing.easeOutBack(clamp((t - smileStart) / 0.5, 0, 1));

  // Background ambient: soft brand glow that intensifies once parse begins
  const ambientOp = clamp((t - 0.3) / 0.8, 0, 0.7);

  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: C.ink,
      overflow: 'hidden',
      fontFamily: C.body,
    }}>
      {/* ambient background glow */}
      <div style={{
        position: 'absolute',
        left: '50%', top: '50%',
        width: 1400, height: 600,
        marginLeft: -700, marginTop: -300,
        background: `radial-gradient(ellipse at center, ${C.brandGlow}, transparent 65%)`,
        opacity: ambientOp,
        filter: 'blur(20px)',
        pointerEvents: 'none',
      }}/>

      {/* faint background wordmark */}
      <div style={{
        position: 'absolute',
        left: 0, right: 0, bottom: -120,
        textAlign: 'center',
        fontFamily: C.display,
        fontStyle: 'italic',
        fontSize: 480,
        color: C.ink2,
        opacity: 0.45,
        letterSpacing: '-0.04em',
        lineHeight: 1,
        pointerEvents: 'none',
        userSelect: 'none',
      }}>crovi</div>

      {/* camera-zoom wrapper around the prompt area */}
      <div style={{
        position: 'absolute', inset: 0,
        transform: `translate(${camX}px, ${camY}px) scale(${zoom})`,
        transformOrigin: 'center center',
        willChange: 'transform',
      }}>
        {/* search-bar shell — clean prompt card, no top/bottom chrome */}
        <div style={{
          position: 'absolute',
          left: '50%', top: '50%',
          transform: `translate(-50%, calc(-50% + ${barTy}px))`,
          opacity: barOpacity,
          width: 1400,
          background: tt('oklch(0.09 0.012 250 / 0.92)'),
          border: `1px solid ${C.ink3}`,
          borderRadius: 22,
          padding: '40px 44px',
          backdropFilter: 'blur(14px)',
          boxShadow: tt(`0 30px 80px oklch(0 0 0 / 0.5), 0 0 0 1px oklch(0.74 0.14 195 / ${0.08 + 0.12 * ambientOp / 0.7}) inset`),
        }}>
          {/* The prompt itself — the only thing inside the card */}
          <div style={{
            fontFamily: C.display,
            fontSize: 50,
            lineHeight: 1.28,
            letterSpacing: '-0.015em',
            color: C.inkText,
          }}>
            {PROMPT_PARTS.map((p, i) => {
              if (!p.key) {
                return <span key={i} style={{ color: C.inkText2 }}>{p.t}</span>;
              }
              const prog = hlProgress(p.hl);
              return (
                <PromptKey key={i} text={p.t} progress={prog} special={p.special}/>
              );
            })}
          </div>
        </div>

        {/* "→ Source" forward toggle — single accent that appears after the
            prompt finishes parsing, signalling progression to the search agent. */}
        {smileOp > 0 && (
          <div style={{
            position: 'absolute',
            left: '50%', top: 'calc(50% + 30px)',
            transform: `translate(420px, 30px) scale(${smileScale})`,
            opacity: smileOp,
            display: 'flex', alignItems: 'center', gap: 8,
            padding: '8px 14px',
            background: tt(`oklch(0.74 0.14 195 / 0.18)`),
            border: `1px solid ${C.brandHi}`,
            borderRadius: 999,
            color: C.brandHi,
            fontFamily: C.mono,
            fontSize: 12,
            letterSpacing: '0.14em',
            textTransform: 'uppercase',
            boxShadow: `0 0 24px ${C.brandGlow}`,
          }}>
            Source
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
              <path d="M2 7 H11 M7 3 L11 7 L7 11"
                stroke={C.brandHi} strokeWidth="1.6"
                strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
          </div>
        )}
      </div>
    </div>
  );
}

// A key phrase span — animates a marker-swipe highlight from left to right,
// and fades the text from secondary to primary as the marker fills.
function PromptKey({ text, progress, special }) {
  const color = interpolate([0, 1], [0.5, 1])(progress); // text emphasis
  const textColor = tt(`oklch(${0.55 + 0.35 * progress} 0.02 60)`);
  // marker fill width (left-to-right wipe)
  const fillW = `${progress * 100}%`;

  if (special) {
    // "make no mistakes" — bigger, italic, with strong gradient + slight scale-up at full
    const scale = 1 + 0.04 * Easing.easeOutBack(progress);
    return (
      <span style={{
        position: 'relative',
        display: 'inline-block',
        fontStyle: 'italic',
        fontWeight: 500,
        color: progress > 0.95 ? 'transparent' : textColor,
        background: progress > 0.95
          ? `linear-gradient(120deg, ${C.brandHi}, ${C.amberHi})`
          : 'transparent',
        WebkitBackgroundClip: progress > 0.95 ? 'text' : 'border-box',
        backgroundClip: progress > 0.95 ? 'text' : 'border-box',
        transform: `scale(${scale})`,
        transformOrigin: 'left center',
        transition: 'color 200ms',
        padding: '0 2px',
      }}>
        <span style={{
          position: 'absolute',
          left: 0, bottom: '12%',
          width: fillW,
          height: '38%',
          background: tt(`linear-gradient(120deg, oklch(0.74 0.14 195 / 0.4), oklch(0.78 0.13 45 / 0.4))`),
          borderRadius: 2,
          zIndex: -1,
          pointerEvents: 'none',
        }}/>
        {text}
      </span>
    );
  }

  // standard key phrase: marker swipe + color
  return (
    <span style={{
      position: 'relative',
      display: 'inline-block',
      color: textColor,
      transition: 'color 200ms',
    }}>
      <span style={{
        position: 'absolute',
        left: 0, bottom: '14%',
        width: fillW,
        height: '34%',
        background: tt(`oklch(0.74 0.14 195 / 0.28)`),
        borderRadius: 2,
        zIndex: -1,
        pointerEvents: 'none',
      }}/>
      {text}
    </span>
  );
}

// Small "parsing" bar indicator — three vertical bars with sequenced heights.
function ParseBars({ t }) {
  const bars = [0, 1, 2];
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', gap: 3, height: 12 }}>
      {bars.map(i => {
        const phase = (t * 4 + i * 0.5) % 2;
        const h = 4 + Math.abs(Math.sin(phase * Math.PI)) * 8;
        return (
          <div key={i} style={{
            width: 2, height: h,
            background: C.brandHi,
            borderRadius: 1,
          }}/>
        );
      })}
    </div>
  );
}

window.Scene1Prompt = Scene1Prompt;
window.PromptKey = PromptKey;
window.PROMPT_PARTS = PROMPT_PARTS;
window.ParseBars = ParseBars;
window.STAGE_W = STAGE_W;
window.STAGE_H = STAGE_H;
