/* Shared.jsx — utility components and hooks */

/** Intersection-observer-based reveal hook */
function useReveal(once = true){
  const ref = React.useRef(null);
  const [shown, setShown] = React.useState(false);
  React.useEffect(()=>{
    const el = ref.current;
    if(!el) return;
    if(typeof IntersectionObserver === "undefined"){ setShown(true); return; }
    const io = new IntersectionObserver((entries)=>{
      entries.forEach(e=>{
        if(e.isIntersecting){
          setShown(true);
          if(once) io.disconnect();
        } else if (!once) setShown(false);
      });
    }, { threshold: 0.18, rootMargin: "0px 0px -8% 0px" });
    io.observe(el);
    return ()=> io.disconnect();
  },[once]);
  return [ref, shown];
}

/** Reveal: simple wrapper that adds .reveal + .is-in classes */
function Reveal({ children, delay=0, as="div", className="", scale=false, ...rest }){
  const [ref, shown] = useReveal(true);
  const Tag = as;
  const cls = [
    "reveal",
    scale ? "reveal-scale" : "",
    delay ? `reveal-d-${delay}` : "",
    shown ? "is-in" : "",
    className
  ].filter(Boolean).join(" ");
  return <Tag ref={ref} className={cls} {...rest}>{children}</Tag>;
}

/** Smooth scroll to id */
function scrollToId(id){
  const el = document.getElementById(id);
  if(!el) return;
  const top = el.getBoundingClientRect().top + window.scrollY - 80;
  window.scrollTo({ top, behavior: "smooth" });
}

/** track scroll progress */
function useScrollProgress(){
  const [p, setP] = React.useState(0);
  React.useEffect(()=>{
    const onScroll = ()=>{
      const h = document.documentElement;
      const total = (h.scrollHeight - h.clientHeight) || 1;
      setP(Math.min(1, Math.max(0, window.scrollY / total)));
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return ()=> window.removeEventListener("scroll", onScroll);
  },[]);
  return p;
}

/** Magnetic effect — translates element a fraction toward cursor on hover */
function useMagnetic(strength = 0.25, max = 14){
  const ref = React.useRef(null);
  React.useEffect(()=>{
    const el = ref.current;
    if(!el) return;
    let raf = 0;
    let tx = 0, ty = 0;
    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) * strength;
      const dy = (e.clientY - cy) * strength;
      tx = Math.max(-max, Math.min(max, dx));
      ty = Math.max(-max, Math.min(max, dy));
      if(!raf) raf = requestAnimationFrame(apply);
    };
    const onLeave = ()=>{
      tx = 0; ty = 0;
      if(!raf) raf = requestAnimationFrame(apply);
    };
    const apply = ()=>{
      el.style.transform = `translate3d(${tx}px, ${ty}px, 0)`;
      raf = 0;
    };
    el.addEventListener("mousemove", onMove);
    el.addEventListener("mouseleave", onLeave);
    return ()=>{
      el.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseleave", onLeave);
    };
  },[strength,max]);
  return ref;
}

/** Counter that animates from->to when in view */
function AnimatedCount({ from = 0, to = 1247, duration = 1600, suffix = "" }){
  const [val, setVal] = React.useState(from);
  const [ref, shown] = useReveal(true);
  React.useEffect(()=>{
    if(!shown) return;
    const start = performance.now();
    let raf = 0;
    const tick = (t)=>{
      const elapsed = t - start;
      const p = Math.min(1, elapsed / duration);
      // ease-out
      const eased = 1 - Math.pow(1 - p, 3);
      setVal(Math.round(from + (to - from) * eased));
      if(p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return ()=> cancelAnimationFrame(raf);
  },[shown, from, to, duration]);
  return <span ref={ref}>{val.toLocaleString()}{suffix}</span>;
}

Object.assign(window, { useReveal, Reveal, scrollToId, useScrollProgress, useMagnetic, AnimatedCount });
