/* global React */
// ============================================================
// SERVICE SCENES — bold, robot-driven canvas animations for the
// Services cards, cohesive with the hero's data-cleaning robots.
//   mode="chat"  — robot fields a stream of chat bubbles, answers coral
//   mode="wire"  — robot wires disconnected nodes; data pulses flow
//   mode="build" — robot snaps scattered tiles into a product grid
// Each pauses when off-screen.
// ============================================================
function ServiceScene({ mode }) {
  const canvasRef = React.useRef(null);
  const wrapRef = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current, wrap = wrapRef.current;
    if (!canvas || !wrap) return;
    const ctx = canvas.getContext('2d');
    const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    const TAU = Math.PI * 2;
    let W = 0, H = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
    let raf = 0, lastT = 0, S = null;

    const ease = (dt, rate) => 1 - Math.exp(-dt * rate);
    function rr(x, y, w, h, r) {
      r = Math.min(r, h / 2, w / 2);
      ctx.beginPath();
      ctx.moveTo(x + r, y);
      ctx.arcTo(x + w, y, x + w, y + h, r);
      ctx.arcTo(x + w, y + h, x, y + h, r);
      ctx.arcTo(x, y + h, x, y, r);
      ctx.arcTo(x, y, x + w, y, r);
      ctx.closePath();
    }
    function bot(x, y, s, active, now, ph = 0) {
      const bob = Math.sin(now * 0.004 + ph) * 1.6;
      ctx.save();
      ctx.translate(x, y + bob);
      ctx.scale(s, s);
      const glow = ctx.createRadialGradient(0, 0, 0, 0, 0, 20);
      glow.addColorStop(0, `rgba(239,141,136,${active ? 0.26 : 0.14})`);
      glow.addColorStop(1, 'rgba(239,141,136,0)');
      ctx.fillStyle = glow; ctx.beginPath(); ctx.arc(0, 0, 20, 0, TAU); ctx.fill();
      ctx.strokeStyle = 'rgba(240,234,218,0.8)'; ctx.lineWidth = 1.2;
      ctx.beginPath(); ctx.moveTo(0, -8.5); ctx.lineTo(0, -13); ctx.stroke();
      const blink = 0.6 + 0.4 * Math.sin(now * 0.006 + ph);
      ctx.fillStyle = `rgba(239,141,136,${blink})`;
      ctx.beginPath(); ctx.arc(0, -14.5, 1.9, 0, TAU); ctx.fill();
      rr(-12, -8.5, 24, 17, 5.5); ctx.fillStyle = '#F0EADA'; ctx.fill();
      ctx.lineWidth = 1.1; ctx.strokeStyle = 'rgba(13,43,82,0.55)'; ctx.stroke();
      ctx.fillStyle = '#E8A08C';
      rr(-14.5, -2.5, 2.6, 5, 1.3); ctx.fill();
      rr(11.9, -2.5, 2.6, 5, 1.3); ctx.fill();
      rr(-8.5, -5, 17, 10, 3.5); ctx.fillStyle = '#0D2B52'; ctx.fill();
      ctx.fillStyle = active ? '#EF8D88' : '#A3EBB1';
      ctx.beginPath(); ctx.arc(-3.6, 0, 1.8, 0, TAU); ctx.fill();
      ctx.beginPath(); ctx.arc(3.6, 0, 1.8, 0, TAU); ctx.fill();
      ctx.strokeStyle = 'rgba(194,178,128,0.5)'; ctx.lineWidth = 1;
      ctx.beginPath(); ctx.moveTo(-2.6, 3.2); ctx.lineTo(2.6, 3.2); ctx.stroke();
      ctx.restore();
    }

    // ---------------- Scene builders ----------------
    function buildChat() {
      return { msgs: [], next: 0, pulse: 0 };
    }
    function chat(s, now, dt) {
      if (now > s.next) {
        const side = s.msgs.length % 2 === 0 ? 'in' : 'bot';
        s.msgs.unshift({ side, wf: 0.42 + Math.random() * 0.5, born: now, y: null });
        if (side === 'bot') s.pulse = 1;
        s.next = now + 1300 + Math.random() * 500;
        if (s.msgs.length > 5) s.msgs.pop();
      }
      s.pulse *= Math.exp(-dt * 3);
      const left = 14, right = W - 70, maxw = right - left, baseY = H - 18, sp = 23;
      s.msgs.forEach((m, i) => {
        const ty = baseY - i * sp;
        m.y = m.y == null ? ty + 12 : m.y + (ty - m.y) * ease(dt, 11);
        const age = (now - m.born) / 1000;
        m.alpha = Math.min(1, age * 5) * Math.max(0, 1 - Math.max(0, i - 3) * 0.55);
      });
      for (let i = s.msgs.length - 1; i >= 0; i--) {
        const m = s.msgs[i];
        const w = maxw * m.wf, h = 16;
        const x = m.side === 'in' ? left : right - w;
        const col = m.side === 'bot' ? '239,141,136' : '194,178,128';
        ctx.globalAlpha = m.alpha;
        ctx.fillStyle = `rgba(${col},0.16)`; rr(x, m.y - h / 2, w, h, 7); ctx.fill();
        ctx.strokeStyle = `rgba(${col},0.5)`; ctx.lineWidth = 1; ctx.stroke();
        ctx.fillStyle = `rgba(${col},0.7)`;
        const dots = Math.max(2, (w / 13) | 0);
        for (let d = 0; d < dots && x + 7 + d * 9 + 5 < x + w - 5; d++) ctx.fillRect(x + 7 + d * 9, m.y - 1.5, 5, 3);
        ctx.globalAlpha = 1;
      }
      bot(W - 40, H / 2, 1.0, s.pulse > 0.25, now, 0);
      if (s.pulse > 0.25) {
        ctx.strokeStyle = `rgba(239,141,136,${s.pulse * 0.6})`;
        ctx.lineWidth = 1.4;
        ctx.beginPath(); ctx.arc(W - 40, H / 2, (1 - s.pulse) * 16 + 14, 0, TAU); ctx.stroke();
      }
    }

    function buildWire() {
      const n = 5;
      const nodes = [];
      for (let i = 0; i < n; i++) {
        nodes.push({
          x: 30 + (W - 60) * (i / (n - 1)),
          y: H / 2 + Math.sin(i * 1.7) * (H * 0.22),
          on: false,
        });
      }
      return { nodes, k: 0, phase: 'move', grow: 0, hold: 0, rx: nodes[0].x, ry: nodes[0].y, t: 0 };
    }
    function wire(s, now, dt) {
      const N = s.nodes.length;
      s.t += dt;
      // wires
      for (let i = 0; i < N - 1; i++) {
        const a = s.nodes[i], b = s.nodes[i + 1];
        let frac = i < s.k ? 1 : (i === s.k && s.phase === 'link' ? s.grow : 0);
        if (frac <= 0) continue;
        ctx.strokeStyle = 'rgba(239,141,136,0.55)'; ctx.lineWidth = 1.6;
        ctx.beginPath(); ctx.moveTo(a.x, a.y); ctx.lineTo(a.x + (b.x - a.x) * frac, a.y + (b.y - a.y) * frac); ctx.stroke();
        if (frac >= 1 && s.phase === 'done') {
          const p = (s.t * 0.6) % 1;
          ctx.fillStyle = 'rgba(163,235,177,0.95)';
          ctx.beginPath(); ctx.arc(a.x + (b.x - a.x) * p, a.y + (b.y - a.y) * p, 2.4, 0, TAU); ctx.fill();
        }
      }
      // nodes
      s.nodes.forEach((nd, i) => {
        const on = i <= s.k && (s.phase !== 'move' || i < s.k) || (s.phase === 'done');
        const col = (i <= s.k && s.phase === 'done') || nd.on ? '163,235,177' : (i <= s.k ? '163,235,177' : '194,178,128');
        ctx.fillStyle = `rgba(${col},0.16)`; rr(nd.x - 11, nd.y - 9, 22, 18, 5); ctx.fill();
        ctx.strokeStyle = `rgba(${col},0.6)`; ctx.lineWidth = 1.2; ctx.stroke();
        ctx.fillStyle = `rgba(${col},0.9)`;
        ctx.beginPath(); ctx.arc(nd.x, nd.y, 2.4, 0, TAU); ctx.fill();
      });
      // robot logic
      const tgt = s.nodes[Math.min(s.k, N - 1)];
      if (s.phase === 'move') {
        s.rx += (tgt.x - s.rx) * ease(dt, 6);
        s.ry += (tgt.y - s.ry) * ease(dt, 6);
        if (Math.hypot(tgt.x - s.rx, tgt.y - s.ry) < 2) {
          if (s.k >= N - 1) { s.phase = 'done'; s.hold = 0; }
          else { s.phase = 'link'; s.grow = 0; }
        }
      } else if (s.phase === 'link') {
        s.grow += dt * 1.8;
        const b = s.nodes[s.k + 1];
        s.rx = s.nodes[s.k].x + (b.x - s.nodes[s.k].x) * s.grow;
        s.ry = s.nodes[s.k].y + (b.y - s.nodes[s.k].y) * s.grow;
        if (s.grow >= 1) { s.nodes[s.k + 1].on = true; s.k++; s.phase = 'move'; }
      } else if (s.phase === 'done') {
        s.hold += dt;
        if (s.hold > 1.4) { s.k = 0; s.phase = 'move'; s.nodes.forEach(nd => nd.on = false); s.rx = s.nodes[0].x; s.ry = s.nodes[0].y; }
      }
      bot(s.rx, s.ry - 16, 0.92, s.phase === 'link', now, 1);
    }

    function buildBuild() {
      const cols = 3, rowsN = 2, tw = 26, th = 15, gx = 8, gy = 9;
      const gw = cols * tw + (cols - 1) * gx, gh = rowsN * th + (rowsN - 1) * gy;
      const ox = W - gw - 26, oy = (H - gh) / 2;
      // Loose-tile region: clear of the top-left icon plate and the grid.
      const lxMin = 70, lxMax = Math.max(lxMin + 24, ox - 30), syTop = 50, syH = Math.max(18, H - 70);
      const sxF = () => lxMin + Math.random() * (lxMax - lxMin);
      const syF = () => syTop + Math.random() * syH;
      const tiles = [];
      for (let r = 0; r < rowsN; r++) for (let c = 0; c < cols; c++) {
        tiles.push({
          sx: ox + c * (tw + gx), sy: oy + r * (th + gy),
          x: sxF(), y: syF(), placed: false, fix: 0, tw, th,
        });
      }
      return { tiles, rx: lxMin, ry: H / 2, phase: 'seek', carry: null, hold: 0, ox, oy, gw, gh, sxF, syF };
    }
    function build(s, now, dt) {
      // product frame
      ctx.strokeStyle = 'rgba(240,234,218,0.12)'; ctx.lineWidth = 1;
      rr(s.ox - 6, s.oy - 6, s.gw + 12, s.gh + 12, 6); ctx.stroke();

      const allPlaced = s.tiles.every(t => t.placed);
      // robot logic
      if (s.phase === 'seek') {
        let best = null, bd = Infinity;
        for (const t of s.tiles) if (!t.placed) { const d = Math.hypot(t.x - s.rx, t.y - s.ry); if (d < bd) { bd = d; best = t; } }
        if (!best) { s.phase = 'done'; s.hold = 0; }
        else {
          s.carry = best;
          s.rx += (best.x - s.rx) * ease(dt, 7); s.ry += (best.y - s.ry) * ease(dt, 7);
          if (Math.hypot(best.x - s.rx, best.y - s.ry) < 3) s.phase = 'carry';
        }
      } else if (s.phase === 'carry') {
        const t = s.carry;
        const dx = t.sx + t.tw / 2, dy = t.sy + t.th / 2;
        s.rx += (dx - s.rx) * ease(dt, 6); s.ry += ((dy - 14) - s.ry) * ease(dt, 6);
        t.x = s.rx; t.y = s.ry + 14;
        if (Math.hypot(dx - s.rx, (dy - 14) - s.ry) < 3) { t.placed = true; t.fix = 1; t.x = dx; t.y = dy; s.carry = null; s.phase = 'seek'; }
      } else if (s.phase === 'done') {
        s.hold += dt;
        if (s.hold > 1.4) { for (const t of s.tiles) { t.placed = false; t.x = s.sxF(); t.y = s.syF(); } s.phase = 'seek'; }
      }
      // tiles
      for (const t of s.tiles) {
        t.fix += (0 - t.fix) * ease(dt, 3);
        const placed = t.placed;
        const mint = t.fix, glow = allPlaced ? 0.5 + 0.5 * Math.sin(now * 0.004) : 0;
        let col = placed ? `rgba(${163},${235},${177},${0.22 + glow * 0.2})` : 'rgba(194,178,128,0.16)';
        if (t === s.carry) col = 'rgba(239,141,136,0.22)';
        const cx = placed ? t.sx + t.tw / 2 : t.x, cy = placed ? t.sy + t.th / 2 : t.y;
        ctx.fillStyle = col; rr(cx - t.tw / 2, cy - t.th / 2, t.tw, t.th, 3); ctx.fill();
        ctx.strokeStyle = placed ? `rgba(163,235,177,${0.55 + glow * 0.3})` : (t === s.carry ? 'rgba(239,141,136,0.6)' : 'rgba(194,178,128,0.4)');
        ctx.lineWidth = 1; ctx.stroke();
        if (mint > 0.05) { ctx.strokeStyle = `rgba(163,235,177,${mint * 0.5})`; ctx.beginPath(); ctx.arc(cx, cy, (1 - mint) * 16 + 6, 0, TAU); ctx.stroke(); }
      }
      bot(s.rx, s.ry - 16, 0.92, s.phase === 'carry', now, 2);
    }

    const SIMS = { chat: [buildChat, chat], wire: [buildWire, wire], build: [buildBuild, build] };

    function layout() {
      const rect = wrap.getBoundingClientRect();
      W = rect.width; H = rect.height;
      if (W < 2 || H < 2) return;
      canvas.width = W * dpr; canvas.height = H * dpr;
      canvas.style.width = W + 'px'; canvas.style.height = H + 'px';
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      const b = SIMS[mode] || SIMS.chat;
      S = b[0]();
    }

    function frame(now) {
      const dt = Math.min(0.05, (now - (lastT || now)) / 1000);
      lastT = now;
      ctx.clearRect(0, 0, W, H);
      const sim = (SIMS[mode] || SIMS.chat)[1];
      if (S) sim(S, now, dt);
      if (!reduced) raf = requestAnimationFrame(frame);
    }

    layout();
    raf = requestAnimationFrame(frame);
    const ro = new ResizeObserver(() => layout());
    ro.observe(wrap);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, [mode]);

  return (
    <div ref={wrapRef} style={{ position: 'absolute', inset: 0, overflow: 'hidden' }}>
      <canvas ref={canvasRef} style={{ display: 'block', width: '100%', height: '100%' }} />
    </div>
  );
}

Object.assign(window, { ServiceScene });
