/* Phasor — page sections */

const { useState, useEffect, useRef, useMemo } = React;

// ---- Reveal: stagger upward fade on scroll ----
const Reveal = ({ children, delay = 0, className = "", as = "div" }) => {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    // Initial visibility check via bounding rect (so things already in viewport reveal even if IO never fires)
    const checkNow = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      if (r.top < vh * 0.95 && r.bottom > 0) { setSeen(true); return true; }
      return false;
    };
    if (checkNow()) return;
    let scrollHandler = null;
    let io = null;
    try {
      io = new IntersectionObserver(([e]) => {
        if (e.isIntersecting) { setSeen(true); io && io.disconnect(); window.removeEventListener('scroll', scrollHandler); }
      }, { threshold: 0.05, rootMargin: '0px 0px -8% 0px' });
      io.observe(el);
    } catch (_) {}
    // Belt-and-suspenders: also watch scroll, since IO can be flaky in some iframe contexts
    scrollHandler = () => { if (checkNow()) { window.removeEventListener('scroll', scrollHandler); io && io.disconnect(); } };
    window.addEventListener('scroll', scrollHandler, { passive: true });
    // Final fallback: reveal after a beat regardless
    const fallback = setTimeout(() => setSeen(true), 1200);
    return () => { io && io.disconnect(); window.removeEventListener('scroll', scrollHandler); clearTimeout(fallback); };
  }, []);
  const Cmp = as;
  return (
    <Cmp ref={ref} style={{ transitionDelay: `${delay}ms` }} className={`reveal ${seen ? 'in' : ''} ${className}`}>
      {children}
    </Cmp>
  );
};

// ---- Line-art icons (drawn here, no Heroicons) ----
const I = {
  Plug: (p) => (
    <svg viewBox="0 0 32 32" fill="none" stroke="currentColor" strokeWidth="1.25" strokeLinecap="square" {...p}>
      <path d="M11 5v7M21 5v7" />
      <rect x="8" y="12" width="16" height="6" rx="0" />
      <path d="M16 18v4M12 22h8M16 26v2" />
    </svg>
  ),
  Grid: (p) => (
    <svg viewBox="0 0 32 32" fill="none" stroke="currentColor" strokeWidth="1.25" {...p}>
      <rect x="5" y="5" width="8" height="8" /><rect x="19" y="5" width="8" height="8" />
      <rect x="5" y="19" width="8" height="8" /><rect x="19" y="19" width="8" height="8" />
      <circle cx="9" cy="9" r="1.2" fill="currentColor" />
    </svg>
  ),
  Wave: (p) => (
    <svg viewBox="0 0 32 32" fill="none" stroke="currentColor" strokeWidth="1.25" strokeLinecap="square" {...p}>
      <path d="M2 16 H7 L9 6 L13 26 L17 9 L21 23 L25 13 L27 16 H30" />
    </svg>
  ),
  Arrow: (p) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.25" {...p}>
      <path d="M5 12h14M13 6l6 6-6 6" />
    </svg>
  ),
  Cross: (p) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" {...p}>
      <path d="M12 2v20M2 12h20" />
      <circle cx="12" cy="12" r="3" />
    </svg>
  ),
  Code: (p) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.25" {...p}>
      <path d="M9 7l-5 5 5 5M15 7l5 5-5 5" />
    </svg>
  ),
};

// ---- HEADER / NAV ----
const Header = () => {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 8);
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  return (
    <header className={`fixed top-0 inset-x-0 z-50 transition-all duration-300 ease-phasor ${scrolled ? 'bg-black/60 backdrop-blur-md border-b border-line' : ''}`}>
      <div className="max-w-[1440px] mx-auto px-8 h-16 flex items-center justify-between">
        <a href="/landing" target="_top" className="flex items-center gap-2.5">
          <PhasorMark size={18} />
          <span className="font-mono text-[13px] tracking-widest uppercase">phasor</span>
        </a>
        <nav className="hidden md:flex items-center gap-8 font-mono text-[12px] uppercase tracking-widest text-mid">
          <a href="#grid" className="hover:text-ink transition-colors duration-150">Visualizers</a>
          <a href="#how" className="hover:text-ink transition-colors duration-150">How it works</a>
          <a href="#byo" className="hover:text-ink transition-colors duration-150">BYO-LLM</a>
          <a href="#spec" className="hover:text-ink transition-colors duration-150">Spec</a>
        </nav>
        <div className="flex items-center gap-2">
          <a href="https://github.com/" target="_top" rel="noopener noreferrer" className="hidden sm:inline-flex items-center gap-2 font-mono text-[12px] uppercase tracking-widest text-mid hover:text-ink transition-colors duration-150">GitHub</a>
          <a href="/player" target="_top" className="inline-flex items-center gap-2 px-3 h-8 hairline font-mono text-[11px] uppercase tracking-widest hover:bg-ink hover:text-black ease-phasor transition-colors duration-150">
            Open in browser <I.Arrow className="w-3.5 h-3.5" />
          </a>
        </div>
      </div>
    </header>
  );
};

const PhasorMark = ({ size = 16 }) => (
  <svg width={size} height={size} viewBox="0 0 16 16" fill="none">
    <circle cx="8" cy="8" r="7.25" stroke="#e8e8e8" strokeWidth="0.8" />
    <path d="M2 8 Q5 1, 8 8 T14 8" stroke="#e8e8e8" strokeWidth="0.8" fill="none" />
  </svg>
);

// ---- HERO ----
const Hero = () => {
  const [bpm, setBpm] = useState(124);
  const [tick, setTick] = useState(0);
  // pulse the BPM chip in time
  useEffect(() => {
    const beatMs = 60000 / 124;
    let id = setInterval(() => setTick(t => (t+1) % 4), beatMs);
    return () => clearInterval(id);
  }, []);
  return (
    <section className="relative h-screen min-h-[760px] w-full overflow-hidden bg-black">
      <div className="absolute inset-0">
        <FluidCanvas density={0.7} intensity={1.0} />
      </div>
      {/* darkening overlay for legibility */}
      <div className="absolute inset-0 pointer-events-none" style={{
        background: 'radial-gradient(ellipse at 30% 50%, rgba(0,0,0,0) 0%, rgba(0,0,0,0.55) 70%)'
      }} />
      <div className="absolute inset-0 pointer-events-none bg-gradient-to-b from-black/40 via-transparent to-black/70" />

      {/* bpm chip top-right */}
      <div className="absolute top-20 right-8 pointer-events-none">
        <div className="hairline bg-black/50 backdrop-blur-md px-3 py-2 font-mono text-[10.5px] uppercase tracking-[0.18em] text-mid flex items-center gap-3">
          <span className="flex items-center gap-1.5"><span className={`inline-block w-1.5 h-1.5 rounded-full ${tick === 0 ? 'bg-[#7cffb4]' : 'bg-[#7cffb4]/30'}`} />BPM 124</span>
          <span className="w-px h-3 bg-line" />
          <span>4/4</span>
          <span className="w-px h-3 bg-line" />
          <span className="text-ink">PORT_01 · LAUNCHKEY</span>
          <span className="w-px h-3 bg-line" />
          <span>3.4 ms</span>
        </div>
      </div>

      {/* corner crosshair marks */}
      <CornerMark cls="top-20 left-8" />
      <CornerMark cls="bottom-8 right-8" rotate={180} />

      {/* foreground */}
      <div className="relative z-10 h-full max-w-[1440px] mx-auto px-8 flex flex-col">
        <div className="flex-1" />
        <div className="pb-32 max-w-[1100px]">
          <Reveal delay={0}>
            <div className="font-mono text-[11px] uppercase tracking-[0.22em] text-mid mb-8 flex items-center gap-3">
              <span className="inline-block w-6 h-px bg-mid" />
              <span>v0.4 — open beta</span>
            </div>
          </Reveal>
          <Reveal delay={40}>
            <h1 className="font-display font-black text-[88px] leading-[0.92] tracking-[-0.035em] text-ink">
              Your MIDI.
            </h1>
          </Reveal>
          <Reveal delay={80}>
            <h1 className="font-display font-black text-[88px] leading-[0.92] tracking-[-0.035em] text-ink">
              Your code.
            </h1>
          </Reveal>
          <Reveal delay={120}>
            <h1 className="font-display font-black text-[88px] leading-[0.92] tracking-[-0.035em] text-ink/55">
              Your visuals.
            </h1>
          </Reveal>
          <Reveal delay={220}>
            <p className="mt-10 max-w-[560px] text-[17px] leading-[1.55] text-mid">
              A browser-based realtime MIDI visualizer for live performers, modular nerds and ambient sets — built around a GPU shader pipeline you can extend in pure TypeScript.
            </p>
          </Reveal>
          <Reveal delay={300}>
            <div className="mt-10 flex items-center gap-3">
              <a href="/player" target="_top" className="inline-flex items-center gap-3 h-11 px-5 bg-ink text-black font-mono text-[12px] uppercase tracking-[0.18em] hover:bg-white transition-colors duration-150">
                Open in browser <I.Arrow className="w-4 h-4" />
              </a>
              <a href="/spec" target="_top" className="inline-flex items-center gap-3 h-11 px-5 hairline font-mono text-[12px] uppercase tracking-[0.18em] text-ink hover:bg-ink hover:text-black transition-colors duration-150">
                Read the spec
              </a>
              <span className="ml-2 hidden md:inline-flex items-center gap-2 font-mono text-[11px] uppercase tracking-[0.18em] text-dim">
                <span className="inline-block w-1.5 h-1.5 bg-dim rotate-45" /> requires webmidi · chrome / edge
              </span>
            </div>
          </Reveal>
        </div>
        {/* footer ticker */}
        <div className="pb-6 flex items-center justify-between font-mono text-[10.5px] uppercase tracking-[0.22em] text-dim">
          <span>scroll · 06 sections</span>
          <span className="hidden md:inline">webgl2 · half-float · 60fps</span>
          <span>↓</span>
        </div>
      </div>
    </section>
  );
};

const CornerMark = ({ cls = "", rotate = 0 }) => (
  <div className={`absolute ${cls} pointer-events-none`} style={{ transform: `rotate(${rotate}deg)` }}>
    <svg width="22" height="22" viewBox="0 0 22 22" fill="none">
      <path d="M0 0H8M0 0V8" stroke="#e8e8e8" strokeWidth="1" />
    </svg>
  </div>
);

// ---- SECTION HEADER ----
const SectionHeader = ({ index, kicker, title, subtitle }) => (
  <div className="flex flex-col gap-6 mb-16 max-w-[1100px]">
    <Reveal>
      <div className="font-mono text-[11px] uppercase tracking-[0.22em] text-mid flex items-center gap-3">
        <span>{index}</span>
        <span className="inline-block w-6 h-px bg-mid/60" />
        <span>{kicker}</span>
      </div>
    </Reveal>
    <Reveal delay={40}>
      <h2 className="font-display font-bold text-[56px] leading-[0.95] tracking-[-0.025em] max-w-[900px]">{title}</h2>
    </Reveal>
    {subtitle && (
      <Reveal delay={80}>
        <p className="text-[17px] leading-[1.55] text-mid max-w-[640px]">{subtitle}</p>
      </Reveal>
    )}
  </div>
);

// ---- 2: LIVE GRID ----
const VIZ_TILES = [
  { id: 'particle-field', label: 'particle-field', sub: 'attractor · 240 pts', Cmp: window.MiniViz.ParticleField },
  { id: 'oscilloscope',   label: 'oscilloscope',   sub: 'lissajous · x/y',   Cmp: window.MiniViz.Oscilloscope },
  { id: 'hex-floor',      label: 'hex-floor',      sub: 'wireframe · sequenced', Cmp: window.MiniViz.HexFloor },
  { id: 'chladni',        label: 'chladni',        sub: 'plate · m=4 n=5',    Cmp: window.MiniViz.Chladni },
  { id: 'plasma-sphere',  label: 'plasma-sphere',  sub: 'raymarch · glsl',    Cmp: window.MiniViz.PlasmaSphere },
  { id: 'marbled',        label: 'marbled',        sub: 'fbm warp · 5 oct',   Cmp: window.MiniViz.Marbled },
];

const LiveGrid = () => {
  const [hover, setHover] = useState(null);
  return (
    <section id="grid" className="relative bg-black border-t border-line py-32">
      <div className="max-w-[1440px] mx-auto px-8">
        <SectionHeader
          index="02 / Live Grid"
          kicker="Six visualizers · running now"
          title={<>Every tile is rendering. Live. <span className="text-mid">Pick one and ship the set.</span></>}
          subtitle="Procedural visualizers shipped in the box. WebGL2 + Canvas2D. Pause when offscreen."
        />
        <div className="grid grid-cols-2 md:grid-cols-3 gap-px bg-line hairline">
          {VIZ_TILES.map((t, i) => {
            const dimmed = hover !== null && hover !== i;
            const Active = t.Cmp;
            return (
              <div
                key={t.id}
                className="relative aspect-[4/3] bg-black overflow-hidden group"
                onMouseEnter={() => setHover(i)}
                onMouseLeave={() => setHover(null)}
                style={{
                  transition: 'opacity 600ms cubic-bezier(0.16,1,0.3,1), transform 600ms cubic-bezier(0.16,1,0.3,1)',
                  opacity: dimmed ? 0.32 : 1,
                  transform: hover === i ? 'scale(1.02)' : 'scale(1.0)',
                  zIndex: hover === i ? 5 : 1,
                }}
              >
                <Active active={hover === i} />
                <div className="absolute inset-0 pointer-events-none">
                  {/* corner ticks */}
                  <CornerTick cls="top-3 left-3" />
                  <CornerTick cls="top-3 right-3" rotate={90} />
                  <CornerTick cls="bottom-3 left-3" rotate={-90} />
                  <CornerTick cls="bottom-3 right-3" rotate={180} />
                </div>
                <div className="absolute left-3 bottom-3 right-3 flex items-end justify-between font-mono text-[10.5px] uppercase tracking-[0.18em] pointer-events-none">
                  <div className="flex flex-col gap-1">
                    <span className="text-ink">{t.label}</span>
                    <span className="text-dim">{t.sub}</span>
                  </div>
                  <span className="text-dim">{String(i+1).padStart(2,'0')} / 06</span>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </section>
  );
};

const CornerTick = ({ cls = "", rotate = 0 }) => (
  <div className={`absolute ${cls}`} style={{ transform: `rotate(${rotate}deg)` }}>
    <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
      <path d="M0 0 H6 M0 0 V6" stroke="#e8e8e8" strokeWidth="1" opacity="0.7" />
    </svg>
  </div>
);

// ---- 3: HOW IT WORKS ----
const StepDiagramConnect = () => {
  // animated pulse traveling from device to laptop
  const [t, setT] = useState(0);
  useEffect(() => {
    let id = 0; let s = performance.now();
    const loop = () => { setT((performance.now() - s) / 1000); id = requestAnimationFrame(loop); };
    loop();
    return () => cancelAnimationFrame(id);
  }, []);
  const pulses = [0.0, 0.33, 0.66];
  return (
    <svg viewBox="0 0 240 120" className="w-full h-auto">
      {/* MIDI device */}
      <rect x="6" y="40" width="60" height="40" stroke="#e8e8e8" strokeWidth="1" fill="none" />
      <line x1="14" y1="50" x2="14" y2="58" stroke="#e8e8e8" strokeWidth="1" />
      <line x1="22" y1="50" x2="22" y2="62" stroke="#e8e8e8" strokeWidth="1" />
      <line x1="30" y1="50" x2="30" y2="56" stroke="#e8e8e8" strokeWidth="1" />
      <line x1="38" y1="50" x2="38" y2="60" stroke="#e8e8e8" strokeWidth="1" />
      <circle cx="56" cy="70" r="3" stroke="#e8e8e8" strokeWidth="1" fill="none" />
      <text x="36" y="92" fontFamily="Geist Mono" fontSize="6" fill="#5a5a5a" textAnchor="middle">CONTROLLER</text>
      {/* cable */}
      <path d="M66 60 C 110 60, 130 60, 174 60" stroke="#3a3a3a" strokeWidth="1" fill="none" />
      {pulses.map((p, i) => {
        const tt = (t * 0.5 + p) % 1;
        const x = 66 + tt * (174 - 66);
        return <circle key={i} cx={x} cy={60} r="2" fill="#7cffb4" />;
      })}
      {/* laptop */}
      <rect x="174" y="42" width="56" height="32" stroke="#e8e8e8" strokeWidth="1" fill="none" />
      <rect x="170" y="74" width="64" height="3" stroke="#e8e8e8" strokeWidth="1" fill="none" />
      <text x="202" y="92" fontFamily="Geist Mono" fontSize="6" fill="#5a5a5a" textAnchor="middle">PHASOR · :3000</text>
    </svg>
  );
};

const StepDiagramPick = () => {
  const [hover, setHover] = useState(2);
  useEffect(() => {
    const id = setInterval(() => setHover(h => (h+1) % 6), 1100);
    return () => clearInterval(id);
  }, []);
  return (
    <svg viewBox="0 0 240 120" className="w-full h-auto">
      {Array.from({ length: 6 }).map((_, i) => {
        const x = 8 + (i % 3) * 76;
        const y = 14 + Math.floor(i / 3) * 50;
        const sel = i === hover;
        return (
          <g key={i}>
            <rect x={x} y={y} width="62" height="38" stroke={sel ? '#e8e8e8' : '#3a3a3a'} strokeWidth={sel ? 1.4 : 1} fill={sel ? '#111' : 'none'} />
            {/* tiny waveform inside */}
            <path d={`M ${x+4} ${y+22} Q ${x+12} ${y+10}, ${x+20} ${y+22} T ${x+36} ${y+22} T ${x+58} ${y+22}`} stroke={sel ? '#e8e8e8' : '#5a5a5a'} strokeWidth="0.8" fill="none" />
            {sel && <rect x={x-2} y={y-2} width="66" height="42" stroke="#7cffb4" strokeWidth="0.6" fill="none" strokeDasharray="3 2" />}
          </g>
        );
      })}
    </svg>
  );
};

const StepDiagramPerform = () => {
  // sequencer grid pulsing notes
  const [t, setT] = useState(0);
  useEffect(() => {
    let id = 0; const s = performance.now();
    const loop = () => { setT((performance.now() - s) / 1000); id = requestAnimationFrame(loop); };
    loop();
    return () => cancelAnimationFrame(id);
  }, []);
  const cols = 16, rows = 4;
  return (
    <svg viewBox="0 0 240 120" className="w-full h-auto">
      {Array.from({ length: rows }).map((_, r) =>
        Array.from({ length: cols }).map((_, c) => {
          const x = 8 + c * 14;
          const y = 14 + r * 22;
          const seed = (r * 7 + c * 3) % 11;
          const beat = Math.floor(t * 4) % cols;
          const lit = beat === c;
          const has = (seed % 3 === 0) || (seed % 5 === 0);
          return (
            <rect key={`${r}-${c}`} x={x} y={y} width="11" height="14"
                  stroke={has ? (lit ? '#e8e8e8' : '#5a5a5a') : '#1a1a1a'} strokeWidth="0.8"
                  fill={lit && has ? '#7cffb4' : 'none'} />
          );
        })
      )}
      <text x="120" y="112" fontFamily="Geist Mono" fontSize="6" fill="#5a5a5a" textAnchor="middle">16 STEPS · 4 LANES · LIVE</text>
    </svg>
  );
};

const HowItWorks = () => {
  const steps = [
    { n: '01', icon: <I.Plug className="w-7 h-7" />, title: 'Connect MIDI', body: 'Plug a controller, modular bridge, or DAW. Phasor speaks Web MIDI directly — no driver, no install. Sysex too, if your gear is weird.', diagram: <StepDiagramConnect /> },
    { n: '02', icon: <I.Grid className="w-7 h-7" />, title: 'Pick a visualizer', body: 'Six built-ins, plus anything you or someone else has dropped into the registry. Switch mid-set. Map a CC to do it for you.', diagram: <StepDiagramPick /> },
    { n: '03', icon: <I.Wave className="w-7 h-7" />, title: 'Perform', body: 'Map any control to any uniform. Velocity to bloom, mod-wheel to chroma, channel pressure to chaos. Hot-swap shaders without losing the set.', diagram: <StepDiagramPerform /> },
  ];
  return (
    <section id="how" className="relative bg-black border-t border-line py-32">
      <div className="max-w-[1440px] mx-auto px-8">
        <SectionHeader
          index="03 / How it works"
          kicker="Three steps · zero install"
          title={<>Open the URL. Plug in. <span className="text-mid">Play the room.</span></>}
        />
        <div className="grid grid-cols-1 md:grid-cols-3 gap-px bg-line hairline">
          {steps.map((s, i) => (
            <Reveal key={s.n} delay={i*40} className="bg-black p-10 flex flex-col gap-8 min-h-[420px]">
              <div className="flex items-start justify-between">
                <span className="font-mono text-[64px] leading-none font-light tracking-tight text-ink">{s.n}</span>
                <span className="text-mid">{s.icon}</span>
              </div>
              <div className="flex-1">
                <h3 className="font-display text-[26px] leading-tight tracking-tight mb-3">{s.title}</h3>
                <p className="text-[15px] leading-[1.55] text-mid max-w-[360px]">{s.body}</p>
              </div>
              <div className="border-t border-line pt-6 -mx-2">{s.diagram}</div>
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
};

window.SectionsA = { Header, Hero, LiveGrid, HowItWorks, Reveal, SectionHeader, I, PhasorMark };
