// app.jsx — Stage controller. Hammer animation lives in WheelScene (GSAP-driven).
const { useState, useEffect, useRef, useCallback } = React;

// Phases:
// 'form'        — Scene 1 doctor form, waits for SUBMIT
// 'wheel-intro' — Scene 2 wheel + hammer flies in (GSAP)
// 'aim'         — Hammer wobbles in windup; waiting for click
// 'smash'       — GSAP strike timeline; calls onStrikeImpact at peak
// 'shatter'     — Wheel explodes into shards
// 'reveal'      — Scene 3 NEWCITA PLUS appears

function App() {
  const [phase, setPhase] = useState('form');
  const [cracked, setCracked] = useState(0);
  const [revealProgress, setRevealProgress] = useState(0);
  const [doctor, setDoctor] = useState(null);
  const stageRef = useRef(null);

  const handleFormSubmit = (data) => {
    setDoctor(data);
    setPhase('wheel-intro');
  };

  // wheel-intro → aim transition (give entrance ~1s to play)
  useEffect(() => {
    if (phase !== 'wheel-intro') return;
    const t = setTimeout(() => setPhase('aim'), 950);
    return () => clearTimeout(t);
  }, [phase]);

  // Strike impact callback — fired by GSAP at the strike's onComplete
  const handleStrikeImpact = useCallback(() => {
    // Cracks flood in fast
    gsap.to({ v: 0 }, {
      v: 1, duration: 0.25, ease: 'power2.out',
      onUpdate: function () { setCracked(this.targets()[0].v); },
    });
    // Camera shake via GSAP — violent initial hit then rapid decay
    if (stageRef.current) {
      gsap.fromTo(stageRef.current,
        { x: 0, y: 0 },
        {
          keyframes: [
            { x: -20, y: 12, duration: 0.03 },
            { x: 18,  y: -14, duration: 0.04 },
            { x: -16, y: 10, duration: 0.04 },
            { x: 14,  y: -8, duration: 0.04 },
            { x: -10, y: 6, duration: 0.05 },
            { x: 7,   y: -4, duration: 0.05 },
            { x: -4,  y: 2, duration: 0.05 },
            { x: 0,   y: 0, duration: 0.06 },
          ],
          ease: 'none',
        }
      );
    }
    playImpactRumble();
    // Haptic feedback on supported devices (tablets/phones)
    if (navigator.vibrate) navigator.vibrate([50, 30, 80]);
    // Hold the planted hammer briefly, then shatter
    setTimeout(() => setPhase('shatter'), 380);
  }, []);

  // shatter → reveal
  useEffect(() => {
    if (phase !== 'shatter') return;
    const t = setTimeout(() => setPhase('reveal'), 1500);
    return () => clearTimeout(t);
  }, [phase]);

  // reveal progress
  useEffect(() => {
    if (phase !== 'reveal') return;
    let raf, t0 = performance.now();
    const tick = (t) => {
      const el = (t - t0) / 1000;
      setRevealProgress(Math.min(1, el / 1.5));
      if (el < 1.5) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [phase]);

  const handleWheelClick = () => {
    if (phase === 'aim') setPhase('smash');
  };

  const restart = () => {
    setCracked(0);
    setRevealProgress(0);
    setDoctor(null);
    setPhase('form');
  };

  const showForm = phase === 'form';
  const showWheel = ['wheel-intro', 'aim', 'smash', 'shatter'].includes(phase);
  const showReveal = phase === 'reveal';

  return (
    <div
      ref={stageRef}
      style={{
        position: 'relative',
        width: 1000, height: 600,
        overflow: 'hidden',
        background: BRAND.bg,
        willChange: 'transform',
      }}
    >
      <div style={{ position: 'absolute', inset: 0, overflow: 'hidden' }}>
        {showForm && <FormScene onSubmit={handleFormSubmit} />}
        {showWheel && (
          <WheelScene
            showHammer={['wheel-intro', 'aim', 'smash'].includes(phase)}
            phase={phase}
            cracked={cracked}
            shards={phase === 'shatter'}
            onWheelClick={handleWheelClick}
            onStrikeImpact={handleStrikeImpact}
          />
        )}
        {showReveal && <NewcitaScene progress={revealProgress} />}

        <SceneChip phase={phase} />
      </div>

      {phase === 'reveal' && revealProgress > 0.9 && (
        <button onClick={restart} style={{
          position: 'absolute', right: 30, top: 30,
          padding: '14px 28px', fontSize: 16, fontWeight: 700,
          background: BRAND.blue, color: 'white', border: 'none',
          borderRadius: 999, cursor: 'pointer',
          boxShadow: '0 6px 20px rgba(0,0,0,0.4)',
          minHeight: 48,
          touchAction: 'manipulation',
          WebkitTapHighlightColor: 'transparent',
        }}>
          Replay
        </button>
      )}
    </div>
  );
}

function SceneChip({ phase }) {
  const labels = {
    'form':         { n: '01', label: 'Prescription Form' },
    'wheel-intro':  { n: '02', label: 'The Cycle' },
    'aim':          { n: '02', label: 'Break the Cycle' },
    'smash':        { n: '02', label: 'Impact!' },
    'shatter':      { n: '02', label: 'Shattered' },
    'reveal':       { n: '03', label: 'Newcita Plus' },
  };
  const c = labels[phase] || labels.form;
  return (
    <div style={{
      position: 'absolute', left: 18, top: 18,
      display: 'flex', alignItems: 'center', gap: 6,
      background: 'rgba(11, 59, 142, 0.92)', color: 'white',
      padding: '4px 10px 4px 4px', borderRadius: 999,
      fontSize: 10, fontWeight: 600,
      boxShadow: '0 3px 8px rgba(0,0,0,0.15)',
      zIndex: 10,
    }}>
      <span style={{
        background: BRAND.yellow, color: BRAND.blue,
        width: 18, height: 18, borderRadius: '50%',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontWeight: 800, fontSize: 9,
      }}>{c.n}</span>
      {c.label}
    </div>
  );
}

// Synthesize an impact rumble using WebAudio
function playImpactRumble() {
  try {
    const ctx = new (window.AudioContext || window.webkitAudioContext)();
    const dur = 0.6;

    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.type = 'sine';
    osc.frequency.setValueAtTime(120, ctx.currentTime);
    osc.frequency.exponentialRampToValueAtTime(40, ctx.currentTime + dur);
    gain.gain.setValueAtTime(0.6, ctx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + dur);
    osc.connect(gain).connect(ctx.destination);
    osc.start();
    osc.stop(ctx.currentTime + dur);

    const bufSize = ctx.sampleRate * 0.4;
    const buf = ctx.createBuffer(1, bufSize, ctx.sampleRate);
    const data = buf.getChannelData(0);
    for (let i = 0; i < bufSize; i++) {
      data[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / bufSize, 2);
    }
    const noise = ctx.createBufferSource();
    noise.buffer = buf;
    const noiseGain = ctx.createGain();
    noiseGain.gain.setValueAtTime(0.4, ctx.currentTime);
    noiseGain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.4);
    const filter = ctx.createBiquadFilter();
    filter.type = 'highpass';
    filter.frequency.value = 800;
    noise.connect(filter).connect(noiseGain).connect(ctx.destination);
    noise.start();
  } catch (e) {}
}

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