/* Shared helpers for the Mesh website kit: Lucide Icon + scroll-reveal hook */

function toPascal(name) {
  return name.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');
}

/* Renders a Lucide icon inside a React-owned span.
   `className` sizes the wrapper (e.g. "ic"); the svg fills it. */
function Icon({ name, className = 'ic', stroke = 1.75 }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el || !window.lucide) return;
    el.innerHTML = '';
    const i = document.createElement('i');
    i.setAttribute('data-lucide', name);
    el.appendChild(i);
    try {
      window.lucide.createIcons({ attrs: { 'stroke-width': stroke }, nameAttr: 'data-lucide' });
    } catch (e) {}
  }, [name, stroke]);
  return <span ref={ref} className={className} aria-hidden="true"></span>;
}

/* Reveal-on-scroll, driven by React state so it survives re-renders.
   Returns [ref, inView]. */
function useReveal() {
  const ref = React.useRef(null);
  const [inView, setInView] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let done = false;
    const reveal = () => { if (!done) { done = true; setInView(true); } };
    if (typeof IntersectionObserver === 'undefined') { reveal(); return; }
    const obs = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { reveal(); obs.unobserve(e.target); } });
    }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
    obs.observe(el);
    // Safety net: if IO never fires (e.g. embedded/full-height viewers that don't
    // scroll the iframe), reveal anyway so content is never stuck hidden. On a real
    // scrolling page IO wins first and gives the on-scroll entrance.
    const t = setTimeout(reveal, 1200);
    return () => { clearTimeout(t); obs.disconnect(); };
  }, []);
  return [ref, inView];
}

/* A revealing wrapper. Pass `delay` (ms) for stagger. */
function Reveal({ children, delay = 0, className = '', as = 'div', style = {} }) {
  const [ref, inView] = useReveal();
  const Tag = as;
  return <Tag ref={ref} className={('reveal ' + (inView ? 'in ' : '') + className).trim()} style={{ transitionDelay: delay + 'ms', ...style }}>{children}</Tag>;
}

Object.assign(window, { Icon, Reveal, useReveal, toPascal });

/* Cross-page anchor scroll. These pages are React apps, so a browser landing on
   "/#faqs" tries to jump before the target is rendered. Poll for the
   element (up to ~3.5s), then scroll to it accounting for the sticky nav.
   Also handles same-page hash clicks via hashchange. */
(function () {
  function scrollToHash() {
    var hash = window.location.hash;
    if (!hash || hash.length < 2) return;
    var id = decodeURIComponent(hash.slice(1));
    var tries = 0;
    (function attempt() {
      var el = document.getElementById(id);
      if (el) {
        var top = el.getBoundingClientRect().top + window.scrollY - 84;
        window.scrollTo({ top: top, behavior: tries === 0 ? 'auto' : 'smooth' });
      } else if (tries++ < 45) {
        setTimeout(attempt, 80);
      }
    })();
  }
  setTimeout(scrollToHash, 120);
  window.addEventListener('hashchange', scrollToHash);
})();
