// components.jsx — Header, Footer, Cursor, image helper
const { useState, useEffect, useRef, useMemo } = React;

/* ─────────────────────────────────────────────────────────────────────
   Custom cursor — small ink dot, expands to outlined ring on hovers.
   Only mounts when enabled via Tweaks.
   ───────────────────────────────────────────────────────────────────── */
function Cursor({ enabled }) {
  const dotRef = useRef(null);
  useEffect(() => {
    if (!enabled) {
      document.documentElement.classList.remove('cursor-custom');
      return;
    }
    document.documentElement.classList.add('cursor-custom');
    const dot = dotRef.current;
    let raf = 0, x = -100, y = -100;
    const onMove = (e) => {
      x = e.clientX; y = e.clientY;
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        if (dot) dot.style.transform = `translate(${x}px, ${y}px) translate(-50%,-50%)`;
      });
    };
    const onOver = (e) => {
      const t = e.target;
      const interactive = t.closest && t.closest('a,button,[data-cursor-hover],input,textarea,select,label');
      if (dot) dot.classList.toggle('hover', !!interactive);
    };
    window.addEventListener('mousemove', onMove, { passive: true });
    window.addEventListener('mouseover', onOver, { passive: true });
    return () => {
      document.documentElement.classList.remove('cursor-custom');
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseover', onOver);
      cancelAnimationFrame(raf);
    };
  }, [enabled]);
  if (!enabled) return null;
  return <div ref={dotRef} className="cursor-dot" aria-hidden="true" />;
}

/* ─────────────────────────────────────────────────────────────────────
   Header — folder-style menu (Photography ▾ opens Index/Editorial/…).
   Restraint version of Koloff's folder navigation.
   ───────────────────────────────────────────────────────────────────── */
function Header({ route, navigate, lang, setLang, t, onSplash }) {
  const m = t.menu;
  const [openFolder, setOpenFolder] = useState(null);
  const closeTimer = useRef(null);

  const openNow = (id) => {
    if (closeTimer.current) { clearTimeout(closeTimer.current); closeTimer.current = null; }
    setOpenFolder(id);
  };
  const closeSoon = () => {
    if (closeTimer.current) clearTimeout(closeTimer.current);
    closeTimer.current = setTimeout(() => setOpenFolder(null), 180);
  };

  // Group structure:
  //   Photography ▾ -> Index / Editorial / Commercial / Archive
  //   Information
  //   Contact
  const folder = {
    id: 'photo',
    label: t.index?.photography || m.editorial.replace(/.+/, 'Photography'),
    items: [
      { id: 'all',        label: m.index,      to: { name: 'index' } },
      { id: 'editorial',  label: m.editorial,  to: { name: 'index', filter: 'EDITORIAL' } },
      { id: 'commercial', label: m.commercial, to: { name: 'index', filter: 'COMMERCIAL' } },
      { id: 'archive',    label: m.archive,    to: { name: 'index', filter: 'ARCHIVE' } },
    ],
  };
  const flatItems = [
    { id: 'information', label: m.information, to: { name: 'information' } },
    { id: 'contact',     label: m.contact,     to: { name: 'contact' } },
  ];

  const isFolderActive = route.name === 'index';
  const isItemActive = (item) => {
    if (route.name !== item.to.name) return false;
    if (item.to.name === 'index') return (route.filter || null) === (item.to.filter || null);
    return true;
  };

  return (
    <header className={`site-header ${onSplash ? 'on-splash' : ''}`}>
      <button
        className="brand no-sel"
        onClick={() => navigate({ name: 'splash' })}
        aria-label="Justin Personnaz — Home"
      >
        Justin Personnaz<span className="role">— {t.role}</span>
      </button>
      <nav className="site-nav" aria-label="Primary">
        {/* Folder dropdown */}
        <div
          className={`nav-folder ${openFolder === folder.id ? 'is-open' : ''} ${isFolderActive ? 'is-current' : ''}`}
          onMouseEnter={() => openNow(folder.id)}
          onMouseLeave={closeSoon}
          onFocus={() => openNow(folder.id)}
          onBlur={closeSoon}
        >
          <button
            className={`nav-trigger ${isFolderActive ? 'active' : ''}`}
            aria-expanded={openFolder === folder.id}
            aria-haspopup="true"
            onClick={() => navigate({ name: 'index' })}
          >
            {lang === 'fr' ? 'Photographie' : 'Photography'}
            <span className="folder-arrow" aria-hidden="true">▾</span>
          </button>
          <div className="folder-pop" role="menu">
            <ul>
              {folder.items.map((it) => (
                <li key={it.id}>
                  <button
                    role="menuitem"
                    className={isItemActive(it) ? 'active' : ''}
                    onClick={() => { navigate(it.to); setOpenFolder(null); }}
                  >
                    <span className="micro folder-num">{
                      it.id === 'all' ? 'I'
                      : it.id === 'editorial' ? 'II'
                      : it.id === 'commercial' ? 'III'
                      : 'IV'
                    }</span>
                    <span className="folder-label">{it.label}</span>
                  </button>
                </li>
              ))}
            </ul>
          </div>
        </div>

        {flatItems.map((it) => (
          <button
            key={it.id}
            className={isItemActive(it) ? 'active nav-flat' : 'nav-flat'}
            onClick={() => navigate(it.to)}
          >
            {it.label}
          </button>
        ))}
        <span className="lang" aria-label="Language">
          <button
            className={lang === 'fr' ? 'active' : ''}
            onClick={() => setLang('fr')}
            aria-pressed={lang === 'fr'}
          >FR</button>
          <span className="sep">/</span>
          <button
            className={lang === 'en' ? 'active' : ''}
            onClick={() => setLang('en')}
            aria-pressed={lang === 'en'}
          >EN</button>
        </span>
      </nav>
    </header>
  );
}

/* ─────────────────────────────────────────────────────────────────────
   Footer.
   ───────────────────────────────────────────────────────────────────── */
function Footer({ t, navigate }) {
  const year = new Date().getFullYear();
  return (
    <footer className="site-footer">
      <div className="group">
        <span className="micro">© {year} — JUSTIN PERSONNAZ</span>
        <span>{t.footer.availability}</span>
      </div>
      <div className="group">
        <button onClick={() => navigate({ name: 'contact' })} className="link-u">studio@justinpersonnaz.studio</button>
        <a href="#" className="link-u" onClick={(e) => e.preventDefault()}>Instagram</a>
        <a href="#" className="link-u" onClick={(e) => e.preventDefault()}>{t.footer.legal}</a>
      </div>
    </footer>
  );
}

/* ─────────────────────────────────────────────────────────────────────
   Image with hover crossfade (vignette behaviour).
   variant: 'opacity' | 'crossfade' | 'static'
   ───────────────────────────────────────────────────────────────────── */
function Vignette({ src, altSrc, alt, ratio = '4 / 5', variant = 'opacity', onClick, label }) {
  const [hover, setHover] = useState(false);
  const [mainOk, setMainOk] = useState(true);
  const [altOk, setAltOk] = useState(true);
  const showAlt = variant === 'crossfade' && altSrc && altOk && hover;
  return (
    <div
      className="img-frame"
      style={{ aspectRatio: ratio, cursor: onClick ? 'pointer' : 'default' }}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      onClick={onClick}
      role={onClick ? 'button' : undefined}
      aria-label={label}
      data-cursor-hover={onClick ? '1' : undefined}
    >
      {!mainOk && (
        <div className="img-ph" aria-hidden="true">
          <span className="meta">{label || 'IMAGE'}</span>
        </div>
      )}
      {mainOk && (
        <img
          src={src}
          alt={alt || ''}
          onError={() => setMainOk(false)}
          style={{
            position: 'absolute', inset: 0,
            opacity: variant === 'opacity' && hover ? 0.85 : 1,
          }}
        />
      )}
      {altSrc && altOk ? (
        <img
          src={altSrc}
          alt=""
          aria-hidden="true"
          onError={() => setAltOk(false)}
          style={{
            position: 'absolute', inset: 0,
            opacity: showAlt ? 1 : 0,
          }}
        />
      ) : null}
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────────────
   Page veil — fade-in then fade-out on route change.
   ───────────────────────────────────────────────────────────────────── */
function PageVeil({ routeKey }) {
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    // Fade in immediately, then out
    setVisible(true);
    const t1 = setTimeout(() => setVisible(false), 220);
    return () => clearTimeout(t1);
  }, [routeKey]);
  return <div className={`page-veil ${visible ? 'in' : ''}`} aria-hidden="true" />;
}

/* ─────────────────────────────────────────────────────────────────────
   SafeImg — a plain <img> that swaps to a placeholder on error.
   ───────────────────────────────────────────────────────────────────── */
function SafeImg({ src, alt, label, ...rest }) {
  const [ok, setOk] = useState(true);
  if (!ok) {
    return (
      <div className="img-ph" aria-hidden="true" {...rest}>
        <span className="meta">{label || 'IMAGE'}</span>
      </div>
    );
  }
  return <img src={src} alt={alt || ''} onError={() => setOk(false)} {...rest} />;
}

Object.assign(window, { Cursor, Header, Footer, Vignette, PageVeil, SafeImg });
