import React, { useRef, useEffect, useState } from 'react';
import { createRoot } from 'react-dom/client';
// Babel Standalone's default JSX transform here is classic, not automatic -
// it compiles <GooeyNav/> to React.createElement(...), which needs a real
// `React` binding in scope. Only the named hooks were imported before, so
// that reference was undefined at render time ("React is not defined"),
// thrown from inside doMount() AFTER it had already wiped the real nav.js
// links via marker.innerHTML = '' - the crash left the nav permanently
// gutted down to just the Perspective link on every load, not a transient
// flash. This default import is the actual fix, not the destructive wipe.
// GooeyNav.css is loaded via a real <link rel="stylesheet"> tag in bio.html
// already — a JS-side `import './GooeyNav.css'` here fails: Babel Standalone
// executes data-type="module" scripts via a Blob URL, and a relative import
// inside that blob resolves against the blob's own synthetic origin, not
// this file's real path, so the fetch 404s (Cloudflare's HTML fallback page
// then fails MIME-type-checking as a module, which was silently blocking
// this entire script from ever executing).

// Split out of mount.jsx into its own tiny file so it loads/transpiles
// independently of the huge shared bundle (WarpText, Carousel, GlowCursor,
// BorderGlow, VariableProximity, ogl, motion). Babel Standalone parsing that
// whole file client-side was taking 30+ seconds, during which the nav sat
// on nav.js's plain fallback links — this file alone mounts in ~1-2s.
const GooeyNav = (function () {

function GooeyNav({
  items,
  animationTime = 600,
  particleCount = 15,
  particleDistances = [90, 10],
  particleR = 100,
  timeVariance = 300,
  colors = [1, 2, 3, 1, 2, 3, 1, 4],
  initialActiveIndex = 0
}) {
  const containerRef = useRef(null);
  const navRef = useRef(null);
  const filterRef = useRef(null);
  const textRef = useRef(null);
  const [activeIndex, setActiveIndex] = useState(initialActiveIndex);

  const noise = (n = 1) => n / 2 - Math.random() * n;

  const getXY = (distance, pointIndex, totalPoints) => {
    const angle = ((360 + noise(8)) / totalPoints) * pointIndex * (Math.PI / 180);
    return [distance * Math.cos(angle), distance * Math.sin(angle)];
  };

  const createParticle = (i, t, d, r) => {
    let rotate = noise(r / 10);
    return {
      start: getXY(d[0], particleCount - i, particleCount),
      end: getXY(d[1] + noise(7), particleCount - i, particleCount),
      time: t,
      scale: 1 + noise(0.2),
      color: colors[Math.floor(Math.random() * colors.length)],
      rotate: rotate > 0 ? (rotate + r / 20) * 10 : (rotate - r / 20) * 10
    };
  };

  const makeParticles = element => {
    const d = particleDistances;
    const r = particleR;
    const bubbleTime = animationTime * 2 + timeVariance;
    element.style.setProperty('--time', `${bubbleTime}ms`);

    for (let i = 0; i < particleCount; i++) {
      const t = animationTime * 2 + noise(timeVariance * 2);
      const p = createParticle(i, t, d, r);
      element.classList.remove('active');

      setTimeout(() => {
        const particle = document.createElement('span');
        const point = document.createElement('span');
        particle.classList.add('particle');
        particle.style.setProperty('--start-x', `${p.start[0]}px`);
        particle.style.setProperty('--start-y', `${p.start[1]}px`);
        particle.style.setProperty('--end-x', `${p.end[0]}px`);
        particle.style.setProperty('--end-y', `${p.end[1]}px`);
        particle.style.setProperty('--time', `${p.time}ms`);
        particle.style.setProperty('--scale', `${p.scale}`);
        particle.style.setProperty('--color', `var(--color-${p.color}, white)`);
        particle.style.setProperty('--rotate', `${p.rotate}deg`);

        point.classList.add('point');
        particle.appendChild(point);
        element.appendChild(particle);
        requestAnimationFrame(() => {
          element.classList.add('active');
        });
        setTimeout(() => {
          try {
            element.removeChild(particle);
          } catch {
            // Do nothing
          }
        }, t);
      }, 30);
    }
  };

  const updateEffectPosition = element => {
    if (!containerRef.current || !filterRef.current || !textRef.current) return;
    const containerRect = containerRef.current.getBoundingClientRect();
    const pos = element.getBoundingClientRect();

    const styles = {
      left: `${pos.x - containerRect.x}px`,
      top: `${pos.y - containerRect.y}px`,
      width: `${pos.width}px`,
      height: `${pos.height}px`
    };
    Object.assign(filterRef.current.style, styles);
    Object.assign(textRef.current.style, styles);
    textRef.current.innerText = element.innerText;
  };

  const handleClick = (e, index) => {
    const liEl = e.currentTarget;
    if (activeIndex === index) return;

    setActiveIndex(index);
    updateEffectPosition(liEl);

    if (filterRef.current) {
      const particles = filterRef.current.querySelectorAll('.particle');
      particles.forEach(p => filterRef.current.removeChild(p));
    }

    if (textRef.current) {
      textRef.current.classList.remove('active');

      void textRef.current.offsetWidth;
      textRef.current.classList.add('active');
    }

    if (filterRef.current) {
      makeParticles(filterRef.current);
    }
  };

  const handleKeyDown = (e, index) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      const liEl = e.currentTarget.parentElement;
      if (liEl) {
        handleClick({ currentTarget: liEl }, index);
      }
    }
  };

  useEffect(() => {
    if (!navRef.current || !containerRef.current) return;
    const activeLi = navRef.current.querySelectorAll('li')[activeIndex];
    if (activeLi) {
      updateEffectPosition(activeLi);
      textRef.current?.classList.add('active');
    }

    const resizeObserver = new ResizeObserver(() => {
      const currentActiveLi = navRef.current?.querySelectorAll('li')[activeIndex];
      if (currentActiveLi) {
        updateEffectPosition(currentActiveLi);
      }
    });

    resizeObserver.observe(containerRef.current);
    return () => resizeObserver.disconnect();
  }, [activeIndex]);

  return (
    <div className="gooey-nav-container" ref={containerRef}>
      <nav>
        <ul ref={navRef}>
          {items.map((item, index) => (
            <li key={index} className={activeIndex === index ? 'active' : ''}>
              <a href={item.href} onClick={e => handleClick(e, index)} onKeyDown={e => handleKeyDown(e, index)}>
                {item.label}
              </a>
            </li>
          ))}
        </ul>
      </nav>
      <span className="effect filter" ref={filterRef} />
      <span className="effect text" ref={textRef} />
    </div>
  );
}
return GooeyNav;
})();

function mountGooeyNav() {
  // The page's own hand-written <nav> is not what actually renders — nav.js
  // (loaded site-wide, before this script) builds a completely separate
  // #sgi-nav bar from scratch and force-hides every other <nav> element via
  // `display:none !important`. #sgi-nav-links is the real, visible
  // container, so that's the actual mount target, not a page-local marker.
  const doMount = marker => {
    // #sgi-nav-perspective is a distinct yellow CTA pill (nav.js's own
    // styling), not one of the tab-style nav items — folding it into
    // GooeyNav's uniform item list flattens that visual hierarchy away.
    // Pull it out, keep its real DOM node untouched, and re-append it
    // after mounting so it keeps its original look and position.
    const perspectiveLink = marker.querySelector('#sgi-nav-perspective');
    const linkEls = Array.from(marker.querySelectorAll('a')).filter(a => a.id !== 'sgi-nav-perspective');
    const items = linkEls.map(a => ({
      label: a.textContent.trim(),
      href: a.getAttribute('href')
    }));
    if (!items.length) return;
    // Cloudflare Pages serves clean URLs (/about, not /about.html) — the
    // link hrefs are still `about.html` though, so a bare pathname segment
    // never matched and findIndex silently fell back to -1 -> index 0
    // (Work), showing the wrong item active on every page but work.html.
    const rawSegment = window.location.pathname.split('/').pop() || 'index';
    const activeHref = rawSegment.includes('.') ? rawSegment : `${rawSegment}.html`;
    const initialActiveIndex = Math.max(0, items.findIndex(it => it.href === activeHref));
    // Snapshot the working nav.js markup before touching the DOM. If
    // createRoot/render throws for any reason (the exact failure mode that
    // gutted the nav down to just Perspective before - see the import fix
    // above), restore this instead of leaving marker permanently emptied.
    const originalHTML = marker.innerHTML;
    try {
      if (perspectiveLink) perspectiveLink.remove();
      marker.innerHTML = '';
      if (perspectiveLink) marker.appendChild(perspectiveLink);
      const gooeyMount = document.createElement('div');
      marker.insertBefore(gooeyMount, perspectiveLink || null);
      const root = createRoot(gooeyMount);
      root.render(
        <GooeyNav
          items={items}
          particleCount={15}
          particleDistances={[90, 10]}
          particleR={100}
          initialActiveIndex={initialActiveIndex}
          animationTime={1100}
          timeVariance={450}
          colors={[1, 2, 3, 1, 2, 3, 1, 4]}
        />
      );
    } catch (err) {
      marker.innerHTML = originalHTML;
      console.error('GooeyNav mount failed, restored plain nav.js links:', err);
    }
  };

  const existing = document.getElementById('sgi-nav-links');
  if (existing) { doMount(existing); return; }

  const observer = new MutationObserver(() => {
    const marker = document.getElementById('sgi-nav-links');
    if (!marker) return;
    observer.disconnect();
    doMount(marker);
  });
  observer.observe(document.body, { childList: true, subtree: true });
}

mountGooeyNav();
