// Reusable animation hooks and atoms for the PROVE landing.
// Adds: scroll progress, cursor glow, magnetic buttons, ambient particles,
// scroll-reveal, scroll-aware navbar, word-by-word slam, PROVE glitch,
// floating proof badges, coin-burst on click, live streak counter.

const { useState: useStateAnim, useEffect: useEffectAnim, useRef: useRefAnim } = React;

// ── Reduced-motion check ─────────────────────────────────────────
function prefersReducedMotion() {
  return typeof window !== 'undefined'
    && window.matchMedia
    && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

// ── ScrollProgress ─ thin coral line on left edge ────────────────
function ScrollProgress({ container }) {
  const [pct, setPct] = useStateAnim(0);
  useEffectAnim(() => {
    const target = container?.current || window;
    const onScroll = () => {
      const el = container?.current;
      if (el) {
        const max = el.scrollHeight - el.clientHeight;
        setPct(max > 0 ? (el.scrollTop / max) * 100 : 0);
      } else {
        const max = document.documentElement.scrollHeight - window.innerHeight;
        setPct(max > 0 ? (window.scrollY / max) * 100 : 0);
      }
    };
    target.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => target.removeEventListener('scroll', onScroll);
  }, [container]);
  return (
    <div style={{
      position: 'absolute', left: 0, top: 0, bottom: 0, width: 2,
      pointerEvents: 'none', zIndex: 50,
    }}>
      <div style={{
        position: 'absolute', top: 0, left: 0, width: '100%',
        height: `${pct}%`, background: 'var(--coral)',
        boxShadow: '0 0 12px rgba(255,97,85,0.6)',
        transition: 'height 0.1s ease-out',
      }} />
    </div>
  );
}

// ── CursorGlow ─ soft coral radial that follows cursor ───────────
function CursorGlow({ scope }) {
  const ref = useRefAnim(null);
  useEffectAnim(() => {
    if (prefersReducedMotion()) return;
    const target = scope?.current;
    if (!target) return;
    let raf;
    const onMove = (e) => {
      const r = target.getBoundingClientRect();
      const x = e.clientX - r.left;
      const y = e.clientY - r.top;
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        if (ref.current) {
          ref.current.style.transform = `translate(${x - 300}px, ${y - 300}px)`;
          ref.current.style.opacity = '1';
        }
      });
    };
    const onLeave = () => { if (ref.current) ref.current.style.opacity = '0'; };
    target.addEventListener('mousemove', onMove);
    target.addEventListener('mouseleave', onLeave);
    return () => {
      target.removeEventListener('mousemove', onMove);
      target.removeEventListener('mouseleave', onLeave);
      cancelAnimationFrame(raf);
    };
  }, [scope]);
  return (
    <div ref={ref} style={{
      position: 'absolute', width: 600, height: 600,
      borderRadius: '50%', pointerEvents: 'none',
      background: 'radial-gradient(circle, rgba(255,97,85,0.10), transparent 60%)',
      opacity: 0,
      transition: 'opacity 0.3s ease, transform 0.12s ease-out',
      left: 0, top: 0, zIndex: 1,
      mixBlendMode: 'screen',
    }} />
  );
}

// ── MagneticButton ─ wraps a CTA, pulls toward cursor on hover ───
function MagneticButton({ children, strength = 0.3, max = 12, style }) {
  const ref = useRefAnim(null);
  useEffectAnim(() => {
    if (prefersReducedMotion()) return;
    const el = ref.current;
    if (!el) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const cx = r.left + r.width / 2;
      const cy = r.top + r.height / 2;
      const dx = e.clientX - cx;
      const dy = e.clientY - cy;
      const dist = Math.hypot(dx, dy);
      if (dist > 100) {
        el.style.transform = '';
        return;
      }
      const tx = Math.max(-max, Math.min(max, dx * strength));
      const ty = Math.max(-max, Math.min(max, dy * strength));
      el.style.transform = `translate(${tx}px, ${ty}px)`;
    };
    const onLeave = () => { el.style.transform = ''; };
    window.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    return () => {
      window.removeEventListener('mousemove', onMove);
      el.removeEventListener('mouseleave', onLeave);
    };
  }, [strength, max]);
  return (
    <span ref={ref} style={{
      display: 'inline-block',
      transition: 'transform 0.3s cubic-bezier(.2,.7,.3,1)',
      ...style,
    }}>{children}</span>
  );
}

// ── AmbientParticles ─ subtle coral particles drifting up ────────
function AmbientParticles({ count = 12 }) {
  if (prefersReducedMotion()) return null;
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', overflow: 'hidden' }}>
      {Array.from({ length: count }).map((_, i) => {
        const left = (Math.sin(i * 7.1) + 1) * 50;
        const size = 2 + (i % 4);
        const dur = 8 + (i % 5) * 1.5;
        const delay = (i * 0.7) % 8;
        const op = 0.15 + ((i % 3) * 0.1);
        return (
          <div key={i} style={{
            position: 'absolute', left: `${left}%`, bottom: '-10%',
            width: size, height: size, borderRadius: '50%',
            background: 'var(--coral)',
            opacity: op,
            animation: `prove-particle-drift ${dur}s linear ${delay}s infinite`,
          }} />
        );
      })}
    </div>
  );
}

// ── ScrollReveal ─ IntersectionObserver-based fade+rise ──────────
function ScrollReveal({ children, delay = 0, threshold = 0.15, y = 32, root, as = 'div', style }) {
  const ref = useRefAnim(null);
  const [shown, setShown] = useStateAnim(false);
  useEffectAnim(() => {
    if (prefersReducedMotion()) { setShown(true); return; }
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) { setShown(true); io.unobserve(el); }
      });
    }, { threshold, root: root?.current || null });
    io.observe(el);
    return () => io.disconnect();
  }, [threshold, root]);
  const Comp = as;
  return (
    <Comp ref={ref} style={{
      opacity: shown ? 1 : 0,
      transform: shown ? 'translateY(0)' : `translateY(${y}px)`,
      transition: `opacity 0.5s ease-out ${delay}ms, transform 0.5s ease-out ${delay}ms`,
      ...style,
    }}>{children}</Comp>
  );
}

// ── WordSlam ─ each word drops in with stagger ───────────────────
function WordSlam({ text, baseDelay = 700, stagger = 60, style }) {
  if (prefersReducedMotion()) {
    return <span style={style}>{text}</span>;
  }
  const words = String(text).split(' ');
  return (
    <span style={{ ...style, display: 'inline' }}>
      {words.map((w, i) => (
        <React.Fragment key={i}>
          <span style={{
            display: 'inline-block',
            animation: `prove-word-slam 0.55s cubic-bezier(.22,1.1,.36,1.05) ${baseDelay + i * stagger}ms backwards`,
          }}>{w}</span>
          {i < words.length - 1 ? ' ' : ''}
        </React.Fragment>
      ))}
    </span>
  );
}

// ── GlitchText ─ briefly scrambles letters every interval ────────
function GlitchText({ text, interval = 4000, style }) {
  const [display, setDisplay] = useStateAnim(text);
  useEffectAnim(() => {
    if (prefersReducedMotion()) return;
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    let timer;
    const cycle = () => {
      let step = 0;
      const scramble = setInterval(() => {
        setDisplay(text.split('').map((c) => c === ' ' ? ' ' : chars[Math.floor(Math.random() * chars.length)]).join(''));
        step++;
        if (step > 6) {
          clearInterval(scramble);
          setDisplay(text);
          timer = setTimeout(cycle, interval);
        }
      }, 30);
    };
    timer = setTimeout(cycle, interval);
    return () => clearTimeout(timer);
  }, [text, interval]);
  return <span style={style}>{display}</span>;
}

// ── FloatingBadge ─ glassy notification around the phone mockup ──
function FloatingBadge({ children, style, drift = 10, period = 4, delay = 0, rotate = 0 }) {
  return (
    <div style={{
      position: 'absolute',
      backdropFilter: 'blur(12px)',
      background: 'rgba(13,13,13,0.8)',
      border: '1px solid rgba(255,255,255,0.15)',
      borderRadius: 12,
      padding: '10px 14px',
      display: 'flex', alignItems: 'center', gap: 10,
      boxShadow: '0 16px 40px rgba(0,0,0,0.4)',
      transform: `rotate(${rotate}deg)`,
      animation: `prove-float ${period}s ease-in-out ${delay}s infinite`,
      '--drift': `${drift}px`,
      ...style,
    }}>{children}</div>
  );
}

// ── SmartNavbar ─ scroll-aware nav (hides going down, shows going up)
function useSmartNav(container) {
  const [state, setState] = useStateAnim({ hidden: false, scrolled: false });
  useEffectAnim(() => {
    const target = container?.current || window;
    let lastY = 0;
    const getY = () => container?.current ? container.current.scrollTop : window.scrollY;
    const onScroll = () => {
      const y = getY();
      setState({
        hidden: y > 200 && y > lastY,
        scrolled: y > 80,
      });
      lastY = y;
    };
    target.addEventListener('scroll', onScroll, { passive: true });
    return () => target.removeEventListener('scroll', onScroll);
  }, [container]);
  return state;
}

// ── CoinBurst ─ tiny particles flying outward on stake click ─────
function useCoinBurst() {
  const [bursts, setBursts] = useStateAnim([]);
  const fire = (x, y, color = 'var(--coral)') => {
    if (prefersReducedMotion()) return;
    const id = Math.random();
    const particles = Array.from({ length: 8 }).map((_, i) => ({
      id: id + i,
      angle: (i / 8) * Math.PI * 2,
      distance: 40 + Math.random() * 20,
    }));
    setBursts((b) => [...b, { id, x, y, color, particles }]);
    setTimeout(() => setBursts((b) => b.filter((bb) => bb.id !== id)), 700);
  };
  const render = (
    <>
      {bursts.map((b) => (
        <div key={b.id} style={{ position: 'absolute', left: b.x, top: b.y, pointerEvents: 'none', zIndex: 20 }}>
          {b.particles.map((p) => (
            <div key={p.id} style={{
              position: 'absolute', width: 6, height: 6, borderRadius: '50%',
              background: b.color,
              animation: `prove-burst 0.6s ease-out forwards`,
              '--bx': `${Math.cos(p.angle) * p.distance}px`,
              '--by': `${Math.sin(p.angle) * p.distance}px`,
            }} />
          ))}
        </div>
      ))}
    </>
  );
  return [fire, render];
}

// ── LiveStreakCounter ─ ticks up every interval ──────────────────
function LiveStreakCounter({ start = 184, intervalMs = 8000 }) {
  const [n, setN] = useStateAnim(start);
  useEffectAnim(() => {
    const t = setInterval(() => setN((v) => v + 1), intervalMs);
    return () => clearInterval(t);
  }, [intervalMs]);
  return (
    <span style={{ display: 'inline-flex', alignItems: 'baseline', gap: 8, fontFamily: 'var(--mono)' }}>
      <span style={{ fontSize: 12, color: 'rgba(255,255,255,0.5)', textTransform: 'uppercase', letterSpacing: 0.1 + 'em' }}>
        Longest active streak
      </span>
      <span style={{ fontSize: 20, fontWeight: 700, color: 'var(--coral)' }}>
        DAY {n}
      </span>
    </span>
  );
}

Object.assign(window, {
  ScrollProgress, CursorGlow, MagneticButton, AmbientParticles,
  ScrollReveal, WordSlam, GlitchText, FloatingBadge,
  useSmartNav, useCoinBurst, LiveStreakCounter, prefersReducedMotion,
});
