/// file: public/assets/js/modules/work-poly-bg.js
/**
 * Work page ambient background — depth gradient, dual mesh, soft stars, aurora (site palette).
 * Scroll depth (0→1) shifts glow layout and palette; time adds slow drift.
 */

const BASE_MID = '#040814';

function lerp(a, b, t) {
  return a + (b - a) * t;
}

function clamp01(x) {
  return Math.min(1, Math.max(0, x));
}

function scrollRatio() {
  const max = document.documentElement.scrollHeight - window.innerHeight;
  if (max <= 1) return 0;
  return clamp01(window.scrollY / max);
}

/** Stable 0–1 for grid cell (ix, iy). */
function cellHash(ix, iy) {
  const s = Math.sin(ix * 12.9898 + iy * 78.233) * 43758.5453;
  return s - Math.floor(s);
}

function drawBaseGradient(ctx, w, h, sr) {
  const g = ctx.createLinearGradient(0, 0, 0, h);
  g.addColorStop(0, `rgb(${8 + sr * 6}, ${14 + sr * 8}, ${32 + sr * 10})`);
  g.addColorStop(0.42, BASE_MID);
  g.addColorStop(1, `rgb(${2 + sr * 2}, ${4 + sr * 3}, ${10 + sr * 4})`);
  ctx.fillStyle = g;
  ctx.fillRect(0, 0, w, h);

  /* Soft horizon bloom — slowly breathes with scroll */
  const hx = w * (0.48 + sr * 0.12);
  const hy = h * (0.88 - sr * 0.06);
  const horizon = ctx.createRadialGradient(hx, hy, 0, hx, hy, Math.max(w, h) * 0.55);
  horizon.addColorStop(0, `rgba(30, 70, 120, ${0.14 + sr * 0.08})`);
  horizon.addColorStop(0.45, `rgba(12, 28, 58, ${0.05 + sr * 0.04})`);
  horizon.addColorStop(1, 'rgba(4, 8, 20, 0)');
  ctx.fillStyle = horizon;
  ctx.fillRect(0, 0, w, h);
}

function drawRotatedLineField(ctx, w, h, rotation, spacing, drift, stroke) {
  const span = Math.hypot(w, h) * 0.85;
  ctx.save();
  ctx.translate(w * 0.5, h * 0.5);
  ctx.rotate(rotation);
  ctx.translate(-w * 0.5 - (drift % spacing), -h * 0.5);
  ctx.strokeStyle = stroke;
  ctx.lineWidth = 1;
  ctx.beginPath();
  for (let y = -span; y <= span; y += spacing) {
    ctx.moveTo(-span, y);
    ctx.lineTo(span, y);
  }
  ctx.stroke();
  ctx.restore();
}

function drawMeshAndStars(ctx, w, h, tSec, sr, scrollPx, animated) {
  const driftA = tSec * 16 + sr * 95 + scrollPx * 0.09;
  const driftB = tSec * 11 + sr * 70 + scrollPx * 0.07;
  const driftOrthoX = (tSec * 20 + sr * 110 + scrollPx * 0.11) % 56;
  const driftOrthoY = (tSec * 15 + sr * 85 + scrollPx * 0.09) % 56;

  drawRotatedLineField(ctx, w, h, 0.32, 92, driftA, `rgba(56, 140, 195, ${0.042 + sr * 0.018})`);
  drawRotatedLineField(ctx, w, h, -0.28, 104, driftB, `rgba(120, 90, 180, ${0.028 + sr * 0.014})`);

  const step = 56;
  ctx.strokeStyle = `rgba(255, 255, 255, ${0.028 + sr * 0.012})`;
  ctx.lineWidth = 1;
  ctx.beginPath();
  for (let x = -driftOrthoX; x <= w + step; x += step) {
    ctx.moveTo(x, 0);
    ctx.lineTo(x, h);
  }
  for (let y = -driftOrthoY; y <= h + step; y += step) {
    ctx.moveTo(0, y);
    ctx.lineTo(w, y);
  }
  ctx.stroke();

  /* Sparse twinkling points — deterministic placement */
  const starStep = 62;
  const ixMax = Math.ceil(w / starStep) + 1;
  const iyMax = Math.ceil(h / starStep) + 1;
  for (let ix = 0; ix < ixMax; ix++) {
    for (let iy = 0; iy < iyMax; iy++) {
      const h0 = cellHash(ix + 17, iy + 3);
      if (h0 < 0.78) continue;
      const ox = cellHash(ix * 3 + 1, iy * 5 + 2) * starStep * 0.72;
      const oy = cellHash(ix * 7 + 4, iy * 2 + 9) * starStep * 0.72;
      const px = ix * starStep + ox;
      const py = iy * starStep + oy;
      if (px < -4 || py < -4 || px > w + 4 || py > h + 4) continue;
      const tw = animated
        ? 0.22 + 0.2 * Math.sin(tSec * (1.15 + h0 * 0.9) + h0 * 16.7)
        : 0.22;
      const a = clamp01(tw) * (0.12 + sr * 0.1 + h0 * 0.08);
      const r = h0 > 0.94 ? 1.35 : 0.9;
      ctx.fillStyle = `rgba(200, 225, 255, ${a})`;
      ctx.beginPath();
      ctx.arc(px, py, r, 0, Math.PI * 2);
      ctx.fill();
    }
  }
}

function drawAurora(ctx, w, h, tSec, sr, mxN, myN) {
  const m = Math.max(w, h);
  const prev = ctx.globalCompositeOperation;

  /* sr pushes energy downward + warms toward violet (matches electric / accent story) */
  const cx1 =
    w *
    (0.38 +
      0.14 * Math.sin(tSec * 0.055) +
      sr * 0.22 +
      mxN * 0.06);
  const cy1 =
    h *
    (0.12 +
      sr * 0.58 +
      0.05 * Math.sin(tSec * 0.042 + sr * 3) +
      myN * 0.04);

  const g1 = ctx.createRadialGradient(cx1, cy1, 0, cx1, cy1, m * 0.75);
  const a0 = 0.12 + sr * 0.1;
  const a1 = 0.05 + sr * 0.04;
  g1.addColorStop(0, `rgba(56, 165, 220, ${a0})`);
  g1.addColorStop(0.35, `rgba(40, 80, 150, ${a1})`);
  g1.addColorStop(1, 'rgba(4, 8, 20, 0)');

  ctx.globalCompositeOperation = 'soft-light';
  ctx.fillStyle = g1;
  ctx.fillRect(0, 0, w, h);

  const cx2 =
    w *
    (0.62 +
      0.12 * Math.cos(tSec * 0.048 + 1.1) +
      (1 - sr) * 0.08 +
      mxN * -0.05);
  const cy2 =
    h *
    (0.72 +
      sr * -0.15 +
      0.06 * Math.sin(tSec * 0.038) +
      myN * 0.05);

  const g2 = ctx.createRadialGradient(cx2, cy2, 0, cx2, cy2, m * 0.62);
  const vA = 0.08 + sr * 0.12;
  g2.addColorStop(0, `rgba(130, 95, 200, ${vA})`);
  g2.addColorStop(0.45, `rgba(55, 40, 95, ${0.04 + sr * 0.03})`);
  g2.addColorStop(1, 'rgba(4, 8, 20, 0)');
  ctx.fillStyle = g2;
  ctx.fillRect(0, 0, w, h);

  /* Deep scroll: cyan rim from bottom */
  const cx3 = w * (0.5 + 0.35 * Math.sin(tSec * 0.04 + sr * 2));
  const cy3 = h * (0.92 - sr * 0.08);
  const g3 = ctx.createRadialGradient(cx3, cy3, 0, cx3, cy3, m * 0.45);
  g3.addColorStop(0, `rgba(100, 200, 230, ${0.04 + sr * 0.09})`);
  g3.addColorStop(1, 'rgba(4, 8, 20, 0)');

  ctx.globalCompositeOperation = 'screen';
  ctx.fillStyle = g3;
  ctx.fillRect(0, 0, w, h);

  ctx.globalCompositeOperation = prev;
}

function drawVignette(ctx, w, h, sr) {
  const g = ctx.createRadialGradient(
    w * 0.5,
    h * (0.38 + sr * 0.18),
    Math.min(w, h) * 0.06,
    w * 0.5,
    h * 0.52,
    Math.max(w, h) * 0.78
  );
  g.addColorStop(0, 'rgba(0, 0, 0, 0)');
  g.addColorStop(0.62, 'rgba(0, 0, 0, 0)');
  g.addColorStop(1, `rgba(2, 4, 12, ${0.5 + sr * 0.18})`);
  ctx.fillStyle = g;
  ctx.fillRect(0, 0, w, h);
}

export function initWorkPolyBg(root) {
  const canvas = root?.querySelector('.work-page__bg-canvas');
  if (!(canvas instanceof HTMLCanvasElement)) return () => {};

  const ctx = canvas.getContext('2d', { alpha: false });
  if (!ctx) return () => {};

  const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  let cssW = 0;
  let cssH = 0;
  let dpr = 1;
  const t0 = performance.now();

  let smoothSr = 0;
  let smoothMx = 0;
  let smoothMy = 0;
  const target = { mx: 0, my: 0 };

  let raf = 0;

  function resize() {
    dpr = Math.min(window.devicePixelRatio || 1, 2);
    cssW = window.innerWidth;
    cssH = window.innerHeight;
    canvas.width = Math.floor(cssW * dpr);
    canvas.height = Math.floor(cssH * dpr);
    canvas.style.width = `${cssW}px`;
    canvas.style.height = `${cssH}px`;
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
  }

  function paintFrame(now, animated) {
    const tSec = animated ? (now - t0) * 0.001 : 0;
    const sr = scrollRatio();
    smoothSr = lerp(smoothSr, sr, reduced ? 1 : animated ? 0.08 : 1);
    smoothMx = lerp(smoothMx, target.mx, reduced ? 1 : animated ? 0.06 : 1);
    smoothMy = lerp(smoothMy, target.my, reduced ? 1 : animated ? 0.06 : 1);

    const mxN = smoothMx / Math.max(cssW, 1);
    const myN = smoothMy / Math.max(cssH, 1);

    drawBaseGradient(ctx, cssW, cssH, smoothSr);
    drawMeshAndStars(ctx, cssW, cssH, tSec, smoothSr, window.scrollY, animated);
    drawAurora(ctx, cssW, cssH, tSec, smoothSr, mxN, myN);
    drawVignette(ctx, cssW, cssH, smoothSr);
  }

  function drawFrame(now) {
    paintFrame(now, true);
    raf = requestAnimationFrame(drawFrame);
  }

  function drawStatic() {
    paintFrame(performance.now(), false);
  }

  function onScroll() {
    if (reduced) drawStatic();
  }

  function onPointer(e) {
    if (reduced) return;
    target.mx = (e.clientX - cssW * 0.5) * 0.85;
    target.my = (e.clientY - cssH * 0.5) * 0.85;
  }

  resize();
  smoothSr = scrollRatio();

  const onResize = () => {
    resize();
    if (reduced) drawStatic();
  };

  window.addEventListener('resize', onResize, { passive: true });
  window.addEventListener('scroll', onScroll, { passive: true });
  window.addEventListener('pointermove', onPointer, { passive: true });

  if (reduced) {
    drawStatic();
  } else {
    raf = requestAnimationFrame(drawFrame);
  }

  return () => {
    cancelAnimationFrame(raf);
    window.removeEventListener('resize', onResize);
    window.removeEventListener('scroll', onScroll);
    window.removeEventListener('pointermove', onPointer);
  };
}
