// Shared UI components: Logo, Nav, Footer, ThemedClock, etc.
const { useState, useEffect, useRef } = React;

// Asset paths in data.js / data-articles.js are stored relative ("assets/…").
// Article URLs are nested (/articles/<slug>), where a relative path resolves to
// /articles/assets/… and 404s. Resolve them against the directory the app's own
// files are served from — "/" on the live site, the serve folder in a preview.
const PV_BASE = (() => {
  try {
    const s = document.querySelector('script[src*="components.jsx"]');
    if (s && s.src) return s.src.replace(/[^/]*$/, '');
  } catch (e) {}
  return '/';
})();
const pvAbs = u => (typeof u === 'string' && /^assets\//.test(u)) ? PV_BASE + u : u;
const pvAbsHtml = h => (typeof h === 'string' ? h.replace(/(src|href|poster)=(["'])assets\//g, '$1=$2' + PV_BASE + 'assets/') : h);

// ─── Pace mark ──────────────────────────────────────────
// Auto-traced vector from the final brand lockup — single path, the slit
// and crosshair are carved out (transparent), so it works on any background.
function Logo({ size = 44, color = "currentColor" }) {
  const w = size * (1.2534);
  return (
    <svg width={w} height={size} viewBox="82 56 366 292" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ display: 'block' }}>
      <path fill={color} d={window.PV_LOGO_PATH}></path>
    </svg>
  );
}

// ─── Hand-drawn annotation strokes ─────────────────────────
// A loose underline under the leading words and a lassoed circle around the
// last one. Single paths with pathLength="1", so the draw-on is a dash-offset
// transition in CSS (see the .hl-ann rules in styles.css).
function Scribble({ kind }) {
  return kind === 'ring'
    ? (
      <svg className="scr scr-ring" viewBox="0 0 100 40" preserveAspectRatio="none" fill="none" aria-hidden="true">
        <path pathLength="1" vectorEffect="non-scaling-stroke" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"
          d="M82 7C71 2 42 0 21 5 3 9 0 26 15 33c18 8 66 7 79-4 8-7 4-16-11-21-8-3-18-4-26-3" />
      </svg>
    )
    : (
      <svg className="scr scr-line" viewBox="0 0 100 10" preserveAspectRatio="none" fill="none" aria-hidden="true">
        <path pathLength="1" vectorEffect="non-scaling-stroke" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"
          d="M1 5C22 2 48 8 74 4c9-1 17-1 25 1" />
      </svg>
    );
}

// ─── Crosshair motif ──────────────────────────────────────
function Crosshair({ size = 24, color = "currentColor", opacity = 1 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" style={{ opacity }}>
      <line x1="2" y1="12" x2="22" y2="12" stroke={color} strokeWidth="1" />
      <line x1="12" y1="2" x2="12" y2="22" stroke={color} strokeWidth="1" />
      <circle cx="12" cy="12" r="3" stroke={color} strokeWidth="1" fill="none" />
    </svg>
  );
}

// ─── Arrow ──────────────────────────────────────────────
function Arrow({ size = 14, color = "currentColor", className = "arr" }) {
  return (
    <svg width={size} height={size} viewBox="0 0 14 14" fill="none" className={className}>
      <path d="M2 12 L12 2 M5 2 H12 V9" stroke={color} strokeWidth="1.4" strokeLinecap="square" />
    </svg>
  );
}

// ─── Live clock ────────────────────────────────────────
const PV_CITIES = [["SAN FRANCISCO","America/Los_Angeles"],["NEW YORK","America/New_York"],["BOSTON","America/New_York"],["LONDON","Europe/London"],["PARIS","Europe/Paris"],["ZURICH","Europe/Zurich"],["BERLIN","Europe/Berlin"]];
// ─── Logo ticker (top-right) — drag-spinnable wheel ────────
function LogoTicker() {
  const logos = (window.PV_DATA.portfolio || []).filter(c => c.logo);
  const wrapRef = React.useRef(null), stripRef = React.useRef(null);
  React.useEffect(() => {
    const strip = stripRef.current, wrap = wrapRef.current;
    if (!strip || !wrap) return;
    let off = 0, v = -14, dragging = false, lastX = 0, lastT = 0, raf;
    const tick = (t) => {
      const w = strip.scrollWidth / 2;
      if (!dragging && w > 0) {
        off += v * 0.016;
        if (Math.abs(v) > 14) v *= 0.94; else v = v < 0 ? -14 : 14;
      }
      if (w > 0) { off = ((off % w) + w) % w; strip.style.transform = 'translateX(' + (-off) + 'px)'; }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    const down = (e) => { dragging = true; lastX = e.clientX; lastT = performance.now(); wrap.classList.add('dragging'); wrap.setPointerCapture(e.pointerId); };
    const move = (e) => {
      if (!dragging) return;
      const dx = e.clientX - lastX, now = performance.now(), dt = Math.max(now - lastT, 1) / 1000;
      off -= dx; v = -dx / dt * 0.6; lastX = e.clientX; lastT = now;
    };
    const up = () => { dragging = false; wrap.classList.remove('dragging'); if (Math.abs(v) > 600) v = Math.sign(v) * 600; };
    wrap.addEventListener('pointerdown', down);
    wrap.addEventListener('pointermove', move);
    wrap.addEventListener('pointerup', up);
    wrap.addEventListener('pointercancel', up);
    return () => { cancelAnimationFrame(raf); wrap.removeEventListener('pointerdown', down); wrap.removeEventListener('pointermove', move); wrap.removeEventListener('pointerup', up); wrap.removeEventListener('pointercancel', up); };
  }, []);
  if (!logos.length) return null;
  const strip = logos.concat(logos);
  return (
    <span className="nav-ticker" ref={wrapRef}>
      <span className="nt-strip" ref={stripRef}>
        {strip.map((c, k) => [
          <img key={k + 'i'} className="nt-i" src={pvAbs(c.monoInk || c.logo)} alt={c.name} title={c.name} draggable="false" />,
          <img key={k + 'w'} className="nt-w" src={pvAbs(c.monoWhite || c.logo)} alt={c.name} title={c.name} draggable="false" />
        ])}
      </span>
    </span>
  );
}

function Clock() {
  const [pick] = useState(() => PV_CITIES[Math.floor(Math.random() * PV_CITIES.length)]);
  const [t, setT] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => setT(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  let s;
  try { s = new Intl.DateTimeFormat('en-GB', { timeZone: pick[1], hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).format(t); }
  catch (e) { s = t.toTimeString().slice(0, 8); }
  return <span className="nav-clock">{pick[0]} — {s}</span>;
}

// ─── Nav ────────────────────────────────────────────
function Nav({ page, setPage }) {
  const items = [
    { id: 'manifesto', label: 'Manifesto' },
    { id: 'portfolio', label: 'Explorers' },
    { id: 'about', label: 'Team' },
    { id: 'insights', label: 'Insights' }
  ];
  const [open, setOpen] = React.useState(false);
  const go = (id) => { setOpen(false); setPage(id); };
  return (
    <nav className="nav">
      <div className="shell nav-inner">
        <div className="nav-left">
          <div className="nav-logo" onClick={() => setPage('home')}>
            <img className="wm-img wm-dark" src={(window.__resources && window.__resources.wmDark) || pvAbs('assets/wordmark-darkblue.svg')} alt="Pace Ventures" />
            <img className="wm-img wm-white" src={(window.__resources && window.__resources.wmWhite) || pvAbs('assets/wordmark-white.svg')} alt="Pace Ventures" />
          </div>
        </div>
        <div className="nav-links">
          {items.map(it => (
            <div key={it.id}
              className={"nav-link" + (page === it.id ? " active" : "")}
              onClick={() => setPage(it.id)}>
              {it.label}
            </div>
          ))}
        </div>
        <div className="nav-right">
          {(window.__NAV_RIGHT || 'ticker') === 'lplogin'
            ? <button className="nav-lp" onClick={() => setPage('lplogin')}>LP Login</button>
            : <LogoTicker />}
          <button className={"nav-burger" + (open ? " open" : "")} aria-label="Menu" onClick={() => setOpen(o => !o)}><span></span><span></span></button>
        </div>
      </div>
      {open && <div className="nav-menu">
        {items.map(it => (
          <div key={it.id} className={"nav-menu-link" + (page === it.id ? " active" : "")} onClick={() => go(it.id)}>{it.label}</div>
        ))}
      </div>}
    </nav>
  );
}

// ─── LP access request ──────────────────────────────
// No password field on purpose: there is no authentication behind this page yet,
// so asking for one would collect a real credential and discard it.
//
// Submitting opens the visitor's mail client with a prefilled message to LP_CONTACT.
// This is a stopgap until the real dataroom exists: it needs no backend, but it does
// depend on the visitor having a mail client and actually pressing send.
const LP_CONTACT = 'info@paceventures.com';

function LPLoginPage({ setPage }) {
  const [sent, setSent] = React.useState(false);
  const submit = (e) => {
    e.preventDefault();
    const email = (e.target.querySelector('#lp-email') || {}).value || '';
    if (LP_CONTACT) {
      const subject = encodeURIComponent('LP dataroom access request');
      const body = encodeURIComponent('Please send LP dataroom access details to: ' + email);
      try { window.location.href = 'mailto:' + LP_CONTACT + '?subject=' + subject + '&body=' + body; } catch (err) {}
    }
    setSent(true);
  };
  return (
    <div className="lp-wrap">
    <div className="shell lp-page">
      <div className="hero-meta"><span className="dot"></span><span>LP ACCESS</span></div>
      {sent
        ? <div className="lp-box">
            <h1 className="lp-title">Thank you.</h1>
            <p className="lp-sub">The Pace team will be in touch with your dataroom access details.</p>
            <button type="button" className="lp-btn" onClick={() => setPage('home')}>Back to site</button>
          </div>
        : <form className="lp-box" onSubmit={submit}>
            <h1 className="lp-title" style={{marginBottom: 14}}>Limited Partner access</h1>
            <p className="lp-sub" style={{marginBottom: 34}}>The LP dataroom is being set up. Leave your email and we will send your access details.</p>
            <label className="lp-label" htmlFor="lp-email">Email</label>
            <input className="lp-input" id="lp-email" type="email" required autoComplete="email" placeholder="you@firm.com" />
            <button className="lp-btn" type="submit">Request access</button>
          </form>}
    </div>
    <Footer setPage={setPage} />
    </div>
  );
}

// ─── Footer ─────────────────────────────────────────
function ThemeToggle() {
  const readTheme = () => document.documentElement.getAttribute('data-theme') || 'light';
  const [t, setT] = React.useState(readTheme);
  // Re-read after mount: if anything set data-theme after the first render, the
  // switch would otherwise be stuck showing the pre-render value.
  React.useEffect(() => { setT(readTheme()); }, []);
  const flip = () => {
    const next = t === 'dark' ? 'light' : 'dark';
    document.documentElement.setAttribute('data-theme', next);
    try { localStorage.setItem('pv-theme', next); } catch (e) {}
    setT(next);
  };
  return <a className="ft-theme ft-toggle" onClick={flip} title="Switch theme" aria-label="Switch theme" data-on={t === 'dark' ? '1' : null}><span className="ft-switch"></span></a>;
}
function Footer({ setPage }) {
  return (
    <footer className="footer">
      <div className="shell">
        <div className="footer-tag">On <em>Pace</em> to make History.</div>
        <div className="footer-bottom">
          <div>© Pace Ventures <a className="ft-legal" onClick={() => setPage('lplogin')} style={{marginLeft: 14}}>LP Login</a></div>
          <div className="right">
            <a className="ft-legal" onClick={() => setPage('legal')}>Privacy &amp; Imprint</a>
            <a href="https://www.linkedin.com/company/paceventures/" target="_blank" rel="noreferrer">LinkedIn</a>
            <ThemeToggle />
          </div>
        </div>
      </div>
    </footer>
  );
}

// ─── Fade-up scroll observer ─────────────────────────
function useFadeUp() {
  useEffect(() => {
    if (typeof IntersectionObserver === 'undefined') return;
    let io;
    try {
      io = new IntersectionObserver((entries) => {
        entries.forEach(e => {
          if (e.isIntersecting || e.intersectionRatio > 0) {
            e.target.classList.add('armed', 'in');
            io.unobserve(e.target);
          }
        });
      }, { threshold: 0, rootMargin: '0px 0px -10% 0px' });
    } catch (err) { return; }

    // Arm only the elements currently OUT of view; in-view stays plain visible.
    const els = document.querySelectorAll('.fade-up:not(.in)');
    els.forEach(el => {
      const r = el.getBoundingClientRect();
      const inView = r.top < window.innerHeight && r.bottom > 0;
      if (!inView) {
        el.classList.add('armed');
        io.observe(el);
      }
    });

    // Safety net: if observer never fires for any reason, reveal everything after 1.2s.
    const safety = setTimeout(() => {
      document.querySelectorAll('.fade-up.armed:not(.in)').forEach(el => el.classList.add('in'));
    }, 1200);

    return () => { clearTimeout(safety); io && io.disconnect(); };
  });
}

Object.assign(window, { ThemeToggle, Logo, Crosshair, Arrow, Clock, LogoTicker, Nav, Footer, useFadeUp, Scribble, pvAbs, pvAbsHtml });
