/* Shared utilities, hooks, and primitives for all 3 LP variants */

/* --- Scroll reveal hook --- */
function useReveal(threshold = 0.15) {
  const ref = React.useRef(null);
  const [shown, setShown] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            setShown(true);
            io.unobserve(e.target);
          }
        });
      },
      { threshold, root: null, rootMargin: '0px 0px -10% 0px' }
    );
    io.observe(ref.current);
    return () => io.disconnect();
  }, [threshold]);
  return [ref, shown];
}

/* --- Scroll progress (0..1 within element) --- */
function useScrollProgress(scrollerRef) {
  const ref = React.useRef(null);
  const [p, setP] = React.useState(0);
  React.useEffect(() => {
    const scroller = scrollerRef?.current;
    if (!ref.current || !scroller) return;
    const el = ref.current;
    function update() {
      const rect = el.getBoundingClientRect();
      const scrollerRect = scroller.getBoundingClientRect();
      const start = scrollerRect.top + scrollerRect.height; // when top of el reaches bottom of scroller
      const top = rect.top; // relative to viewport (which is scroller in this case for the iframe)
      // simpler: use scroller scrollTop relative to element offsetTop
      const offsetTop = el.offsetTop;
      const scrollerH = scroller.clientHeight;
      const scrollTop = scroller.scrollTop;
      const elH = el.offsetHeight;
      const startAt = offsetTop - scrollerH;
      const endAt = offsetTop + elH;
      const raw = (scrollTop - startAt) / (endAt - startAt);
      setP(Math.max(0, Math.min(1, raw)));
    }
    update();
    scroller.addEventListener('scroll', update, { passive: true });
    window.addEventListener('resize', update);
    return () => {
      scroller.removeEventListener('scroll', update);
      window.removeEventListener('resize', update);
    };
  }, [scrollerRef]);
  return [ref, p];
}

/* --- Count up on reveal --- */
function CountUp({ to, duration = 1200, suffix = '' }) {
  const [ref, shown] = useReveal(0.4);
  const [n, setN] = React.useState(0);
  React.useEffect(() => {
    if (!shown) return;
    let raf;
    const start = performance.now();
    const tick = (t) => {
      const p = Math.min(1, (t - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setN(Math.round(to * eased));
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [shown, to, duration]);
  return <span ref={ref}>{n}{suffix}</span>;
}

/* --- Reveal wrapper --- */
function Reveal({ children, delay = 0, y = 24, className = '', as: As = 'div' }) {
  const [ref, shown] = useReveal();
  return (
    <As
      ref={ref}
      className={className}
      style={{
        transform: shown ? 'translateY(0)' : `translateY(${y}px)`,
        opacity: shown ? 1 : 0,
        transition: `transform 1100ms cubic-bezier(.2,.7,.2,1) ${delay}ms, opacity 1100ms ease ${delay}ms`,
      }}
    >
      {children}
    </As>
  );
}

/* --- Placeholder image (striped) ---
   Used until real product photos are dropped in. Pass `kind` to label it. */
function Placeholder({ ratio = '4 / 3', kind = 'photo', tone = 'warm', accent }) {
  const stripes = {
    warm: ['#e8dfd1', '#dfd3c0'],
    green: ['#dfe5d8', '#d4dccb'],
    mono: ['#e8e6e2', '#dcdad6'],
    dark: ['#2a2622', '#322d28'],
  };
  const [a, b] = stripes[tone] || stripes.warm;
  const fg = tone === 'dark' ? 'rgba(255,255,255,.55)' : 'rgba(0,0,0,.45)';
  return (
    <div
      style={{
        aspectRatio: ratio,
        background: `repeating-linear-gradient(135deg, ${a} 0 14px, ${b} 14px 28px)`,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        position: 'relative',
        overflow: 'hidden',
        borderRadius: 2,
      }}
    >
      <div
        style={{
          fontFamily: 'ui-monospace, "SF Mono", Menlo, monospace',
          fontSize: 11,
          letterSpacing: '0.08em',
          color: fg,
          textTransform: 'uppercase',
          padding: '4px 10px',
          background: tone === 'dark' ? 'rgba(0,0,0,.3)' : 'rgba(255,255,255,.7)',
          borderRadius: 999,
        }}
      >
        {kind}
      </div>
      {accent && (
        <div style={{
          position: 'absolute', left: 12, top: 12,
          width: 6, height: 6, borderRadius: 99, background: accent
        }} />
      )}
    </div>
  );
}

/* --- Vertical writing helper --- */
function Tategaki({ children, style }) {
  return (
    <span style={{ writingMode: 'vertical-rl', textOrientation: 'upright', ...style }}>
      {children}
    </span>
  );
}

/* --- Mobile frame chrome (status bar etc) --- */
function MobileChrome({ children, bg = '#fff', innerRef }) {
  return (
    <div style={{
      width: 390,
      height: 844,
      borderRadius: 44,
      background: '#0a0a0a',
      padding: 10,
      boxShadow: '0 30px 60px -20px rgba(0,0,0,.35), 0 0 0 1px rgba(0,0,0,.06)',
      position: 'relative',
    }}>
      <div style={{
        width: '100%', height: '100%', borderRadius: 36, overflow: 'hidden',
        background: bg, position: 'relative',
      }}>
        {/* status bar */}
        <div style={{
          position: 'absolute', top: 0, left: 0, right: 0, height: 44,
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          padding: '0 28px 0 32px', zIndex: 50,
          fontSize: 14, fontWeight: 600, fontFamily: '-apple-system, system-ui',
          color: bg === '#fff' || bg === '#fdfaf3' || bg === '#f6f3ec' ? '#000' : '#fff',
          mixBlendMode: 'difference', filter: 'invert(0)',
        }}>
          <span>9:41</span>
          <span style={{ display: 'flex', gap: 5, alignItems: 'center' }}>
            <svg width="17" height="11" viewBox="0 0 17 11" fill="currentColor"><rect x="0" y="6" width="3" height="5" rx="0.5"/><rect x="4.5" y="4" width="3" height="7" rx="0.5"/><rect x="9" y="2" width="3" height="9" rx="0.5"/><rect x="13.5" y="0" width="3" height="11" rx="0.5"/></svg>
            <svg width="22" height="11" viewBox="0 0 22 11" fill="none" stroke="currentColor" strokeWidth="1"><rect x="0.5" y="0.5" width="18" height="10" rx="2"/><rect x="2" y="2" width="15" height="7" rx="1" fill="currentColor"/><rect x="19.5" y="3.5" width="1.5" height="4" fill="currentColor"/></svg>
          </span>
        </div>
        {/* notch */}
        <div style={{
          position: 'absolute', top: 8, left: '50%', transform: 'translateX(-50%)',
          width: 120, height: 32, background: '#0a0a0a', borderRadius: 20, zIndex: 60,
        }} />
        {/* scrollable content */}
        <div ref={innerRef} style={{
          width: '100%', height: '100%', overflowY: 'auto', overflowX: 'hidden',
          WebkitOverflowScrolling: 'touch',
        }}>
          {children}
        </div>
        {/* home indicator */}
        <div style={{
          position: 'absolute', bottom: 8, left: '50%', transform: 'translateX(-50%)',
          width: 134, height: 5, borderRadius: 3, background: 'rgba(0,0,0,.3)', zIndex: 50,
          mixBlendMode: 'difference',
        }} />
      </div>
    </div>
  );
}

Object.assign(window, {
  useReveal, useScrollProgress, CountUp, Reveal, Placeholder, Tategaki, MobileChrome,
});
