/* ============================================================
   app.jsx — root, scroll reveal, Tweaks
   本番版: tweaks-panel.jsx は読み込まないため、Tweaks UI は
   window.TweaksPanel が未定義のとき自動的に非表示になる。
   設定値は下記 TWEAK_DEFAULTS（捺印インパクト案 = 表紙）で固定。
   ============================================================ */

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "heroVariant": "impact",
  "goldTone": "#C9A84C",
  "showTexture": true,
  "scrollAnim": true
}/*EDITMODE-END*/;

function useReveal(active, dep) {
  React.useEffect(() => {
    const all = () => document.querySelectorAll('.reveal, .reveal-scale');
    if (!active) {
      // animations off: ensure everything visible, nothing armed
      document.body.classList.remove('reveal-armed');
      all().forEach(el => el.classList.remove('in-view'));
      return;
    }
    let cleanups = [];
    let disarmed = false;
    const disarm = () => {
      disarmed = true;
      // Force every reveal element to its visible state with transition:none,
      // so values snap immediately even if the CSS clock is frozen mid-transition.
      all().forEach(el => {
        el.style.transition = 'none';
        el.style.opacity = '1';
        el.style.transform = 'none';
      });
      document.body.classList.remove('reveal-armed');
    };
    const check = () => {
      if (disarmed) return;
      const vh = window.innerHeight;
      all().forEach(el => {
        if (el.classList.contains('in-view')) return;
        const r = el.getBoundingClientRect();
        if (r.top < vh * 0.92 && r.bottom > 0) el.classList.add('in-view');
      });
    };
    const onScroll = () => window.requestAnimationFrame(check);

    // Only arm the hidden/animated state if rAF fires.
    const raf1 = requestAnimationFrame(() => {
      document.body.classList.add('reveal-armed');
      // arm hidden state this frame, reveal in-viewport els next frame so the
      // above-the-fold content actually transitions in.
      const raf2 = requestAnimationFrame(check);
      window.addEventListener('scroll', onScroll, { passive: true });
      window.addEventListener('resize', onScroll, { passive: true });
      cleanups.push(() => cancelAnimationFrame(raf2));
      cleanups.push(() => window.removeEventListener('scroll', onScroll));
      cleanups.push(() => window.removeEventListener('resize', onScroll));

      // CRITICAL SAFETY NET: rAF firing does NOT guarantee the CSS transition
      // clock advances (performance.now() and rAF can run while compositor
      // animations are frozen). If in-view elements are still invisible after
      // a beat, the transition clock is dead — disarm so content can never
      // stay hidden. In a healthy browser these have already faded to ~1.
      const safety = setTimeout(() => {
        if (disarmed) return;
        const inView = [...all()].filter(el => el.classList.contains('in-view'));
        const stuck = inView.length === 0 ||
          inView.some(el => parseFloat(getComputedStyle(el).opacity) < 0.02);
        if (stuck) disarm();
      }, 1300);
      cleanups.push(() => clearTimeout(safety));
    });

    return () => {
      cancelAnimationFrame(raf1);
      cleanups.forEach(fn => fn());
    };
  }, [active, dep]);
}

function App() {
  // tweaks-panel.jsx is excluded in production → fall back to React.useState
  // so the chosen defaults are applied and the editor UI stays absent.
  const useTw = window.useTweaks || React.useState;
  const [t, setTweak] = useTw(TWEAK_DEFAULTS);

  React.useEffect(() => {
    document.body.classList.toggle('no-anim', !t.scrollAnim);
  }, [t.scrollAnim]);

  React.useEffect(() => {
    document.documentElement.style.setProperty('--gold', t.goldTone);
  }, [t.goldTone]);

  React.useEffect(() => {
    document.body.classList.toggle('no-texture', !t.showTexture);
  }, [t.showTexture]);

  // re-run reveal whenever hero variant changes (DOM swaps)
  useReveal(t.scrollAnim, t.heroVariant);

  // Tweaks UI components — undefined when tweaks-panel.jsx is not loaded.
  const TweaksPanel = window.TweaksPanel;
  const TweakSection = window.TweakSection;
  const TweakRadio = window.TweakRadio;
  const TweakColor = window.TweakColor;
  const TweakToggle = window.TweakToggle;

  return (
    <React.Fragment>
      <Nav />
      <main>
        <Hero variant={t.heroVariant} key={t.heroVariant} />
        <Problem />
        <Feature />
        <Trust />
        <Pricing />
        <CTAForm />
      </main>
      <Footer />

      {TweaksPanel && (
        <TweaksPanel>
          <TweakSection label="Hero レイアウト" />
          <TweakRadio label="構成" value={t.heroVariant}
            options={[
              { value: 'centered', label: '正統' },
              { value: 'split', label: '対比' },
              { value: 'impact', label: '捺印' },
            ]}
            onChange={(v) => setTweak('heroVariant', v)} />
          <TweakSection label="意匠" />
          <TweakColor label="ゴールド" value={t.goldTone}
            options={['#C9A84C', '#E8C97A', '#B8923A', '#D4B25A']}
            onChange={(v) => setTweak('goldTone', v)} />
          <TweakToggle label="背景テクスチャ" value={t.showTexture}
            onChange={(v) => setTweak('showTexture', v)} />
          <TweakToggle label="スクロール演出" value={t.scrollAnim}
            onChange={(v) => setTweak('scrollAnim', v)} />
        </TweaksPanel>
      )}
    </React.Fragment>
  );
}

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