// Refined MorphingCell — configurable intensity & accent color. Self-contained
// so the main page can drop it in without importing the old variation-c file.

function OVMorphingCell({ intensity = 1, accent = '#00E5FF', accent2 = '#7C5CFF', accent3 = '#FFB067', showSatellites = true }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let raf;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    const resize = () => {
      const r = canvas.getBoundingClientRect();
      canvas.width = r.width * dpr;
      canvas.height = r.height * dpr;
      ctx.setTransform(1, 0, 0, 1, 0, 0);
      ctx.scale(dpr, dpr);
    };
    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);

    const hexToRgb = (h) => {
      const m = h.replace('#', '');
      return [parseInt(m.slice(0, 2), 16), parseInt(m.slice(2, 4), 16), parseInt(m.slice(4, 6), 16)];
    };
    const [a1r, a1g, a1b] = hexToRgb(accent);
    const [a2r, a2g, a2b] = hexToRgb(accent2);
    const [a3r, a3g, a3b] = hexToRgb(accent3);

    const start = performance.now();
    const tick = (now) => {
      const t = (now - start) / 1000;
      const r = canvas.getBoundingClientRect();
      ctx.clearRect(0, 0, r.width, r.height);

      const cx = r.width * 0.5, cy = r.height * 0.52;
      const baseR = Math.min(r.width, r.height) * 0.28;
      const phase = (Math.sin(t * 0.2) + 1) / 2; // 0 epithelial -> 1 mesenchymal
      const I = intensity;

      // Outer glow
      const glow = ctx.createRadialGradient(cx, cy, 0, cx, cy, baseR * 2.4);
      glow.addColorStop(0, `rgba(${a1r},${a1g},${a1b},${(0.12 + phase * 0.06) * I})`);
      glow.addColorStop(0.5, `rgba(${a2r},${a2g},${a2b},${(0.06 + phase * 0.04) * I})`);
      glow.addColorStop(1, 'rgba(10,14,26,0)');
      ctx.fillStyle = glow;
      ctx.fillRect(0, 0, r.width, r.height);

      // Outer membrane — distortion amplitudes scale with baseR so protrusions
      // look the same at any viewport size.
      const N = 220;
      ctx.strokeStyle = `rgba(${a1r},${a1g},${a1b},${(0.65 - phase * 0.2)})`;
      ctx.lineWidth = 1.3;
      ctx.beginPath();
      for (let i = 0; i <= N; i++) {
        const a = (i / N) * Math.PI * 2;
        const r1 = baseR
          + Math.sin(a * 3 + t * 0.6) * baseR * (0.06 + phase * 0.18) * I
          + Math.sin(a * 7 + t * 0.3) * baseR * (0.04 + phase * 0.14) * I
          + Math.sin(a * 13 + t * 1.2) * baseR * (0.025 + phase * 0.10) * I;
        const stretch = 1 + phase * 0.3 * Math.cos(a);
        const x = cx + Math.cos(a) * r1 * stretch;
        const y = cy + Math.sin(a) * r1;
        if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
      }
      ctx.closePath();
      ctx.shadowColor = accent;
      ctx.shadowBlur = 24 * I;
      ctx.stroke();
      ctx.shadowBlur = 0;

      // Inner membrane echo
      ctx.strokeStyle = `rgba(${a2r},${a2g},${a2b},${(0.3 - phase * 0.1)})`;
      ctx.lineWidth = 0.9;
      ctx.beginPath();
      for (let i = 0; i <= N; i++) {
        const a = (i / N) * Math.PI * 2;
        const r1 = baseR * 0.7
          + Math.sin(a * 5 + t * 0.8) * baseR * (0.04 + phase * 0.10) * I
          + Math.sin(a * 11 + t * 0.5) * baseR * (0.03 + phase * 0.08) * I;
        const x = cx + Math.cos(a) * r1;
        const y = cy + Math.sin(a) * r1;
        if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
      }
      ctx.closePath();
      ctx.stroke();

      // Nucleus — small pulsing kernel
      const nr = baseR * (0.22 + Math.sin(t * 0.9) * 0.04);
      const ng = ctx.createRadialGradient(cx, cy, 0, cx, cy, nr);
      ng.addColorStop(0, `rgba(${a1r},${a1g},${a1b},${0.18})`);
      ng.addColorStop(1, `rgba(${a1r},${a1g},${a1b},0)`);
      ctx.fillStyle = ng;
      ctx.beginPath();
      ctx.arc(cx, cy, nr, 0, Math.PI * 2);
      ctx.fill();

      // Ion channel flickers along membrane
      for (let i = 0; i < 50; i++) {
        const a = (i / 50) * Math.PI * 2 + t * 0.08;
        const r1 = baseR + Math.sin(a * 3 + t * 0.6) * baseR * (0.06 + phase * 0.18) * I;
        const stretch = 1 + phase * 0.3 * Math.cos(a);
        const x = cx + Math.cos(a) * r1 * stretch;
        const y = cy + Math.sin(a) * r1;
        const flicker = Math.sin(t * 2.2 + i * 1.3) * 0.5 + 0.5;
        const useA = i % 3 === 0;
        ctx.fillStyle = useA
          ? `rgba(${a1r},${a1g},${a1b},${flicker})`
          : `rgba(${a2r},${a2g},${a2b},${flicker * 0.7})`;
        ctx.beginPath();
        ctx.arc(x, y, 1.6, 0, Math.PI * 2);
        ctx.fill();
      }

      // Satellite cells — detach more as phase rises
      if (showSatellites) {
        for (let i = 0; i < 10; i++) {
          const a = i * (Math.PI * 2 / 10) + t * 0.12;
          const dist = baseR * (1.6 + phase * 0.9) + Math.sin(t + i) * 12;
          const x = cx + Math.cos(a) * dist;
          const y = cy + Math.sin(a) * dist;
          const alpha = phase * 0.85 * I;
          ctx.strokeStyle = `rgba(${a3r},${a3g},${a3b},${alpha * 0.65})`;
          ctx.lineWidth = 0.7;
          ctx.beginPath();
          ctx.arc(x, y, 12 + Math.sin(t * 1.8 + i) * 3, 0, Math.PI * 2);
          ctx.stroke();

          // connective filament trailing back toward the cell
          if (phase > 0.3) {
            ctx.strokeStyle = `rgba(${a3r},${a3g},${a3b},${alpha * 0.15})`;
            ctx.lineWidth = 0.5;
            ctx.beginPath();
            ctx.moveTo(x, y);
            ctx.lineTo(cx + Math.cos(a) * baseR * 1.05, cy + Math.sin(a) * baseR * 1.05);
            ctx.stroke();
          }
        }
      }

      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, [intensity, accent, accent2, accent3, showSatellites]);

  return <canvas ref={ref} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }} />;
}

Object.assign(window, { OVMorphingCell });
