// ============================================================
// PORTFOLIO UI KIT — primitives
// Icon (Lucide-style, 1.5px stroke), Eyebrow, Button, Reveal
// ============================================================

const ICONS = {
  'arrow-up-right': <g><line x1="7" y1="17" x2="17" y2="7"/><polyline points="7 7 17 7 17 17"/></g>,
  'arrow-right':    <g><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></g>,
  'arrow-left':     <g><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></g>,
  'user':           <g><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></g>,
  'menu':           <g><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></g>,
  'x':              <g><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></g>,
  'plus':           <g><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></g>,
  'arrow-down':     <g><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></g>,
  'mail':           <g><rect x="3" y="5" width="18" height="14" rx="2"/><polyline points="3 7 12 13 21 7"/></g>,
  'corner':         <g><polyline points="6 6 6 18 18 18"/></g>,
  'moon':           <g><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></g>,
  'sun':            <g><circle cx="12" cy="12" r="4"/><line x1="12" y1="2" x2="12" y2="4"/><line x1="12" y1="20" x2="12" y2="22"/><line x1="4.9" y1="4.9" x2="6.3" y2="6.3"/><line x1="17.7" y1="17.7" x2="19.1" y2="19.1"/><line x1="2" y1="12" x2="4" y2="12"/><line x1="20" y1="12" x2="22" y2="12"/><line x1="4.9" y1="19.1" x2="6.3" y2="17.7"/><line x1="17.7" y1="6.3" x2="19.1" y2="4.9"/></g>,
};

function Icon({ name, size = 18, style }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"
      style={style} aria-hidden="true">
      {ICONS[name]}
    </svg>
  );
}

function Eyebrow({ num, children, style }) {
  return (
    <span className="eyebrow" style={style}>
      {num && <span className="num">{num}</span>}
      {children}
    </span>
  );
}

function Button({ variant = 'primary', icon, children, onClick }) {
  return (
    <button className={`btn btn-${variant}`} onClick={onClick}>
      {children}
      {icon && <Icon name={icon} size={16} />}
    </button>
  );
}

// Intersection-observer reveal wrapper
function Reveal({ children, delay = 0, as: Tag = 'div', className = '', style }) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
    }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return (
    <Tag ref={ref} className={`reveal ${seen ? 'in' : ''} ${className}`}
      style={{ transitionDelay: `${delay}ms`, ...style }}>
      {children}
    </Tag>
  );
}

// Theme toggle — persists to localStorage, animates the color swap only
function ThemeToggle() {
  const [theme, setTheme] = React.useState(
    () => (typeof document !== 'undefined' && document.documentElement.dataset.theme) || 'light'
  );
  const toggle = () => {
    const next = theme === 'dark' ? 'light' : 'dark';
    const root = document.documentElement;
    root.classList.add('theme-anim');
    root.dataset.theme = next;
    try { localStorage.setItem('va-theme', next); } catch (e) {}
    setTheme(next);
    window.setTimeout(() => root.classList.remove('theme-anim'), 340);
  };
  return (
    <button className="theme-toggle" onClick={toggle}
      aria-label="Toggle colour theme" title="Toggle theme">
      <Icon name={theme === 'dark' ? 'sun' : 'moon'} size={17} />
    </button>
  );
}

// ---- Systems-thinking creative elements (restrained, decorative) ----

// An abstract node-link "system map": nodes connected by thin lines that
// draw on when scrolled into view. Reinforces the idea of systems &
// connection without ever competing with the type. Recolors per theme.
function SystemMap({ className = '', style }) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver((es) => {
      es.forEach((e) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
    }, { threshold: 0.25 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  // node coordinates (in a 200 x 260 viewBox)
  const N = {
    a: [30, 40], b: [150, 26], c: [98, 96], d: [22, 150],
    e: [168, 130], f: [120, 196], g: [54, 230], h: [176, 224],
  };
  const edges = [['a','c'],['b','c'],['c','d'],['c','e'],['d','g'],['c','f'],['e','f'],['e','h'],['f','g'],['f','h']];
  const accentNodes = ['c', 'f'];
  return (
    <svg ref={ref} className={`system-map ${seen ? 'in' : ''} ${className}`}
      viewBox="0 0 200 260" fill="none" aria-hidden="true" style={style}>
      <g className="sm-edges">
        {edges.map(([p, q], i) => (
          <line key={i} x1={N[p][0]} y1={N[p][1]} x2={N[q][0]} y2={N[q][1]}
            style={{ ['--d']: i }} />
        ))}
      </g>
      <g className="sm-nodes">
        {Object.entries(N).map(([k, [x, y]], i) => (
          <circle key={k} cx={x} cy={y} r={accentNodes.includes(k) ? 4 : 2.6}
            className={accentNodes.includes(k) ? 'sm-node accent' : 'sm-node'}
            style={{ ['--d']: i }} />
        ))}
      </g>
    </svg>
  );
}

// A barely-there fine grid field — architectural linework behind a section.
// Pure decoration; sits at low opacity and never carries content.
function FieldGrid({ className = '', style }) {
  return <div className={`field-grid ${className}`} aria-hidden="true" style={style}></div>;
}

// Lottie wrapper — loads a JSON, recolors to --accent via CSS, plays once
// when scrolled into view (loop optional). Decorative only.
function Lottie({ src, loop = false, speed = 1, height = 26, width, className = '', style }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el || !window.lottie) return;
    const anim = window.lottie.loadAnimation({
      container: el, renderer: 'svg', loop, autoplay: false, path: src,
    });
    if (speed) anim.setSpeed(speed);
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { anim.play(); if (!loop) io.disconnect(); } });
    }, { threshold: 0.35 });
    io.observe(el);
    return () => { io.disconnect(); anim.destroy(); };
  }, [src, loop, speed]);
  return <div ref={ref} className={`lottie ${className}`} aria-hidden="true"
    style={{ height, width: width || '100%', ...style }}></div>;
}

Object.assign(window, { Icon, Eyebrow, Button, Reveal, ThemeToggle, Lottie, SystemMap, FieldGrid });

