// ─────────────────────────────────────────────────────────────
// Mezoo — Primitives partagées
// Logos en JSX (les SVG sont aussi sur disque dans assets/), composants
// d'interface réutilisés sur toutes les pages, hook scroll-reveal,
// routeur ultra-léger.
// ─────────────────────────────────────────────────────────────

// ── Logos (versions JSX, pilotables par currentColor) ────────────

function MezooMark({ size = 40, ariaHidden = false }) {
  return (
    <svg width={size} height={size} viewBox="0 0 64 64" aria-hidden={ariaHidden} aria-label={ariaHidden ? undefined : 'Mezoo'} role={ariaHidden ? 'presentation' : 'img'}>
      <rect x="2.25" y="2.25" width="59.5" height="59.5" fill="none" stroke="currentColor" strokeWidth="1.5" />
      <path d="M14 50 L14 16 M50 50 L50 16 M14 16 L32 36 L50 16"
        fill="none" stroke="currentColor" strokeWidth="3.5"
        strokeLinecap="square" strokeLinejoin="miter" strokeMiterlimit="6" />
      <rect x="46" y="46" width="6" height="6" fill="var(--accent)" />
    </svg>
  );
}

function MezooWordmark({ size = 24, withDot = true }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'baseline', gap: 0,
      fontFamily: 'var(--font-display)', fontWeight: 500,
      letterSpacing: '-0.045em', fontSize: size, color: 'currentColor', lineHeight: 0.9,
    }}>
      <span>mezoo</span>
      {withDot && (
        <span style={{
          display: 'inline-block', width: size * 0.14, height: size * 0.14,
          background: 'var(--accent)', marginLeft: size * 0.08, marginBottom: size * 0.06,
        }} />
      )}
    </span>
  );
}

function MezooLockup({ size = 28, tagline = 'Atelier numérique' }) {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 14 }}>
      <MezooMark size={size + 12} ariaHidden />
      <span style={{ display: 'flex', alignItems: 'baseline', gap: 12 }}>
        <MezooWordmark size={size} withDot={false} />
        {tagline && (
          <span className="mz-mono" style={{ color: 'var(--fg-subtle)', textTransform: 'uppercase', letterSpacing: '0.14em' }}>
            — {tagline}
          </span>
        )}
      </span>
    </span>
  );
}

// ── Scroll reveal hook ──────────────────────────────────────────
// IntersectionObserver attaches .is-in once when element enters viewport.
function useReveal() {
  React.useEffect(() => {
    const els = document.querySelectorAll('.mz-reveal:not(.is-in)');
    if (!els.length) return undefined;
    const io = new IntersectionObserver((entries) => {
      for (const e of entries) {
        if (e.isIntersecting) {
          e.target.classList.add('is-in');
          io.unobserve(e.target);
        }
      }
    }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  });
}

// Stagger: child indexes drive --reveal-delay so siblings cascade in.
function Reveal({ children, delay = 0, as: As = 'div', ...rest }) {
  return (
    <As className="mz-reveal" style={{ '--reveal-delay': `${delay}ms` }} {...rest}>
      {children}
    </As>
  );
}

// ── Animated counter (counts up to value once in viewport) ──────
function CountUp({ to, suffix = '', prefix = '', decimals = 0, duration = 1100 }) {
  const ref = React.useRef(null);
  const [val, setVal] = React.useState(0);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return undefined;
    let raf;
    const io = new IntersectionObserver((entries) => {
      if (!entries[0].isIntersecting) return;
      const start = performance.now();
      const step = (now) => {
        const t = Math.min(1, (now - start) / duration);
        const eased = 1 - Math.pow(1 - t, 3);
        setVal(to * eased);
        if (t < 1) raf = requestAnimationFrame(step);
      };
      raf = requestAnimationFrame(step);
      io.disconnect();
    }, { threshold: 0.5 });
    io.observe(el);
    return () => { io.disconnect(); cancelAnimationFrame(raf); };
  }, [to, duration]);
  return <span ref={ref}>{prefix}{val.toFixed(decimals)}{suffix}</span>;
}

// ── Italic emphasis (serif over running sans) ───────────────────
function Em({ children }) {
  return <em className="mz-italic">{children}</em>;
}

// ── Eyebrow ─────────────────────────────────────────────────────
function Eyebrow({ children, line = true }) {
  return <div className={line ? 'mz-eyebrow mz-eyebrow-line' : 'mz-eyebrow'}>{children}</div>;
}

// ── Spec callout — Stratum-style data card ──────────────────────
// Used to inject "technical proof" into Senior-flavored layouts.
function SpecCard({ title, status = 'live', children, meta }) {
  return (
    <aside style={{
      border: '1px solid var(--hairline)', background: 'var(--surface)',
      borderRadius: 'var(--r-card)', overflow: 'hidden',
      display: 'flex', flexDirection: 'column',
    }}>
      <header style={{
        padding: '10px 14px', borderBottom: '1px solid var(--hairline)',
        display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.12em',
        textTransform: 'uppercase', color: 'var(--fg-muted)',
      }}>
        <span>↳ {title}</span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
          <span style={{ width: 6, height: 6, borderRadius: 6, background: 'var(--signal-ok)' }} />
          {status}
        </span>
      </header>
      <div style={{ padding: 'var(--s-4)', flex: 1 }}>{children}</div>
      {meta && (
        <footer style={{
          padding: '8px 14px', borderTop: '1px solid var(--hairline)',
          fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.1em',
          textTransform: 'uppercase', color: 'var(--fg-subtle)',
          display: 'flex', justifyContent: 'space-between',
        }}>{meta}</footer>
      )}
    </aside>
  );
}

// Tiny key-value spec row used inside SpecCard.
function SpecRow({ k, v }) {
  return (
    <div style={{
      display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
      padding: '7px 0', borderBottom: '1px dashed var(--hairline)',
      fontFamily: 'var(--font-mono)', fontSize: 11,
    }}>
      <span style={{ color: 'var(--fg-subtle)', letterSpacing: '0.04em' }}>{k}</span>
      <span style={{ color: 'var(--fg)' }}>{v}</span>
    </div>
  );
}

// ── Image placeholder (until real captures arrive) ──────────────
function CapturePlaceholder({ label, ratio = '16 / 10', accent = true, dense = false, style }) {
  return (
    <div style={{
      aspectRatio: ratio, width: '100%',
      background: 'var(--surface)',
      border: '1px solid var(--hairline)',
      borderRadius: 'var(--r-card)',
      position: 'relative', overflow: 'hidden',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      ...style,
    }}>
      <svg style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', opacity: 0.5 }} preserveAspectRatio="none">
        <line x1="0" y1="0" x2="100%" y2="100%" stroke="var(--hairline)" />
        <line x1="100%" y1="0" x2="0" y2="100%" stroke="var(--hairline)" />
      </svg>
      {/* Corner ticks (Stratum signature) */}
      {!dense && [
        { top: 10, left: 10, borderTop: '1px solid var(--fg-subtle)', borderLeft: '1px solid var(--fg-subtle)' },
        { top: 10, right: 10, borderTop: '1px solid var(--fg-subtle)', borderRight: '1px solid var(--fg-subtle)' },
        { bottom: 10, left: 10, borderBottom: '1px solid var(--fg-subtle)', borderLeft: '1px solid var(--fg-subtle)' },
        { bottom: 10, right: 10, borderBottom: '1px solid var(--fg-subtle)', borderRight: '1px solid var(--fg-subtle)' },
      ].map((s, i) => <div key={i} style={{ position: 'absolute', width: 10, height: 10, ...s }} />)}
      {accent && (
        <span style={{
          position: 'absolute', top: 16, left: 16,
          width: 6, height: 6, background: 'var(--accent)',
        }} />
      )}
      <span className="mz-mono" style={{
        position: 'relative', color: 'var(--fg-subtle)',
        letterSpacing: '0.16em', textTransform: 'uppercase', fontSize: 11,
      }}>{label}</span>
    </div>
  );
}

// ── Theme toggle (light ⇄ dark on <html>) ───────────────────────
function useTheme() {
  const [theme, setTheme] = React.useState(() => {
    if (typeof document === 'undefined') return 'light';
    return document.documentElement.dataset.theme || 'light';
  });
  React.useEffect(() => {
    document.documentElement.dataset.theme = theme;
    try { localStorage.setItem('mezoo.theme', theme); } catch {}
  }, [theme]);
  return [theme, setTheme];
}

// ── Router (3 pages: home / case / contact) ─────────────────────
const MezooRouter = React.createContext({ page: 'home', go: () => {} });
function useRouter() { return React.useContext(MezooRouter); }

function RouterProvider({ children }) {
  const [state, setState] = React.useState(() => ({
    page: (location.hash.replace('#', '') || 'home'),
    caseId: null,
  }));
  const go = React.useCallback((page, opts = {}) => {
    setState({ page, caseId: opts.caseId || null });
    location.hash = page;
    // Always reset scroll on navigation to keep the page-transition feel clean.
    requestAnimationFrame(() => window.scrollTo({ top: 0, behavior: 'instant' in window ? 'instant' : 'auto' }));
  }, []);
  React.useEffect(() => {
    const onHash = () => setState((s) => ({ ...s, page: location.hash.replace('#', '') || 'home' }));
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  return <MezooRouter.Provider value={{ ...state, go }}>{children}</MezooRouter.Provider>;
}

Object.assign(window, {
  MezooMark, MezooWordmark, MezooLockup,
  useReveal, Reveal, CountUp, Em, Eyebrow,
  SpecCard, SpecRow, CapturePlaceholder,
  useTheme, RouterProvider, useRouter,
});
