// Ambient page background: gears running on closed-loop belts, drifting + spinning.
// Airy/ambient in the spirit of bloom-network, but themed to ActionBoard's gear
// motif. Fixed, full-viewport, non-interactive (pointer-events:none). Shows through
// the dark sections of the page for a continuous animated backdrop.

const GearFieldBG = () => {
  const canvasRef = React.useRef(null);
  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    let W = 0, H = 0, DPR = 1, raf = 0, loops = [], solo = [];
    const HUES = [262, 32, 200, 158, 344]; // violet, amber, blue, emerald, rose

    const buildLoop = (cx, cy, a, b) => {
      const r = Math.min(a, b) * 0.6, pts = [], step = 5;
      const push = (x, y) => pts.push({ x, y });
      const line = (x0, y0, x1, y1) => { const d = Math.hypot(x1 - x0, y1 - y0), n = Math.max(2, Math.round(d / step)); for (let i = 0; i < n; i++) { const t = i / n; push(x0 + (x1 - x0) * t, y0 + (y1 - y0) * t); } };
      const arc = (ax, ay, a0, a1) => { const d = Math.abs(a1 - a0) * r, n = Math.max(4, Math.round(d / step)); for (let i = 0; i < n; i++) { const t = i / n, an = a0 + (a1 - a0) * t; push(ax + Math.cos(an) * r, ay + Math.sin(an) * r); } };
      line(cx - a + r, cy - b, cx + a - r, cy - b);
      arc(cx + a - r, cy - b + r, -Math.PI / 2, 0);
      line(cx + a, cy - b + r, cx + a, cy + b - r);
      arc(cx + a - r, cy + b - r, 0, Math.PI / 2);
      line(cx + a - r, cy + b, cx - a + r, cy + b);
      arc(cx - a + r, cy + b - r, Math.PI / 2, Math.PI);
      line(cx - a, cy + b - r, cx - a, cy - b + r);
      arc(cx - a + r, cy - b + r, Math.PI, Math.PI * 1.5);
      let acc = 0;
      for (let i = 0; i < pts.length; i++) {
        const p = pts[i], q = pts[(i + 1) % pts.length], m = pts[(i - 1 + pts.length) % pts.length];
        p.s = acc; acc += Math.hypot(q.x - p.x, q.y - p.y);
        let tx = q.x - m.x, ty = q.y - m.y; const L = Math.hypot(tx, ty) || 1; tx /= L; ty /= L;
        p.nx = -ty; p.ny = tx;
      }
      return { pts, len: acc };
    };
    const at = (loop, s) => {
      const { pts, len } = loop; s = ((s % len) + len) % len;
      let lo = 0, hi = pts.length - 1;
      while (lo < hi) { const mid = (lo + hi + 1) >> 1; if (pts[mid].s <= s) lo = mid; else hi = mid - 1; }
      return pts[lo];
    };

    const layout = () => {
      loops = []; solo = [];
      const specs = [
        { cx: W * 0.24, cy: H * 0.30, a: Math.min(W * 0.24, 420), b: Math.min(H * 0.22, 230), n: 4, dir: 1, spd: 20 },
        { cx: W * 0.74, cy: H * 0.62, a: Math.min(W * 0.30, 520), b: Math.min(H * 0.26, 280), n: 5, dir: -1, spd: 16 },
        { cx: W * 0.52, cy: H * 0.16, a: Math.min(W * 0.34, 620), b: Math.min(H * 0.12, 150), n: 4, dir: 1, spd: 24 },
      ];
      for (const sp of specs) {
        const loop = buildLoop(sp.cx, sp.cy, sp.a, sp.b);
        loop.dir = sp.dir; loop.spd = sp.spd;
        loop.gears = [];
        for (let i = 0; i < sp.n; i++) {
          const R = 16 + Math.random() * 20;
          loop.gears.push({ s: (i / sp.n) * loop.len, R, teeth: Math.round(R / 4) + 7, rot: Math.random() * 6, hue: HUES[(i + specs.indexOf(sp)) % HUES.length] });
        }
        loops.push(loop);
      }
      // large slow solo gears for depth
      const soloSpecs = [[W * 0.12, H * 0.78, 120], [W * 0.9, H * 0.2, 150], [W * 0.62, H * 0.9, 96], [W * 0.4, H * 0.55, 74]];
      solo = soloSpecs.map(([x, y, R], i) => ({ x, y, R, teeth: Math.round(R / 8) + 10, rot: Math.random() * 6, dir: i % 2 ? -1 : 1, hue: HUES[i % HUES.length] }));
    };

    const resize = () => {
      DPR = Math.min(window.devicePixelRatio || 1, 2);
      W = window.innerWidth; H = window.innerHeight;
      canvas.width = W * DPR; canvas.height = H * DPR; ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
      layout();
    };
    window.addEventListener('resize', resize);

    const gearPath = (x, y, R, teeth, rot) => {
      const ri = R * 0.80;
      ctx.beginPath();
      for (let i = 0; i < teeth; i++) {
        const a0 = rot + (i / teeth) * Math.PI * 2, step = (Math.PI * 2 / teeth) / 4;
        const p = (rr, aa) => [x + Math.cos(aa) * rr, y + Math.sin(aa) * rr];
        const A = p(ri, a0), B = p(R, a0 + step * 0.9), C = p(R, a0 + step * 2.1), D = p(ri, a0 + step * 3);
        if (i === 0) ctx.moveTo(A[0], A[1]); else ctx.lineTo(A[0], A[1]);
        ctx.lineTo(B[0], B[1]); ctx.lineTo(C[0], C[1]); ctx.lineTo(D[0], D[1]);
      }
      ctx.closePath();
    };
    const drawGear = (x, y, R, teeth, rot, hue, alpha) => {
      ctx.strokeStyle = `hsla(${hue},70%,72%,${alpha})`;
      ctx.lineWidth = 1.1;
      gearPath(x, y, R, teeth, rot); ctx.stroke();
      ctx.beginPath(); ctx.arc(x, y, R * 0.46, 0, 7); ctx.stroke();
      const sp = R > 60 ? 6 : 4;
      ctx.lineWidth = Math.max(1, R * 0.045);
      for (let i = 0; i < sp; i++) {
        const a = rot + (i / sp) * Math.PI * 2;
        ctx.beginPath();
        ctx.moveTo(x + Math.cos(a) * R * 0.46, y + Math.sin(a) * R * 0.46);
        ctx.lineTo(x + Math.cos(a) * R * 0.72, y + Math.sin(a) * R * 0.72);
        ctx.stroke();
      }
      ctx.beginPath(); ctx.arc(x, y, R * 0.12, 0, 7);
      ctx.fillStyle = `hsla(${hue},80%,72%,${alpha * 1.4})`; ctx.fill();
    };

    let last = performance.now();
    const step = (now) => {
      const dt = Math.min(0.05, (now - last) / 1000); last = now;
      ctx.fillStyle = '#08080c'; ctx.fillRect(0, 0, W, H);
      // ambient washes
      const wash = (cx, cy, rad, col) => { const g = ctx.createRadialGradient(cx, cy, 0, cx, cy, rad); g.addColorStop(0, col); g.addColorStop(1, 'rgba(0,0,0,0)'); ctx.fillStyle = g; ctx.fillRect(0, 0, W, H); };
      wash(W * 0.2, H * 0.25, W * 0.5, 'rgba(124,58,237,0.10)');
      wash(W * 0.82, H * 0.7, W * 0.5, 'rgba(245,158,11,0.06)');

      // solo depth gears
      for (const g of solo) {
        g.rot += g.dir * 0.12 * dt;
        drawGear(g.x, g.y, g.R, g.teeth, g.rot, g.hue, 0.06);
      }

      // belts + traveling gears
      for (const loop of loops) {
        const { pts } = loop;
        ctx.lineJoin = 'round'; ctx.lineCap = 'round';
        ctx.beginPath(); ctx.moveTo(pts[0].x, pts[0].y);
        for (let i = 1; i < pts.length; i += 2) ctx.lineTo(pts[i].x, pts[i].y);
        ctx.closePath();
        ctx.strokeStyle = 'rgba(255,255,255,0.05)'; ctx.lineWidth = 2; ctx.stroke();
        const ds = loop.dir * loop.spd * dt;
        for (const g of loop.gears) {
          g.s += ds; g.rot -= ds / g.R;
          const p = at(loop, g.s);
          const off = g.R * 0.9;
          const gx = p.x + p.nx * off, gy = p.y + p.ny * off;
          drawGear(gx, gy, g.R, g.teeth, g.rot, g.hue, 0.16);
        }
      }
      raf = requestAnimationFrame(step);
    };

    resize();
    if (reduce) { step(performance.now()); cancelAnimationFrame(raf); }
    else raf = requestAnimationFrame(step);

    return () => { cancelAnimationFrame(raf); window.removeEventListener('resize', resize); };
  }, []);
  return <canvas ref={canvasRef} className="lp-gearfield-canvas" aria-hidden="true" />;
};

Object.assign(window, { GearFieldBG });

// Section-contained gears: a faint, animated gear-and-belt field sized to its parent
// section. Transparent (no dark fill) so it overlays LIGHT section backgrounds and
// keeps text readable. Used behind the AI Labs and bottom sections.
const SectionGears = () => {
  const canvasRef = React.useRef(null);
  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    const host = canvas.parentElement;
    if (!host) return;
    const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    let W = 0, H = 0, DPR = 1, raf = 0, loops = [], solo = [];

    const buildLoop = (cx, cy, a, b) => {
      const r = Math.min(a, b) * 0.6, pts = [], step = 6;
      const push = (x, y) => pts.push({ x, y });
      const line = (x0, y0, x1, y1) => { const d = Math.hypot(x1 - x0, y1 - y0), n = Math.max(2, Math.round(d / step)); for (let i = 0; i < n; i++) { const t = i / n; push(x0 + (x1 - x0) * t, y0 + (y1 - y0) * t); } };
      const arc = (ax, ay, a0, a1) => { const d = Math.abs(a1 - a0) * r, n = Math.max(4, Math.round(d / step)); for (let i = 0; i < n; i++) { const t = i / n, an = a0 + (a1 - a0) * t; push(ax + Math.cos(an) * r, ay + Math.sin(an) * r); } };
      line(cx - a + r, cy - b, cx + a - r, cy - b);
      arc(cx + a - r, cy - b + r, -Math.PI / 2, 0);
      line(cx + a, cy - b + r, cx + a, cy + b - r);
      arc(cx + a - r, cy + b - r, 0, Math.PI / 2);
      line(cx + a - r, cy + b, cx - a + r, cy + b);
      arc(cx - a + r, cy + b - r, Math.PI / 2, Math.PI);
      line(cx - a, cy + b - r, cx - a, cy - b + r);
      arc(cx - a + r, cy - b + r, Math.PI, Math.PI * 1.5);
      let acc = 0;
      for (let i = 0; i < pts.length; i++) {
        const p = pts[i], q = pts[(i + 1) % pts.length], m = pts[(i - 1 + pts.length) % pts.length];
        p.s = acc; acc += Math.hypot(q.x - p.x, q.y - p.y);
        let tx = q.x - m.x, ty = q.y - m.y; const L = Math.hypot(tx, ty) || 1; tx /= L; ty /= L;
        p.nx = -ty; p.ny = tx;
      }
      return { pts, len: acc };
    };
    const at = (loop, s) => {
      const { pts, len } = loop; s = ((s % len) + len) % len;
      let lo = 0, hi = pts.length - 1;
      while (lo < hi) { const mid = (lo + hi + 1) >> 1; if (pts[mid].s <= s) lo = mid; else hi = mid - 1; }
      return pts[lo];
    };
    const layout = () => {
      loops = []; solo = [];
      const specs = [
        { cx: W * 0.20, cy: H * 0.34, a: Math.min(W * 0.26, 440), b: Math.min(H * 0.34, 200), n: 4, dir: 1, spd: 18 },
        { cx: W * 0.80, cy: H * 0.64, a: Math.min(W * 0.30, 520), b: Math.min(H * 0.36, 230), n: 5, dir: -1, spd: 15 },
      ];
      for (const sp of specs) {
        const loop = buildLoop(sp.cx, sp.cy, sp.a, sp.b);
        loop.dir = sp.dir; loop.spd = sp.spd; loop.gears = [];
        for (let i = 0; i < sp.n; i++) {
          const R = 18 + Math.random() * 22;
          loop.gears.push({ s: (i / sp.n) * loop.len, R, teeth: Math.round(R / 4) + 7, rot: Math.random() * 6 });
        }
        loops.push(loop);
      }
      const soloSpecs = [[W * 0.08, H * 0.82, 110], [W * 0.94, H * 0.18, 130], [W * 0.5, H * 0.5, 80]];
      solo = soloSpecs.map(([x, y, R], i) => ({ x, y, R, teeth: Math.round(R / 8) + 10, rot: Math.random() * 6, dir: i % 2 ? -1 : 1 }));
    };
    const resize = () => {
      DPR = Math.min(window.devicePixelRatio || 1, 2);
      W = host.clientWidth; H = host.clientHeight;
      canvas.width = W * DPR; canvas.height = H * DPR; ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
      layout();
    };

    const gearPath = (x, y, R, teeth, rot) => {
      const ri = R * 0.80;
      ctx.beginPath();
      for (let i = 0; i < teeth; i++) {
        const a0 = rot + (i / teeth) * Math.PI * 2, step = (Math.PI * 2 / teeth) / 4;
        const p = (rr, aa) => [x + Math.cos(aa) * rr, y + Math.sin(aa) * rr];
        const A = p(ri, a0), B = p(R, a0 + step * 0.9), C = p(R, a0 + step * 2.1), D = p(ri, a0 + step * 3);
        if (i === 0) ctx.moveTo(A[0], A[1]); else ctx.lineTo(A[0], A[1]);
        ctx.lineTo(B[0], B[1]); ctx.lineTo(C[0], C[1]); ctx.lineTo(D[0], D[1]);
      }
      ctx.closePath();
    };
    const drawGear = (x, y, R, teeth, rot, alpha) => {
      ctx.strokeStyle = `rgba(124,58,237,${alpha})`;
      ctx.lineWidth = 1.2;
      gearPath(x, y, R, teeth, rot); ctx.stroke();
      ctx.beginPath(); ctx.arc(x, y, R * 0.46, 0, 7); ctx.stroke();
      const sp = R > 60 ? 6 : 4;
      ctx.lineWidth = Math.max(1, R * 0.05);
      for (let i = 0; i < sp; i++) {
        const a = rot + (i / sp) * Math.PI * 2;
        ctx.beginPath();
        ctx.moveTo(x + Math.cos(a) * R * 0.46, y + Math.sin(a) * R * 0.46);
        ctx.lineTo(x + Math.cos(a) * R * 0.72, y + Math.sin(a) * R * 0.72);
        ctx.stroke();
      }
      ctx.beginPath(); ctx.arc(x, y, R * 0.12, 0, 7);
      ctx.fillStyle = `rgba(124,58,237,${alpha * 1.5})`; ctx.fill();
    };

    let last = performance.now();
    const step = (now) => {
      const dt = Math.min(0.05, (now - last) / 1000); last = now;
      ctx.clearRect(0, 0, W, H);
      for (const g of solo) { g.rot += g.dir * 0.1 * dt; drawGear(g.x, g.y, g.R, g.teeth, g.rot, 0.05); }
      for (const loop of loops) {
        const { pts } = loop;
        ctx.lineJoin = 'round'; ctx.lineCap = 'round';
        ctx.beginPath(); ctx.moveTo(pts[0].x, pts[0].y);
        for (let i = 1; i < pts.length; i += 2) ctx.lineTo(pts[i].x, pts[i].y);
        ctx.closePath();
        ctx.strokeStyle = 'rgba(124,58,237,0.05)'; ctx.lineWidth = 2; ctx.stroke();
        const ds = loop.dir * loop.spd * dt;
        for (const g of loop.gears) {
          g.s += ds; g.rot -= ds / g.R;
          const p = at(loop, g.s);
          const off = g.R * 0.9;
          drawGear(p.x + p.nx * off, p.y + p.ny * off, g.R, g.teeth, g.rot, 0.13);
        }
      }
      raf = requestAnimationFrame(step);
    };

    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(host);
    if (reduce) { step(performance.now()); cancelAnimationFrame(raf); }
    else raf = requestAnimationFrame(step);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, []);
  return <canvas ref={canvasRef} className="lp-sgears" aria-hidden="true" />;
};

Object.assign(window, { SectionGears });
