/* app.jsx — entry reveal, hero, nav, music, overlays, composition */
const { useState: useS, useEffect: useE, useRef: useR } = React;

/* ---- fun looping piano (royalty-free, synthesized — no audio file) ---------
   Bright, celebratory I–V–vi–IV arpeggio with a struck-string envelope + echo. */
function makeAmbient() {
  let ctx, master, lp, delay, fb, wet, timer, on = false, step = 0;

  const CH = (b, a, c, d) => ({ bass: b, arp: [a, c, d, c] });
  const prog = [
    CH(130.81, 261.63, 329.63, 392.00),  // C
    CH(98.00, 246.94, 293.66, 392.00),   // G
    CH(110.00, 261.63, 329.63, 440.00),  // Am
    CH(87.31, 261.63, 349.23, 440.00),   // F
  ];
  const STEP = 0.38;

  function voice(freq, t, dur, peak) {
    const g = ctx.createGain();
    g.gain.setValueAtTime(0.0001, t);
    g.gain.exponentialRampToValueAtTime(peak, t + 0.01);
    g.gain.exponentialRampToValueAtTime(0.0001, t + dur);
    g.connect(lp);
    const o1 = ctx.createOscillator(); o1.type = 'triangle'; o1.frequency.value = freq;
    const o2 = ctx.createOscillator(); o2.type = 'sine'; o2.frequency.value = freq * 2;
    const g2 = ctx.createGain(); g2.gain.value = 0.28; o2.connect(g2); g2.connect(g);
    o1.connect(g);
    o1.start(t); o2.start(t); o1.stop(t + dur + 0.1); o2.stop(t + dur + 0.1);
  }

  function tick() {
    if (!on) return;
    const t = ctx.currentTime + 0.06;
    const chord = prog[Math.floor(step / 4) % prog.length];
    const idx = step % 4;
    if (idx === 0) voice(chord.bass, t, 2.2, 0.14);
    voice(chord.arp[idx], t, 1.8, 0.18);
    step++;
    timer = setTimeout(tick, STEP * 1000);
  }

  return {
    toggle() {
      if (!on) {
        ctx = ctx || new (window.AudioContext || window.webkitAudioContext)();
        if (ctx.state === 'suspended') ctx.resume();
        if (!master) {
          master = ctx.createGain(); master.gain.value = 0; master.connect(ctx.destination);
          lp = ctx.createBiquadFilter(); lp.type = 'lowpass'; lp.frequency.value = 3200; lp.connect(master);
          delay = ctx.createDelay(); delay.delayTime.value = 0.3;
          fb = ctx.createGain(); fb.gain.value = 0.24;
          wet = ctx.createGain(); wet.gain.value = 0.22;
          lp.connect(delay); delay.connect(fb); fb.connect(delay); delay.connect(wet); wet.connect(master);
        }
        on = true; step = 0;
        master.gain.cancelScheduledValues(ctx.currentTime);
        master.gain.setTargetAtTime(0.85, ctx.currentTime, 0.8);
        tick();
      } else {
        on = false;
        clearTimeout(timer);
        if (master) master.gain.setTargetAtTime(0, ctx.currentTime, 0.5);
      }
      return on;
    },
    get on() { return on; },
  };
}
const ambient = makeAmbient();

function Entry({ onEnter }) {
  const [breaking, setBreaking] = useS(false);
  const sparks = React.useMemo(() => Array.from({ length: 22 }, () => ({
    l: Math.random() * 100, t: Math.random() * 100, d: Math.random() * 3, s: 2 + Math.random() * 3, sz: 2 + Math.random() * 3,
  })), []);
  const open = () => {
    if (breaking) return;
    setBreaking(true);
    try { ambient.toggle(); } catch (e) {}
    setTimeout(onEnter, 950);
  };
  return (
    <div id="entry" className={breaking ? 'gone' : ''}>
      {sparks.map((s, i) => (
        <span key={i} className="spark" style={{ left: s.l + '%', top: s.t + '%', width: s.sz, height: s.sz, animation: `sparkFloat ${s.s}s ${s.d}s ease-in-out infinite` }} />
      ))}
      <div className={`entry-inner ${breaking ? 'dismiss' : ''}`}>
        <span className="kicker">You're invited to celebrate</span>
        <div className="entry-sub">Rajshree turns fifty</div>
        <div className={`seal ${breaking ? 'broken' : ''}`} onClick={open}><span>R</span></div>
        <div className="tap-hint">Tap the seal to open</div>
      </div>
    </div>
  );
}

function Hero() {
  const heroRef = useR(null);
  const cardRef = useR(null);
  useE(() => {
    const cleanDust = window.R50FX ? window.R50FX.heroDust(heroRef.current) : null;
    let cleanTilt = null;
    if (cardRef.current && window.R50FX) {
      // entrance, then enable parallax tilt
      const a = cardRef.current.animate(
        [{ opacity: 0, transform: 'translateY(42px) scale(.96)' }, { opacity: 1, transform: 'none' }],
        { duration: 1300, delay: 250, easing: 'cubic-bezier(.2,.7,.2,1)', fill: 'backwards' }
      );
      a.onfinish = () => { cleanTilt = window.R50FX.tilt(cardRef.current, 6); };
    }
    return () => { cleanDust && cleanDust(); cleanTilt && cleanTilt(); };
  }, []);
  return (
    <section id="hero" ref={heroRef}>
      <div className="hero-card" ref={cardRef}>
        <div className="frame-in" />
        <img className="hero-photo" src="assets/rajshree-circle-v2.jpg" alt="Rajshree" />
        <div className="hero-name">Rajshree</div>
        <div className="hero-turns">turns</div>
        <div className="hero-fifty gold-text">50</div>
        <p className="hero-msg">An afternoon of love, laughter, and five wonderful decades worth celebrating.</p>
      </div>
      <a className="scroll-cue" href="#countdown"><span>Scroll</span><span className="chev" /></a>
    </section>
  );
}

function Nav({ onMusic, musicOn }) {
  const [solid, setSolid] = useS(false);
  const [open, setOpen] = useS(false);
  useE(() => {
    const h = () => setSolid(window.scrollY > 80);
    window.addEventListener('scroll', h); h();
    return () => window.removeEventListener('scroll', h);
  }, []);
  return (
    <nav id="nav" className={solid ? 'solid' : ''}>
      <span className="brand"></span>
      <div className="links">
        {SECTION_LINKS.map(([label, id]) => <a key={id} href={'#' + id}>{label}</a>)}
      </div>
      <button className="nav-toggle" onClick={() => setOpen(!open)}>{open ? '✕' : '☰'}</button>
      {open && (
        <div style={{ position: 'absolute', top: '100%', right: 16, background: 'rgba(22,17,12,.96)', borderRadius: 12, padding: '14px 20px', display: 'flex', flexDirection: 'column', gap: 14, border: '1px solid var(--line)' }}>
          {SECTION_LINKS.map(([label, id]) => <a key={id} href={'#' + id} onClick={() => setOpen(false)} style={{ color: '#d8ccb5', textDecoration: 'none', fontSize: 12, letterSpacing: '.18em', textTransform: 'uppercase' }}>{label}</a>)}
        </div>
      )}
    </nav>
  );
}

function Lightbox({ item, onClose }) {
  if (!item) return null;
  return (
    <div id="lightbox" className="on" onClick={onClose}>
      <button className="lb-close" onClick={onClose}>✕</button>
      {item.type === 'image'
        ? <img className="lb-media" src={item.src} alt={item.caption || ''} onClick={(e) => e.stopPropagation()} />
        : <video className="lb-media" src={item.src} controls autoPlay playsInline onClick={(e) => e.stopPropagation()} />}
    </div>
  );
}

function Slideshow({ list, onClose }) {
  const [i, setI] = useS(0);
  useE(() => {
    if (!list) return;
    const id = setInterval(() => setI((x) => (x + 1) % list.length), 4200);
    const key = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', key);
    return () => { clearInterval(id); window.removeEventListener('keydown', key); };
  }, [list]);
  if (!list) return null;
  const m = list[i];
  return (
    <div id="slideshow" className="on">
      <button className="ss-close" onClick={onClose}>✕</button>
      <div className="ss-count">{i + 1} / {list.length}</div>
      <img className="slide-media" src={m.src} alt="" key={m.id} />
      {(m.name || m.caption) && <div className="slide-cap"><b>{m.caption || ''}</b>{m.name ? '— ' + m.name : ''}</div>}
    </div>
  );
}

function App() {
  const [entered, setEntered] = useS(false);
  const [lightItem, setLightItem] = useS(null);
  const [slides, setSlides] = useS(null);
  const [toast, setToast] = useS('');
  const [musicOn, setMusicOn] = useS(false);
  const toastTimer = useR(null);

  useE(() => {
    window.R50UI = {
      toast: (msg) => {
        setToast(msg);
        clearTimeout(toastTimer.current);
        toastTimer.current = setTimeout(() => setToast(''), 2600);
      },
      lightbox: (item) => setLightItem(item),
      slideshow: (list) => { if (list && list.length) setSlides(list); },
    };
  }, []);

  useE(() => { document.body.classList.toggle('locked', !entered); }, [entered]);

  // scroll progress ribbon
  useE(() => {
    const bar = document.getElementById('progress');
    const h = () => {
      const max = document.documentElement.scrollHeight - window.innerHeight;
      const p = max > 0 ? window.scrollY / max : 0;
      if (bar) bar.style.transform = 'scaleX(' + p + ')';
    };
    window.addEventListener('scroll', h, { passive: true }); h();
    return () => window.removeEventListener('scroll', h);
  }, [entered]);

  const toggleMusic = () => { try { setMusicOn(ambient.toggle()); } catch (e) {} };

  return (
    <>
      <div id="progress"></div>
      {entered && <GoldDustControls />}
      {!entered && <Entry onEnter={() => { setEntered(true); setMusicOn(ambient.on); }} />}
      <Nav />
      <Hero />
      <Countdown />
      <Invitation />
      <Details />
      <Rsvp />
      <Guestbook />
      <Gallery />
      <footer>
        <div className="f-name script">Rajshree turns 50</div>
        <div className="f-meta">
          Saturday, July 11<sup>th</sup> 2026 · 4:00 PM<br />
          1934 Saint Andrews Ct, Jamison, PA 18929<br />
          RSVP: Rajshree 302.397.4407 · Sri 610.505.4453
        </div>
      </footer>

      <button id="music-btn" className={musicOn ? 'playing' : ''} onClick={toggleMusic} title={musicOn ? 'Mute music' : 'Play music'}>
        {musicOn ? <span className="eq"><i></i><i></i><i></i><i></i></span> : '♪'}
      </button>

      <Lightbox item={lightItem} onClose={() => setLightItem(null)} />
      {slides && <Slideshow list={slides} onClose={() => setSlides(null)} />}
      <div id="toast" className={toast ? 'show' : ''}>{toast}</div>
    </>
  );
}

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