// HeroLogoConvergence: pixels scattered → assembled into the EZ logo grid →
// crossfade into the real anti-aliased logo. Auto-plays once on mount and
// rests on the final logo frame. Sized for the hero-mark column.
//
// Plays once when the component mounts. Triggers a re-play if the page is
// scrolled back to top (so revisiting the hero feels alive without being noisy).

const HLC_STAGE = 720;          // square canvas
const HLC_LOGO_W = 460;
const HLC_STRIDE = 6;
const HLC_PIXEL = HLC_STRIDE;
const HLC_BLUE = '#0067a2';
const HLC_ORANGE = '#f47b2e';
const HLC_ASSEMBLE = 3.0;
const HLC_TRANSFORM_END = 4.4;

// Easing helpers (self-contained — don't depend on Easing global)
const _easeOutCubic = (t) => (--t) * t * t + 1;
const _easeInOutSine = (t) => -(Math.cos(Math.PI * t) - 1) / 2;
const _easeInQuad = (t) => t * t;

function SiteHeroLogoConvergence() {
  const canvasRef = React.useRef(null);
  const pixelsRef = React.useRef(null);
  const logoRef = React.useRef(null);
  const logoBoxRef = React.useRef(null);
  const startedAtRef = React.useRef(null);
  const rafRef = React.useRef(null);

  // Build pixel list once
  React.useEffect(() => {
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => {
      logoRef.current = img;
      const aspect = img.height / img.width;
      const targetW = HLC_LOGO_W;
      const targetH = Math.round(targetW * aspect);

      const sampleW = Math.floor(targetW / HLC_STRIDE);
      const sampleH = Math.floor(targetH / HLC_STRIDE);
      const off = document.createElement('canvas');
      off.width = sampleW;
      off.height = sampleH;
      const octx = off.getContext('2d', { willReadFrequently: true });
      octx.drawImage(img, 0, 0, sampleW, sampleH);
      const data = octx.getImageData(0, 0, sampleW, sampleH).data;

      const offsetX = Math.round((HLC_STAGE - targetW) / 2);
      const offsetY = Math.round((HLC_STAGE - targetH) / 2);
      logoBoxRef.current = { x: offsetX, y: offsetY, w: targetW, h: targetH };

      const targets = [];
      for (let y = 0; y < sampleH; y++) {
        for (let x = 0; x < sampleW; x++) {
          const i = (y * sampleW + x) * 4;
          const a = data[i + 3];
          if (a > 80) {
            const r = data[i], g = data[i + 1], b = data[i + 2];
            const isOrange = r > b + 20;
            targets.push({
              tx: offsetX + x * HLC_STRIDE,
              ty: offsetY + y * HLC_STRIDE,
              color: isOrange ? HLC_ORANGE : HLC_BLUE,
            });
          }
        }
      }

      const cx = HLC_STAGE / 2;
      const cy = HLC_STAGE / 2;
      const pixels = targets.map((t) => {
        const angle = Math.random() * Math.PI * 2;
        const radius = 250 + Math.random() * 460;
        const sx = cx + Math.cos(angle) * radius;
        const sy = cy + Math.sin(angle) * radius;
        const delay = Math.random() * 1.3;
        const duration = 1.5 + Math.random() * 1.0;
        return { sx, sy, tx: t.tx, ty: t.ty, color: t.color, delay, duration };
      });
      pixelsRef.current = pixels;

      // Kick off the animation now that data is ready
      startedAtRef.current = performance.now();
      tick();
    };
    img.src = 'assets/logo-transparent.png';

    return () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
    };
  }, []);

  const tick = React.useCallback(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    const pixels = pixelsRef.current;
    if (!pixels) return;

    const now = performance.now();
    const t = (now - startedAtRef.current) / 1000;

    let phase;
    if (t < HLC_ASSEMBLE) phase = 'assemble';
    else if (t < HLC_TRANSFORM_END) phase = 'transform';
    else phase = 'rest';

    let mosaicAlpha = 1;
    let logoAlpha = 0;
    if (phase === 'transform') {
      const local = (t - HLC_ASSEMBLE) / (HLC_TRANSFORM_END - HLC_ASSEMBLE);
      const e = _easeInOutSine(local);
      mosaicAlpha = 1 - e;
      logoAlpha = e;
    } else if (phase === 'rest') {
      mosaicAlpha = 0;
      logoAlpha = 1;
    }

    ctx.clearRect(0, 0, HLC_STAGE, HLC_STAGE);

    if (mosaicAlpha > 0.001) {
      for (const p of pixels) {
        let progress, dx, dy;
        if (phase === 'assemble') {
          const local = (t - p.delay) / p.duration;
          progress = Math.max(0, Math.min(1, local));
          progress = _easeOutCubic(progress);
          dx = p.sx + (p.tx - p.sx) * progress;
          dy = p.sy + (p.ty - p.sy) * progress;
        } else {
          dx = p.tx; dy = p.ty;
          progress = 1;
        }
        const perPixelAlpha = phase === 'assemble'
          ? Math.min(1, progress * 1.4)
          : 1;

        ctx.globalAlpha = mosaicAlpha * perPixelAlpha;
        ctx.fillStyle = p.color;
        ctx.fillRect(Math.round(dx), Math.round(dy), HLC_PIXEL, HLC_PIXEL);
      }
    }

    if (logoAlpha > 0.001 && logoRef.current && logoBoxRef.current) {
      const box = logoBoxRef.current;
      ctx.globalAlpha = logoAlpha;
      ctx.drawImage(logoRef.current, box.x, box.y, box.w, box.h);
    }
    ctx.globalAlpha = 1;

    if (phase !== 'rest') {
      rafRef.current = requestAnimationFrame(tick);
    }
  }, []);

  return (
    <canvas
      ref={canvasRef}
      width={HLC_STAGE}
      height={HLC_STAGE}
      style={{ width: '100%', maxWidth: 460, height: 'auto', display: 'block' }}
      aria-hidden="true"
    />
  );
}
window.SiteHeroLogoConvergence = SiteHeroLogoConvergence;
