// site-components.jsx — shared React components (Nav, Footer, BgVideo, AnimHelpers)
// Expects: React, ReactDOM, and framer-motion on window (as window.FramerMotion / window.motion)

const { useState, useEffect, useRef, useLayoutEffect, useMemo } = React;
const FM = window.Motion || window.FramerMotion || window;
const motion = FM.motion || window.motion;
const AnimatePresence = FM.AnimatePresence;
const useScroll = FM.useScroll;
const useTransform = FM.useTransform;
const useMotionValueEvent = FM.useMotionValueEvent || window.useMotionValueEvent;
const useSpring = FM.useSpring;

// ──────────────────────────────────────────────────────────────
// Logo mark — tiny version of the "E" with swash
// ──────────────────────────────────────────────────────────────
function LogoMark({ size = 34, inverted = false }) {
  const fg = inverted ? 'var(--ink-000)' : 'var(--ink-950)';
  const bg = inverted ? 'var(--ink-950)' : 'transparent';
  return (
    <div
      style={{
        width: size, height: size,
        display: 'grid', placeItems: 'center',
        background: bg,
        borderRadius: '50%',
        border: inverted ? 'none' : '1px solid var(--glass-border-strong)',
        position: 'relative',
      }}
      aria-label="Excelsior Web Design"
    >
      <svg viewBox="0 0 40 40" width={size * 0.62} height={size * 0.62}>
        <text
          x="20" y="28"
          textAnchor="middle"
          fontFamily="Cormorant Garamond, serif"
          fontSize="28"
          fontWeight="400"
          fill={fg}
        >E</text>
        <path
          d="M6 22 Q 20 14, 34 22"
          stroke={fg} strokeWidth="1" fill="none" strokeLinecap="round"
        />
      </svg>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// Navigation
// ──────────────────────────────────────────────────────────────
function Nav({ active = 'home' }) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const on = () => setScrolled(window.scrollY > 24);
    on(); window.addEventListener('scroll', on, { passive: true });
    return () => window.removeEventListener('scroll', on);
  }, []);

  const links = [
    { id: 'home', label: 'Home', href: 'index.html' },
    { id: 'work', label: 'Work', href: 'work.html' },
    { id: 'pricing', label: 'Pricing', href: 'pricing.html' },
    { id: 'about', label: 'About', href: 'about.html' },
  ];

  return (
    <nav className={`nav${scrolled ? ' is-scrolled' : ''}`} data-nav>
      <a href="index.html" className="nav-brand" aria-label="Excelsior home">
        <LogoMark size={32} />
        <span>Excelsior <span style={{ color: 'var(--ink-700)' }}>Web Design</span></span>
      </a>
      <ul className="nav-links">
        {links.map((l) => (
          <li key={l.id}>
            <a href={l.href} className={`nav-link${active === l.id ? ' is-active' : ''}`}>{l.label}</a>
          </li>
        ))}
      </ul>
      <a href="contact.html" className={`nav-cta${active === 'contact' ? ' is-active' : ''}`}>
        Start a project →
      </a>
    </nav>
  );
}

// ──────────────────────────────────────────────────────────────
// Background video (dual-layer crossfade; supports single or multi)
// Handles HLS .m3u8 URLs via hls.js (auto-loaded on first HLS source)
// ──────────────────────────────────────────────────────────────
const isHls = (url) => typeof url === 'string' && url.includes('.m3u8');
let __hlsLoader = null;
function ensureHls() {
  if (window.Hls) return Promise.resolve(window.Hls);
  if (__hlsLoader) return __hlsLoader;
  __hlsLoader = new Promise((resolve, reject) => {
    const s = document.createElement('script');
    s.src = 'https://cdn.jsdelivr.net/npm/hls.js@1.5.17/dist/hls.min.js';
    s.onload = () => resolve(window.Hls);
    s.onerror = reject;
    document.head.appendChild(s);
  });
  return __hlsLoader;
}
function attachSrc(videoEl, src) {
  if (!videoEl || !src) return;
  // tear down prior hls
  if (videoEl.__hls) { try { videoEl.__hls.destroy(); } catch(e){} videoEl.__hls = null; }
  if (isHls(src) && !videoEl.canPlayType('application/vnd.apple.mpegurl')) {
    ensureHls().then((Hls) => {
      if (Hls && Hls.isSupported()) {
        const hls = new Hls({ enableWorker: true });
        hls.loadSource(src);
        hls.attachMedia(videoEl);
        videoEl.__hls = hls;
      } else {
        videoEl.src = src;
      }
    });
  } else {
    videoEl.src = src;
  }
}

function BgVideo({ sources, interval = 12000, vignette = true, children, grain = true }) {
  const v1 = useRef(null);
  const v2 = useRef(null);
  const [activeIsOne, setActiveIsOne] = useState(true);

  const srcs = useMemo(() => (Array.isArray(sources) ? sources : [sources]).filter(Boolean), [sources]);

  useEffect(() => {
    if (v1.current && srcs[0]) {
      attachSrc(v1.current, srcs[0]);
      v1.current.play().catch(() => {});
    }
    if (v2.current && srcs[1 % srcs.length]) {
      attachSrc(v2.current, srcs[1 % srcs.length]);
    }
  }, [srcs]);

  useEffect(() => {
    if (srcs.length < 2) return;
    let idx = 0;
    const t = setInterval(() => {
      const next = (idx + 1) % srcs.length;
      const nextEl = activeIsOne ? v2.current : v1.current;
      if (nextEl) {
        nextEl.currentTime = 0;
        nextEl.play().catch(() => {});
      }
      setActiveIsOne((a) => !a);
      setTimeout(() => {
        const willBeInactive = activeIsOne ? v1.current : v2.current;
        const queuedSrc = srcs[(next + 1) % srcs.length];
        if (willBeInactive) attachSrc(willBeInactive, queuedSrc);
      }, 1400);
      idx = next;
    }, interval);
    return () => clearInterval(t);
  }, [srcs, interval, activeIsOne]);

  return (
    <div className={`bgvid${vignette ? ' bgvid--vignette' : ''}`}>
      <video
        ref={v1}
        className={activeIsOne ? 'is-active' : ''}
        muted autoPlay loop={srcs.length === 1} playsInline preload="auto"
      />
      {srcs.length > 1 && (
        <video
          ref={v2}
          className={!activeIsOne ? 'is-active' : ''}
          muted autoPlay loop={false} playsInline preload="auto"
        />
      )}
      {grain && <div className="grain" />}
      {children}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// SplitLines — for staggered word/line entrance animations
// ──────────────────────────────────────────────────────────────
function SplitWords({ text, delay = 0, stagger = 0.06, className = '', em }) {
  const words = text.split(' ');
  return (
    <span className={className} style={{ display: 'inline' }}>
      {words.map((w, i) => {
        const isEm = em && em.includes(i);
        return (
          <React.Fragment key={i}>
            <span
              style={{
                display: 'inline-block',
                overflow: 'hidden',
                verticalAlign: 'baseline',
                lineHeight: 'inherit',
                paddingBottom: '0.18em',
                marginBottom: '-0.18em',
              }}
            >
              <motion.span
                style={{
                  display: 'inline-block',
                  fontStyle: isEm ? 'italic' : 'inherit',
                  color: isEm ? 'var(--ink-800)' : 'inherit',
                }}
                initial={{ y: '110%' }}
                animate={{ y: '0%' }}
                transition={{ duration: 1.1, delay: delay + i * stagger, ease: [0.16, 1, 0.3, 1] }}
              >
                {w}
              </motion.span>
            </span>
            {i < words.length - 1 ? ' ' : ''}
          </React.Fragment>
        );
      })}
    </span>
  );
}

function FadeUp({ children, delay = 0, y = 20, duration = 0.9 }) {
  return (
    <motion.div
      initial={{ opacity: 0, y }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true, margin: '-10% 0px' }}
      transition={{ duration, delay, ease: [0.16, 1, 0.3, 1] }}
    >
      {children}
    </motion.div>
  );
}

// ──────────────────────────────────────────────────────────────
// Footer
// ──────────────────────────────────────────────────────────────
function Footer() {
  return (
    <footer className="footer">
      <div className="footer-wordmark" aria-hidden="true">Excelsior</div>
      <div className="footer-inner">
        <div>
          <div className="eyebrow" style={{ marginBottom: 16 }}>Excelsior Web Design</div>
          <p className="lead" style={{ fontSize: 15 }}>
            Quiet, considered websites for brands that would rather be remembered than noticed.
          </p>
          <div style={{ marginTop: 24 }}>
            <a href="contact.html" className="btn btn--ghost">
              Start a project <span className="arrow">→</span>
            </a>
          </div>
        </div>
        <div>
          <h4>Studio</h4>
          <ul>
            <li><a href="about.html">About</a></li>
            <li><a href="work.html">Work</a></li>
            <li><a href="pricing.html">Pricing</a></li>
            <li><a href="contact.html">Contact</a></li>
          </ul>
        </div>
        <div>
          <h4>Services</h4>
          <ul>
            <li><a href="pricing.html">Static sites</a></li>
            <li><a href="pricing.html">Interactive sites</a></li>
            <li><a href="pricing.html">Brand + design</a></li>
            <li><a href="pricing.html">Care plans</a></li>
          </ul>
        </div>
        <div>
          <h4>Contact</h4>
          <ul>
            <li><a href="contact.html">Project inquiry →</a></li>
          </ul>
        </div>
      </div>
      <div className="footer-bottom">
        <span className="mono">© {new Date().getFullYear()} Excelsior Web Design. All rights reserved.</span>
        <span className="mono">Made with care, in California.</span>
      </div>
    </footer>
  );
}

// Expose to other babel scripts
Object.assign(window, {
  LogoMark, Nav, BgVideo, SplitWords, FadeUp, Footer,
  motion, AnimatePresence, useScroll, useTransform, useMotionValueEvent, useSpring,
});
