/* global React, ReactDOM */
const { useState, useEffect, useRef, useMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "displayFont": "Eurostile Ext",
  "bodyFont": "Neue Haas",
  "edgeGlow": true,
  "glowStrength": 0.55,
  "showMobileNudge": true,
  "showBrand": false,
  "showLabels": false,
  "headlineCopy": "Angel Rocket",
  "logoLayout": "inner",
  "homeButtonStyle": "arrow"
}/*EDITMODE-END*/;

const FONT_DISPLAY_OPTIONS = ['Eurostile Ext', 'Microgramma Ext', 'Neue Haas', 'Manrope'];
const FONT_BODY_OPTIONS = ['Neue Haas', 'Inter', 'Manrope'];

function App() {
  const [t, setTweak] = window.useTweaks(TWEAK_DEFAULTS);

  // Apply font tweaks
  useEffect(() => {
    document.documentElement.style.setProperty('--font-display', `'${t.displayFont}', system-ui, sans-serif`);
    document.documentElement.style.setProperty('--font-body', `'${t.bodyFont}', system-ui, sans-serif`);
  }, [t.displayFont, t.bodyFont]);

  // Apply glow strength
  useEffect(() => {
    document.documentElement.style.setProperty('--glow-strength', String(t.glowStrength ?? 0.55));
  }, [t.glowStrength]);

  const [view, setView] = useState('home'); // 'home' | 'transition' | key
  const [transition, setTransition] = useState(null); // { key, rect }
  // On by default: browsers keep audio silent until the first tap anyway, and holding a panel
  // to listen has to work before anyone has found the mute button inside a province.
  const [soundOn, setSoundOn] = useState(true);
  const autoMutedRef = useRef(false);
  const [isMobile, setIsMobile] = useState(false);
  const [showHint, setShowHint] = useState(false);
  const [entered, setEntered] = useState(false);
  const hintTimerRef = useRef(null);

  useEffect(() => {
    const mq = window.matchMedia('(max-width: 760px), (pointer: coarse)');
    const update = () => setIsMobile(mq.matches);
    update();
    if (mq.addEventListener) mq.addEventListener('change', update);
    else mq.addListener(update);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener('change', update);
      else mq.removeListener(update);
    };
  }, []);

  useEffect(() => {
    if (entered && isMobile && view === 'home') {
      setShowHint(true);
      clearTimeout(hintTimerRef.current);
      hintTimerRef.current = setTimeout(() => setShowHint(false), 4500);
    } else {
      setShowHint(false);
    }
    return () => clearTimeout(hintTimerRef.current);
  }, [entered, isMobile, view]);

  // Unlock audio on the first gesture the browser accepts. iOS only honours touchend/click,
  // so listen on every candidate until the context is actually running.
  useEffect(() => {
    const events = ['pointerdown', 'touchstart', 'touchend', 'click', 'keydown'];
    function unlock() {
      const c = window.AR_AUDIO.unlock();
      if (c && c.state === 'running') events.forEach(e => window.removeEventListener(e, unlock, true));
    }
    events.forEach(e => window.addEventListener(e, unlock, true));
    return () => events.forEach(e => window.removeEventListener(e, unlock, true));
  }, []);

  // Sync mute to engine
  useEffect(() => {
    window.AR_AUDIO.setMuted(!soundOn);
  }, [soundOn]);

  function handleEnter(key, rect, logoBox) {
    setTransition({ key, rect, logoBox });
    setView('transition');
    if (!soundOn) setSoundOn(true); // auto-unmute on entry
    setTimeout(() => window.AR_AUDIO.activate(key, 1000), 60);
  }

  function handleTransitionDone() {
    if (transition) setView(transition.key);
  }

  // Stable identity so the Player's blur listener isn't re-bound every render.
  const muteAmbient = React.useCallback(() => {
    autoMutedRef.current = true;
    setSoundOn(false);
  }, []);

  function handleClose() {
    window.AR_AUDIO.deactivate();
    if (autoMutedRef.current) {
      autoMutedRef.current = false;
      setSoundOn(true);
    }
    setTransition(null);
    setView('home');
  }

  const { Intro, Splash, Expander, Section, MobileNudge } = window.ARComponents;
  const lore = window.AR_LORE;
  const sectionData = view !== 'home' && view !== 'transition' ? lore[view] : null;

  // Tweak controls
  const {
    TweaksPanel, TweakSection, TweakSelect, TweakToggle, TweakText, TweakRadio, TweakSlider
  } = window;

  return (
    <>
      {(view === 'home' || view === 'transition') && (
        <Splash
          onEnter={handleEnter}
          glow={t.edgeGlow}
          isMobile={isMobile}
          headline={t.headlineCopy}
          layout={t.logoLayout}
          showBrand={t.showBrand}
          showLabels={t.showLabels}
          activeKey={transition?.key}
        />
      )}

      {!entered && <Intro headline={t.headlineCopy} isMobile={isMobile} onEnter={() => setEntered(true)} />}

      {entered && view === 'home' && isMobile && (
        <>
          <div className={`mobile-hint ${showHint ? 'show' : ''}`}>Hold to listen · Tap to enter</div>
          {t.showMobileNudge && (
            <MobileNudge messages={[
              'Hold a panel to hear its ambient. Tap to enter the world.',
              'Each quadrant is a province. Pick your weather.',
              'Sound is off until you tap. Toggle it any time inside.'
            ]} onDismiss={() => setTweak('showMobileNudge', false)} />
          )}
        </>
      )}

      {view === 'transition' && transition && (
        <Expander
          rect={transition.rect}
          logoBox={transition.logoBox}
          paneClass={lore[transition.key].panelClass}
          logoSrc={lore[transition.key].logoSrc}
          onDone={handleTransitionDone}
        />
      )}

      {sectionData && (
        <Section
          data={sectionData}
          onClose={handleClose}
          soundOn={soundOn}
          onToggleSound={() => { autoMutedRef.current = false; setSoundOn(s => !s); }}
          onListen={muteAmbient}
          homeButtonStyle={t.homeButtonStyle}
        />
      )}

      <TweaksPanel title="Tweaks">
        <TweakSection label="Type">
          <TweakSelect
            label="Display font"
            value={t.displayFont}
            options={FONT_DISPLAY_OPTIONS}
            onChange={(v) => setTweak('displayFont', v)}
          />
          <TweakSelect
            label="Body font"
            value={t.bodyFont}
            options={FONT_BODY_OPTIONS}
            onChange={(v) => setTweak('bodyFont', v)}
          />
        </TweakSection>
        <TweakSection label="Splash">
          <TweakRadio
            label="Logo layout"
            value={t.logoLayout}
            options={[
              { value: 'inner', label: 'Inner' },
              { value: 'centered', label: 'Centered' }
            ]}
            onChange={(v) => setTweak('logoLayout', v)}
          />
          <TweakToggle
            label="Show province labels"
            value={t.showLabels}
            onChange={(v) => setTweak('showLabels', v)}
          />
          <TweakToggle
            label="Show 'Angel Rocket' wordmark"
            value={t.showBrand}
            onChange={(v) => setTweak('showBrand', v)}
          />
          <TweakText
            label="Wordmark text"
            value={t.headlineCopy}
            onChange={(v) => setTweak('headlineCopy', v)}
          />
          <TweakToggle
            label="Edge glow on hover"
            value={t.edgeGlow}
            onChange={(v) => setTweak('edgeGlow', v)}
          />
          <TweakSlider
            label="Glow strength"
            value={t.glowStrength}
            min={0} max={1} step={0.05}
            onChange={(v) => setTweak('glowStrength', v)}
          />
          <TweakToggle
            label="Mobile clippy nudge"
            value={t.showMobileNudge}
            onChange={(v) => setTweak('showMobileNudge', v)}
          />
        </TweakSection>
        <TweakSection label="Section page">
          <TweakRadio
            label="Home button"
            value={t.homeButtonStyle}
            options={[
              { value: 'arrow', label: '←' },
              { value: 'text', label: '← Home' },
              { value: 'close', label: '×' },
              { value: 'grid', label: '⊞' }
            ]}
            onChange={(v) => setTweak('homeButtonStyle', v)}
          />
        </TweakSection>
      </TweaksPanel>
    </>
  );
}

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