// Fixed background layers — matches atopile.io home:
//   · faint orange grid (CSS background-image)
//   · soft radial glow (CSS radial-gradient)
//   · canvas "tracer" snakes walking the grid in brand orange
// Canvas animation ported from apps/marketing-site/src/app/page.tsx.

function Background() {
  const canvasRef = React.useRef(null);

  React.useEffect(() => {
    const C = canvasRef.current;
    if (!C) return;
    const X = C.getContext("2d");
    if (!X) return;

    const G = 48;
    const NUM = 7;
    const DX = [1, 0, -1, 0];
    const DY = [0, 1, 0, -1];

    const snakes = [];
    let rafId = 0;
    let last = 0;

    const cols = () => Math.ceil(C.width / G) + 2;
    const rows = () => Math.ceil(C.height / G) + 2;

    const resize = () => {
      C.width = window.innerWidth;
      C.height = window.innerHeight;
    };

    const pickDir = (gx, gy, exclude) => {
      const nc = cols(), nr = rows();
      const out = [];
      for (let d = 0; d < 4; d += 1) {
        if (d === exclude) continue;
        const tx = gx + DX[d], ty = gy + DY[d];
        if (tx >= 0 && tx < nc && ty >= 0 && ty < nr) out.push(d);
      }
      return out;
    };

    const makeSnake = () => {
      const nc = cols(), nr = rows();
      const gx = Math.floor(Math.random() * nc);
      const gy = Math.floor(Math.random() * nr);
      const dirs = pickDir(gx, gy, -1);
      const dir = dirs[Math.floor(Math.random() * dirs.length)];
      return {
        gx, gy, dir,
        pts: [[gx * G, gy * G]],
        len: 12 + Math.floor(Math.random() * 8),
        speed: 0.45 + Math.random() * 0.5,
        alpha: 0.18 + Math.random() * 0.12,
        t: 0,
        runway: 4 + Math.floor(Math.random() * 8),
      };
    };

    const stepSnake = (s) => {
      s.gx += DX[s.dir];
      s.gy += DY[s.dir];
      const nc = cols(), nr = rows();
      if (s.gx < 0 || s.gx >= nc || s.gy < 0 || s.gy >= nr) return false;

      s.pts.push([s.gx * G, s.gy * G]);
      if (s.pts.length > s.len + 1) s.pts.shift();

      s.runway -= 1;
      const reverse = (s.dir + 2) % 4;
      const cw = (s.dir + 1) % 4;
      const ccw = (s.dir + 3) % 4;
      const fwdOk =
        s.gx + DX[s.dir] >= 0 && s.gx + DX[s.dir] < nc &&
        s.gy + DY[s.dir] >= 0 && s.gy + DY[s.dir] < nr;
      const hitWall = !fwdOk;

      if (hitWall || (s.runway <= 0 && Math.random() < 0.5)) {
        let opts = [];
        [cw, ccw].forEach((d) => {
          const tx = s.gx + DX[d], ty = s.gy + DY[d];
          if (tx >= 0 && tx < nc && ty >= 0 && ty < nr) opts.push(d);
        });
        if (!hitWall && fwdOk) opts.push(s.dir);
        if (!opts.length) opts = pickDir(s.gx, s.gy, reverse);
        if (!opts.length) return false;
        s.dir = opts[Math.floor(Math.random() * opts.length)];
        s.runway = 4 + Math.floor(Math.random() * 9);
      }
      return true;
    };

    const updateSnake = (s, dt) => {
      s.t += s.speed * dt;
      while (s.t >= 1) {
        s.t -= 1;
        if (!stepSnake(s)) return makeSnake();
      }
      return s;
    };

    const drawSnake = (s) => {
      if (s.pts.length < 1) return;
      const lastCorner = s.pts[s.pts.length - 1];
      const hx = lastCorner[0] + DX[s.dir] * s.t * G;
      const hy = lastCorner[1] + DY[s.dir] * s.t * G;

      const pts = s.pts.slice();
      pts.push([hx, hy]);
      const n = pts.length;

      X.lineWidth = 1.5;
      X.lineCap = "square";
      for (let i = 1; i < n; i += 1) {
        const a = Math.pow(i / (n - 1), 1.8) * s.alpha;
        X.strokeStyle = `rgba(249,80,21,${a.toFixed(3)})`;
        X.beginPath();
        X.moveTo(pts[i - 1][0], pts[i - 1][1]);
        X.lineTo(pts[i][0], pts[i][1]);
        X.stroke();
      }

      X.fillStyle = `rgba(249,80,21,${Math.min(s.alpha * 1.8, 0.8).toFixed(3)})`;
      X.beginPath();
      X.arc(hx, hy, 2, 0, 6.2832);
      X.fill();
    };

    const frame = (ts) => {
      rafId = window.requestAnimationFrame(frame);
      const dt = Math.min((ts - last) / 1000, 0.05);
      last = ts;
      X.clearRect(0, 0, C.width, C.height);
      for (let i = 0; i < snakes.length; i += 1) {
        snakes[i] = updateSnake(snakes[i], dt);
        drawSnake(snakes[i]);
      }
    };

    resize();
    window.addEventListener("resize", resize);

    for (let i = 0; i < NUM; i += 1) {
      const s = makeSnake();
      const warmup = 20 + Math.floor(Math.random() * 40);
      for (let j = 0; j < warmup; j += 1) stepSnake(s);
      snakes.push(s);
    }

    rafId = window.requestAnimationFrame(frame);

    return () => {
      window.cancelAnimationFrame(rafId);
      window.removeEventListener("resize", resize);
    };
  }, []);

  // Portal the fixed layers directly into <body> so they're siblings of
  // #root, not descendants. That keeps their "position: fixed" anchored to
  // the viewport regardless of any stacking context created on #root, and
  // guarantees they stay put while content scrolls.
  return ReactDOM.createPortal(
    <React.Fragment>
      <div className="bg-grid" aria-hidden="true"/>
      <div className="bg-glow" aria-hidden="true"/>
      <canvas ref={canvasRef} className="bg-canvas" aria-hidden="true"/>
    </React.Fragment>,
    document.body
  );
}

window.Background = Background;
