/* App: live-preview mode by default (single direction, full viewport, native scroll),
   with a "compare" mode that puts A & B side-by-side in a design canvas.
   Audio chip swaps tracks per chapter as recipient scrolls. */

const { useState: useStateApp, useEffect: useEffectApp, useRef: useRefApp, useCallback: useCallbackApp } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "viewMode": "preview",
  "previewDirection": "a",
  "showOnlyDirection": "both",
  "palette": "warm-light",
  "typePair": "fraunces",
  "grain": false,
  "audioFollowsDirection": "a"
}/*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [activeChapter, setActiveChapter] = useStateApp(null);
  const sectionsA = useRefApp(new Map());
  const sectionsB = useRefApp(new Map());

  const openingChapter = window.MEMORIES && {
    id: '__opening',
    eyebrow: window.MEMORIES.opening.eyebrow,
    place: 'OPENING',
    title: window.MEMORIES.opening.title,
    track: window.MEMORIES.opening.track || { artist: '', title: '', file: '' },
    roman: '·',
  };
  const allChapters = window.MEMORIES
    ? [openingChapter, ...window.MEMORIES.chapters]
    : [];

  // body classes for palette/type and view mode
  useEffectApp(() => {
    const cls = document.body.classList;
    [...cls].forEach((c) => {
      if (c.startsWith('palette-') || c.startsWith('type-') || c.startsWith('view-')) cls.remove(c);
    });
    cls.add(`palette-${t.palette}`);
    cls.add(`type-${t.typePair}`);
    cls.add(`view-${t.viewMode}`);
  }, [t.palette, t.typePair, t.viewMode]);

  useEffectApp(() => {
    if (!activeChapter && openingChapter) setActiveChapter(openingChapter);
  }, []);

  const registerA = useCallbackApp((id, el) => { sectionsA.current.set(id, el); }, []);
  const registerB = useCallbackApp((id, el) => { sectionsB.current.set(id, el); }, []);

  // Audio scroll watcher — uses window scroll in preview mode, scroll-frame in compare mode.
  useEffectApp(() => {
    const which = t.viewMode === 'preview' ? t.previewDirection : t.audioFollowsDirection;
    const sections = which === 'a' ? sectionsA.current : sectionsB.current;
    if (!sections.size) return;

    let scroller, getScrollTop, getViewportH;
    if (t.viewMode === 'preview') {
      scroller = window;
      getScrollTop = () => window.scrollY;
      getViewportH = () => window.innerHeight;
    } else {
      const frame = document.querySelector(`.scroll-frame[data-scroll-frame="${which}"]`);
      if (!frame) return;
      scroller = frame;
      getScrollTop = () => frame.scrollTop;
      getViewportH = () => frame.clientHeight;
    }

    const onScroll = () => {
      const top = getScrollTop();
      const triggerLine = top + getViewportH() * 0.25;
      let best = null;
      let bestDist = Infinity;
      for (const [id, el] of sections.entries()) {
        // For window scroll, use offsetTop relative to scroll-frame OR doc
        const offsetTop = t.viewMode === 'preview' ? getDocOffsetTop(el) : el.offsetTop;
        const elBot = offsetTop + el.offsetHeight;
        if (offsetTop <= triggerLine && elBot >= triggerLine) { best = id; break; }
        const dist = Math.min(Math.abs(offsetTop - triggerLine), Math.abs(elBot - triggerLine));
        if (dist < bestDist) { bestDist = dist; best = id; }
      }
      if (best) {
        const ch = allChapters.find(c => c.id === best);
        if (ch && (!activeChapter || activeChapter.id !== ch.id)) setActiveChapter(ch);
      }
    };

    scroller.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => scroller.removeEventListener('scroll', onScroll);
  }, [t.viewMode, t.previewDirection, t.audioFollowsDirection, activeChapter && activeChapter.id]);

  function getDocOffsetTop(el) {
    let top = 0, n = el;
    while (n) { top += n.offsetTop; n = n.offsetParent; }
    return top;
  }

  const showA = t.showOnlyDirection === 'both' || t.showOnlyDirection === 'a';
  const showB = t.showOnlyDirection === 'both' || t.showOnlyDirection === 'b';

  return (
    <>
      {t.viewMode === 'preview' ? (
        <div className="preview-host">
          {t.previewDirection === 'a'
            ? <DirectionA tweaks={t} registerSection={registerA} fullViewport />
            : <DirectionB tweaks={t} registerSection={registerB} fullViewport />}
        </div>
      ) : (
        <DesignCanvas>
          <DCSection
            id="memories"
            title="anniversary memories"
            subtitle="two scrapbook directions — click any artboard to focus and scroll"
          >
            {showA && (
              <DCArtboard id="paper-tape" label="A · paper & tape  —  dense, layered" width={1280} height={820}>
                <DirectionA tweaks={t} registerSection={registerA} />
              </DCArtboard>
            )}
            {showB && (
              <DCArtboard id="quiet" label="B · quiet scrapbook  —  composed, editorial" width={1280} height={820}>
                <DirectionB tweaks={t} registerSection={registerB} />
              </DCArtboard>
            )}
          </DCSection>
        </DesignCanvas>
      )}

      <ChapterAudio activeChapter={activeChapter} chapters={window.MEMORIES?.chapters} />

      <TweaksPanel title="Tweaks">
        <TweakSection label="View" />
        <TweakRadio
          label="Mode"
          value={t.viewMode}
          options={['preview', 'compare']}
          onChange={(v) => setTweak('viewMode', v)}
        />
        {t.viewMode === 'preview' ? (
          <TweakRadio
            label="Show direction"
            value={t.previewDirection}
            options={['a', 'b']}
            onChange={(v) => setTweak('previewDirection', v)}
          />
        ) : (
          <>
            <TweakRadio
              label="Show"
              value={t.showOnlyDirection}
              options={['both', 'a', 'b']}
              onChange={(v) => setTweak('showOnlyDirection', v)}
            />
            <TweakRadio
              label="Audio follows"
              value={t.audioFollowsDirection}
              options={['a', 'b']}
              onChange={(v) => setTweak('audioFollowsDirection', v)}
            />
          </>
        )}

        <TweakSection label="Palette" />
        <TweakSelect
          label="Color mood"
          value={t.palette}
          options={[
            { value: 'warm-light', label: 'Warm light · cream + ivory' },
            { value: 'cream',      label: 'Cream · soft gold' },
            { value: 'blush',      label: 'Blush · rose + peach' },
            { value: 'sepia',      label: 'Sepia · faded film' },
          ]}
          onChange={(v) => setTweak('palette', v)}
        />

        <TweakSection label="Typography" />
        <TweakSelect
          label="Type pair"
          value={t.typePair}
          options={[
            { value: 'fraunces',   label: 'Fraunces + Caveat' },
            { value: 'dm-serif',   label: 'DM Serif Display + EB Garamond' },
            { value: 'cormorant',  label: 'Cormorant + Homemade Apple' },
            { value: 'playfair',   label: 'Playfair + Lora + Patrick Hand' },
          ]}
          onChange={(v) => setTweak('typePair', v)}
        />

        <TweakSection label="Atmosphere" />
        <TweakToggle
          label="Film grain"
          value={t.grain}
          onChange={(v) => setTweak('grain', v)}
        />
      </TweaksPanel>
    </>
  );
}

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