// Shared primitives: icons, particle field, splat thumbnail, stat counter

const { useState, useEffect, useRef, useMemo } = React;

// Lucide-style line icons (1.5 stroke). Currentcolor.
const Icon = ({ name, size = 20, className = '', style = {} }) => {
  const s = size;
  const sw = 1.5;
  const common = { width: s, height: s, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: sw, strokeLinecap: 'round', strokeLinejoin: 'round', className, style };
  const paths = {
    arrowRight: <><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></>,
    arrowUpRight: <><line x1="7" y1="17" x2="17" y2="7"/><polyline points="7 7 17 7 17 17"/></>,
    chevDown: <polyline points="6 9 12 15 18 9"/>,
    check: <polyline points="20 6 9 17 4 12"/>,
    sparkle: <><path d="M12 3l2.5 6.5L21 12l-6.5 2.5L12 21l-2.5-6.5L3 12l6.5-2.5z"/></>,
    cube: <><polygon points="12 2 22 7 22 17 12 22 2 17 2 7 12 2"/><polyline points="2 7 12 12 22 7"/><line x1="12" y1="12" x2="12" y2="22"/></>,
    layers: <><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></>,
    globe: <><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></>,
    grid: <><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></>,
    play: <polygon points="6 4 20 12 6 20 6 4"/>,
    pause: <><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></>,
    enter: <><path d="M14 5l7 7-7 7"/><path d="M21 12H3"/></>,
    monitor: <><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></>,
    tablet: <><rect x="5" y="2" width="14" height="20" rx="2"/><line x1="12" y1="18" x2="12" y2="18"/></>,
    phone: <><rect x="7" y="2" width="10" height="20" rx="2"/></>,
    bookOpen: <><path d="M2 4h8a2 2 0 0 1 2 2v14H4a2 2 0 0 1-2-2V4z"/><path d="M22 4h-8a2 2 0 0 0-2 2v14h8a2 2 0 0 0 2-2V4z"/></>,
    award: <><circle cx="12" cy="8" r="6"/><path d="M8.21 13.89L7 22l5-3 5 3-1.21-8.12"/></>,
    code: <><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></>,
    sliders: <><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></>,
    user: <><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></>,
    book: <><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></>,
    network: <><circle cx="12" cy="5" r="2"/><circle cx="5" cy="19" r="2"/><circle cx="19" cy="19" r="2"/><path d="M12 7v3M7 19h10M10 18l2-6M14 18l-2-6"/></>,
    school: <><path d="M2 9l10-5 10 5-10 5L2 9z"/><path d="M6 11v6a6 6 0 0 0 12 0v-6"/></>,
  };
  return <svg {...common}>{paths[name] || null}</svg>;
};

// Drifting particle field — used in hero + final CTA
const ParticleField = ({ density = 80, color = '125, 255, 196', baseAlpha = 0.5, speed = 0.06 }) => {
  const ref = useRef(null);
  useEffect(() => {
    const c = ref.current;
    if (!c) return;
    let raf;
    const ctx = c.getContext('2d');
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    const resize = () => {
      const r = c.getBoundingClientRect();
      c.width = r.width * dpr;
      c.height = r.height * dpr;
      c.style.width = r.width + 'px';
      c.style.height = r.height + 'px';
    };
    resize();
    window.addEventListener('resize', resize);

    const pts = [];
    for (let i = 0; i < density; i++) {
      pts.push({
        x: Math.random(), y: Math.random(),
        z: Math.random(), // depth 0..1
        vx: (Math.random() - 0.5) * speed * 0.001,
        vy: (Math.random() - 0.5) * speed * 0.001,
        r: Math.random() * 0.7 + 0.3,
      });
    }
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    let t = 0;
    const draw = () => {
      const w = c.width, h = c.height;
      ctx.clearRect(0, 0, w, h);
      t += 0.003;
      pts.forEach((p, i) => {
        if (!reduce) {
          p.x += p.vx + Math.sin(t + i) * 0.00005;
          p.y += p.vy + Math.cos(t * 0.7 + i) * 0.00005;
          if (p.x < 0) p.x += 1; if (p.x > 1) p.x -= 1;
          if (p.y < 0) p.y += 1; if (p.y > 1) p.y -= 1;
        }
        const size = (p.r + p.z * 1.6) * dpr;
        const alpha = baseAlpha * (0.3 + p.z * 0.7);
        ctx.beginPath();
        ctx.fillStyle = `rgba(${color}, ${alpha})`;
        ctx.arc(p.x * w, p.y * h, size, 0, Math.PI * 2);
        ctx.fill();
        // subtle glow for closer points
        if (p.z > 0.7) {
          ctx.beginPath();
          ctx.fillStyle = `rgba(${color}, ${alpha * 0.15})`;
          ctx.arc(p.x * w, p.y * h, size * 4, 0, Math.PI * 2);
          ctx.fill();
        }
      });
      if (!reduce) raf = requestAnimationFrame(draw);
    };
    draw();
    return () => { cancelAnimationFrame(raf); window.removeEventListener('resize', resize); };
  }, [density, color, baseAlpha, speed]);
  return <canvas ref={ref} className="particle-bg" />;
};

// Splat thumbnail — layered gradients + grain + point cloud edges
const SplatThumb = ({ scheme = 'space', label, density = 60 }) => {
  const schemes = {
    // [bg, layer1 color, layer2 color, accent color]
    space:    { bg: '#070912', a: 'rgba(89, 124, 255, 0.4)',   b: 'rgba(150, 90, 220, 0.35)', c: 'rgba(125, 255, 196, 0.25)' },
    ancient:  { bg: '#100A07', a: 'rgba(245, 158, 11, 0.4)',   b: 'rgba(180, 60, 40, 0.35)',  c: 'rgba(255, 200, 120, 0.25)' },
    cell:     { bg: '#06100C', a: 'rgba(125, 255, 196, 0.4)',  b: 'rgba(60, 200, 180, 0.3)',  c: 'rgba(180, 255, 230, 0.2)' },
    math:     { bg: '#0B0A14', a: 'rgba(167, 139, 250, 0.4)',  b: 'rgba(89, 124, 255, 0.3)',  c: 'rgba(125, 255, 196, 0.2)' },
    story:    { bg: '#0F0807', a: 'rgba(220, 120, 90, 0.4)',   b: 'rgba(160, 80, 100, 0.3)',  c: 'rgba(245, 200, 150, 0.2)' },
    city:     { bg: '#070D10', a: 'rgba(80, 180, 220, 0.4)',   b: 'rgba(125, 255, 196, 0.3)', c: 'rgba(200, 240, 255, 0.2)' },
  };
  const s = schemes[scheme] || schemes.space;
  // deterministic-ish points using a seeded sequence
  const pts = useMemo(() => {
    const out = [];
    let seed = scheme.split('').reduce((a, c) => a + c.charCodeAt(0), 0);
    const rand = () => { seed = (seed * 9301 + 49297) % 233280; return seed / 233280; };
    for (let i = 0; i < density; i++) {
      out.push({ x: rand() * 100, y: rand() * 100, r: rand() * 1.8 + 0.3, o: rand() * 0.7 + 0.2 });
    }
    return out;
  }, [scheme, density]);

  return (
    <div className="splat-thumb" style={{ background: s.bg }}>
      <div className="layer" style={{ background: `radial-gradient(ellipse 70% 50% at 30% 40%, ${s.a}, transparent 70%)` }} />
      <div className="layer" style={{ background: `radial-gradient(ellipse 50% 70% at 70% 60%, ${s.b}, transparent 65%)` }} />
      <div className="layer" style={{ background: `radial-gradient(ellipse 30% 30% at 50% 70%, ${s.c}, transparent 60%)` }} />
      <svg className="pts" viewBox="0 0 100 100" preserveAspectRatio="none" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
        {pts.map((p, i) => (
          <circle key={i} cx={p.x} cy={p.y} r={p.r * 0.15} fill="white" opacity={p.o * 0.5} />
        ))}
      </svg>
      <div className="scanline" />
      <div className="grain" />
      {label && (
        <div className="mono" style={{ position: 'absolute', bottom: 12, left: 14, fontSize: 10, color: 'rgba(255,255,255,0.45)', letterSpacing: '0.08em' }}>
          {label}
        </div>
      )}
    </div>
  );
};

// Number that counts up when visible
const useInView = (ref, opts = { threshold: 0.4 }) => {
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    if (!ref.current || seen) return;
    const obs = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setSeen(true); obs.disconnect(); } }, opts);
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, [ref, seen]);
  return seen;
};

const CountUp = ({ to, duration = 900, suffix = '', prefix = '' }) => {
  const ref = useRef(null);
  const inView = useInView(ref);
  const [val, setVal] = useState(0);
  useEffect(() => {
    if (!inView) return;
    let raf, start;
    const step = (t) => {
      if (!start) start = t;
      const p = Math.min(1, (t - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setVal(Math.round(to * eased));
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [inView, to, duration]);
  return <span ref={ref}>{prefix}{val.toLocaleString()}{suffix}</span>;
};

// Tiny logo mark
const Logo = () => (
  <a href="#" className="logo">
    <span className="logo-mark" />
    <span className="logo-text">The VR School</span>
  </a>
);

Object.assign(window, { Icon, ParticleField, SplatThumb, CountUp, Logo, useInView });
