/* eslint-disable */
/* =============================================================
   solar-drift.jsx — premium heliocentric visual for PlanetsPage.
   v2: prerendered sprites + ping-pong trail buffer + 30fps cap.
   -------------------------------------------------------------
   The sun drifts through space (star parallax + helical trails
   stream behind) while the planets orbit it with real relative
   periods. Canvas-based, DPR-aware, clickable planets, respects
   prefers-reduced-motion, pauses off-screen.
   Exposes window.SolarDrift({ selKey, onSelect, lang }).
   ============================================================= */
(function () {
  const { useRef, useEffect } = React;

  // relative orbit radius (fraction of half-size) + period (earth = 1)
  const BODIES = [
    { key: "mercury", r: 0.17, T: 0.24, s: 2.2 },
    { key: "venus",   r: 0.24, T: 0.62, s: 3.0 },
    { key: "earth",   r: 0.31, T: 1.00, s: 3.1 },
    { key: "mars",    r: 0.38, T: 1.88, s: 2.6 },
    { key: "jupiter", r: 0.49, T: 4.0,  s: 5.2 },
    { key: "saturn",  r: 0.60, T: 6.5,  s: 4.6 },
    { key: "uranus",  r: 0.70, T: 9.5,  s: 3.6 },
    { key: "neptune", r: 0.79, T: 12.5, s: 3.5 },
    { key: "pluto",   r: 0.88, T: 16.0, s: 2.0 },
  ];
  const FALLBACK = {
    mercury: "#F4A261", venus: "#FF78B5", earth: "#62DDFF", mars: "#F45F5F",
    jupiter: "#9076FF", saturn: "#F8C648", uranus: "#5FD6B5", neptune: "#5FC8EF", pluto: "#C084FF",
  };
  const TILT = 0.36;            // ellipse squash (perspective)
  const EARTH_PERIOD_S = 26;    // calm pace: earth year = 26s
  const DRIFT = { x: -0.022, y: -0.008 }; // sun's travel (fraction of size/100 per 33ms)
  const FRAME_MS = 33;          // ~30fps — half the work, same calm motion

  window.SolarDrift = function SolarDrift({ selKey, onSelect, lang }) {
    const wrapRef = useRef(null);
    const cvsRef = useRef(null);
    const stateRef = useRef({ selKey, onSelect, lang });
    stateRef.current = { selKey, onSelect, lang };

    useEffect(() => {
      const cvs = cvsRef.current, wrap = wrapRef.current;
      if (!cvs || !wrap) return;
      const ctx = cvs.getContext("2d");
      const reduced = window.matchMedia && matchMedia("(prefers-reduced-motion: reduce)").matches;
      const PDB = window.PLANET_DB || {};
      let W = 0, H = 0, dpr = Math.min(window.devicePixelRatio || 1, 1.5);
      let raf = 0, dead = false, visible = true, hoverKey = null, last = 0;
      const screenPos = {};

      const colorOf = (k) => (PDB[k] && PDB[k].color) || FALLBACK[k] || "#C4B5FF";
      const nameOf = (k) => { const p = PDB[k] || {}; return stateRef.current.lang === "ar" ? (p.ar || k) : (p.en || k); };

      // ── prerendered layers (rebuilt on resize) ──────────────
      let bgLayer, starsA, starsB, trailF, trailB, trailFx, trailBx, sunSprite, raysSprite, sprites = {};
      const mk = (w, h) => { const c = document.createElement("canvas"); c.width = w; c.height = h; return c; };

      function buildLayers() {
        const size = Math.min(W, H);
        const cx = W / 2, cy = H / 2 - size * 0.02;

        // nebula + orbit ellipses (static)
        bgLayer = mk(W, H);
        const bc = bgLayer.getContext("2d");
        const neb = (x, y, r, col, a) => {
          const g = bc.createRadialGradient(x, y, 0, x, y, r);
          g.addColorStop(0, col.replace("A)", a + ")")); g.addColorStop(1, col.replace("A)", "0)"));
          bc.fillStyle = g; bc.fillRect(0, 0, W, H);
        };
        neb(W * 0.78, H * 0.2, size * 0.55, "rgba(98,60,160,A)", 0.16);
        neb(W * 0.18, H * 0.75, size * 0.5, "rgba(40,80,160,A)", 0.12);
        neb(W * 0.5, H * 0.45, size * 0.7, "rgba(150,100,255,A)", 0.05);
        bc.strokeStyle = "rgba(170,150,255,0.075)"; bc.lineWidth = 1;
        BODIES.forEach((b) => {
          const R = b.r * size * 0.5;
          bc.beginPath(); bc.ellipse(cx, cy, R, R * TILT, 0, 0, Math.PI * 2); bc.stroke();
        });

        // two parallax star layers
        const stars = (n, bright) => {
          const c = mk(W, H), sc = c.getContext("2d");
          for (let i = 0; i < n; i++) {
            const r = 0.4 + Math.random() * (bright ? 1.1 : 0.7);
            sc.fillStyle = `rgba(213,215,242,${(bright ? 0.5 : 0.28) + Math.random() * 0.3})`;
            sc.fillRect(Math.random() * W, Math.random() * H, r, r);
          }
          return c;
        };
        starsA = stars(60, false); starsB = stars(45, true);

        // trail ping-pong buffers (CSS-pixel resolution — cheap)
        trailF = mk(W, H); trailB = mk(W, H);
        trailFx = trailF.getContext("2d"); trailBx = trailB.getContext("2d");

        // sun sprite: corona + body
        const sr = size * 0.052, sR = sr * 6;
        sunSprite = mk(sR * 2, sR * 2);
        const sx = sunSprite.getContext("2d");
        let g = sx.createRadialGradient(sR, sR, 0, sR, sR, sR);
        g.addColorStop(0, "rgba(255,236,170,0.55)"); g.addColorStop(0.18, "rgba(248,198,72,0.22)");
        g.addColorStop(0.5, "rgba(248,160,60,0.07)"); g.addColorStop(1, "rgba(248,198,72,0)");
        sx.fillStyle = g; sx.fillRect(0, 0, sR * 2, sR * 2);
        g = sx.createRadialGradient(sR - sr * 0.3, sR - sr * 0.3, sr * 0.1, sR, sR, sr);
        g.addColorStop(0, "#FFFBEA"); g.addColorStop(0.45, "#FFE9A8"); g.addColorStop(0.78, "#F8C648"); g.addColorStop(1, "#E08F2E");
        sx.fillStyle = g; sx.beginPath(); sx.arc(sR, sR, sr, 0, Math.PI * 2); sx.fill();
        // crisp rim
        sx.strokeStyle = "rgba(255,240,190,0.5)"; sx.lineWidth = 1;
        sx.beginPath(); sx.arc(sR, sR, sr, 0, Math.PI * 2); sx.stroke();

        // rotating rays sprite (very subtle, drawn under the sun)
        raysSprite = mk(sR * 2, sR * 2);
        const rx = raysSprite.getContext("2d");
        rx.translate(sR, sR);
        for (let i = 0; i < 7; i++) {
          rx.rotate(Math.PI / 3.5);
          const rg = rx.createLinearGradient(0, 0, sR * 0.95, 0);
          rg.addColorStop(0, "rgba(248,198,72,0.10)"); rg.addColorStop(1, "rgba(248,198,72,0)");
          rx.fillStyle = rg;
          rx.beginPath(); rx.moveTo(sr * 0.4, 0);
          rx.lineTo(sR * 0.95, -sr * 0.5); rx.lineTo(sR * 0.95, sr * 0.5); rx.closePath(); rx.fill();
        }

        // planet sprites (body + glow + saturn ring), highlight up-start
        sprites = {};
        BODIES.forEach((b) => {
          const col = colorOf(b.key);
          const pr = b.s * (size / 340);
          const R = Math.ceil(pr * 5);
          const c = mk(R * 2, R * 2), pc = c.getContext("2d");
          let pg = pc.createRadialGradient(R, R, 0, R, R, pr * 4.2);
          pg.addColorStop(0, hexA(col, 0.32)); pg.addColorStop(1, hexA(col, 0));
          pc.fillStyle = pg; pc.fillRect(0, 0, R * 2, R * 2);
          pg = pc.createRadialGradient(R - pr * 0.42, R - pr * 0.42, pr * 0.12, R, R, pr);
          pg.addColorStop(0, "#ffffff"); pg.addColorStop(0.3, col); pg.addColorStop(1, hexA(col, 0.45));
          pc.fillStyle = pg; pc.beginPath(); pc.arc(R, R, pr, 0, Math.PI * 2); pc.fill();
          // soft terminator (adds depth)
          pg = pc.createRadialGradient(R + pr * 0.55, R + pr * 0.55, pr * 0.1, R, R, pr * 1.02);
          pg.addColorStop(0, "rgba(2,4,13,0.35)"); pg.addColorStop(0.6, "rgba(2,4,13,0)");
          pc.fillStyle = pg; pc.beginPath(); pc.arc(R, R, pr, 0, Math.PI * 2); pc.fill();
          if (b.key === "saturn") {
            pc.strokeStyle = hexA(col, 0.7); pc.lineWidth = 1.4;
            pc.beginPath(); pc.ellipse(R, R, pr * 2.15, pr * 0.72, -0.45, 0, Math.PI * 2); pc.stroke();
            pc.strokeStyle = hexA(col, 0.25); pc.lineWidth = 3;
            pc.beginPath(); pc.ellipse(R, R, pr * 1.8, pr * 0.58, -0.45, 0, Math.PI * 2); pc.stroke();
          }
          sprites[b.key] = { c, R, pr, col };
        });
      }

      const resize = () => {
        const w = wrap.clientWidth || 300;
        W = w; H = Math.round(w * 1.02);
        cvs.width = Math.round(W * dpr); cvs.height = Math.round(H * dpr);
        cvs.style.height = H + "px";
        buildLayers();
      };
      resize();
      const ro = new ResizeObserver(resize);
      ro.observe(wrap);
      const io = new IntersectionObserver((es) => { visible = es[0] ? es[0].isIntersecting : true; });
      io.observe(cvs);

      let t0 = performance.now(), sOffA = { x: 0, y: 0 }, sOffB = { x: 0, y: 0 };

      const draw = (now) => {
        if (dead) return;
        raf = requestAnimationFrame(draw);
        if (!visible || now - last < FRAME_MS) return;
        last = now;
        const t = (now - t0) / 1000;
        const size = Math.min(W, H);
        const cx = W / 2, cy = H / 2 - size * 0.02;
        const drift = { x: DRIFT.x * size / 100, y: DRIFT.y * size / 100 };

        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
        ctx.clearRect(0, 0, W, H);

        // nebula + orbits (1 blit)
        ctx.drawImage(bgLayer, 0, 0);

        // parallax stars (wrapped blits)
        const wrapBlit = (layer, off, alpha) => {
          ctx.globalAlpha = alpha;
          const ox = ((off.x % W) + W) % W, oy = ((off.y % H) + H) % H;
          ctx.drawImage(layer, ox - W, oy - H); ctx.drawImage(layer, ox, oy - H);
          ctx.drawImage(layer, ox - W, oy);     ctx.drawImage(layer, ox, oy);
          ctx.globalAlpha = 1;
        };
        if (!reduced) {
          sOffA.x -= drift.x * 0.5; sOffA.y -= drift.y * 0.5;
          sOffB.x -= drift.x * 1.1; sOffB.y -= drift.y * 1.1;
        }
        wrapBlit(starsA, sOffA, 0.75 + 0.2 * Math.sin(t * 1.1));
        wrapBlit(starsB, sOffB, 0.8 + 0.2 * Math.sin(t * 1.6 + 2));

        // ── compute planet positions ──
        const sel = stateRef.current.selKey;
        const pts = BODIES.map((b, i) => {
          const w = (Math.PI * 2) / (b.T * EARTH_PERIOD_S);
          const ang = t * w + i * 1.7;
          const R = b.r * size * 0.5;
          const sin = Math.sin(ang);
          return { b, ang, sin, x: cx + Math.cos(ang) * R, y: cy + sin * R * TILT, behind: sin < 0 };
        });

        // ── trails: fade + stream the whole buffer, stamp dots ──
        if (!reduced) {
          trailBx.clearRect(0, 0, W, H);
          trailBx.globalAlpha = 0.93;
          trailBx.drawImage(trailF, -drift.x, -drift.y);
          trailBx.globalAlpha = 1;
          const tmp = trailF; trailF = trailB; trailB = tmp;
          const tmpx = trailFx; trailFx = trailBx; trailBx = tmpx;
          // stamp current positions
          trailFx.fillStyle = "rgba(248,198,72,0.05)";
          trailFx.beginPath(); trailFx.arc(cx, cy, size * 0.045, 0, Math.PI * 2); trailFx.fill();
          pts.forEach(({ b, x, y }) => {
            const sp = sprites[b.key];
            trailFx.fillStyle = hexA(sp.col, 0.4);
            trailFx.beginPath(); trailFx.arc(x, y, Math.max(1, sp.pr * 0.32), 0, Math.PI * 2); trailFx.fill();
          });
          ctx.drawImage(trailF, 0, 0);
        }

        const drawPlanet = (p) => {
          const sp = sprites[p.b.key];
          const isSel = sel === p.b.key, isHov = hoverKey === p.b.key;
          const depth = 1 + p.sin * 0.16;                 // nearer = bigger
          const sc = depth * (isSel ? 1.3 : 1);
          screenPos[p.b.key] = { x: p.x, y: p.y, r: Math.max(sp.pr * 2.4 * sc, 14) };
          ctx.save();
          ctx.globalAlpha = p.behind ? 0.8 : 1;
          const d = sp.R * sc;
          ctx.drawImage(sp.c, p.x - d, p.y - d, d * 2, d * 2);
          if (isSel || isHov) {
            ctx.strokeStyle = hexA(sp.col, 0.85); ctx.lineWidth = 1.3;
            ctx.setLineDash([3, 4]);
            ctx.beginPath(); ctx.arc(p.x, p.y, sp.pr * 2.1 * sc + 1.5 * Math.sin(t * 3), 0, Math.PI * 2); ctx.stroke();
            ctx.setLineDash([]);
            ctx.font = `600 ${Math.max(10, size / 30)}px Cairo, sans-serif`;
            ctx.textAlign = "center"; ctx.fillStyle = "rgba(255,255,255,0.92)";
            ctx.fillText(nameOf(p.b.key), p.x, p.y + sp.pr * 2.4 * sc + 13);
          }
          ctx.restore();
        };

        pts.filter((p) => p.behind).forEach(drawPlanet);

        // ── sun (2 blits: slow-spinning rays + pulsing body) ──
        const pulse = reduced ? 1 : 1 + 0.035 * Math.sin(t * 1.5);
        const sR = sunSprite.width / 2;
        ctx.save();
        ctx.translate(cx, cy);
        ctx.rotate(t * 0.05);
        ctx.globalAlpha = 0.9;
        ctx.drawImage(raysSprite, -sR * pulse, -sR * pulse, sR * 2 * pulse, sR * 2 * pulse);
        ctx.restore();
        ctx.drawImage(sunSprite, cx - sR * pulse, cy - sR * pulse, sR * 2 * pulse, sR * 2 * pulse);
        screenPos.sun = { x: cx, y: cy, r: size * 0.08 };

        pts.filter((p) => !p.behind).forEach(drawPlanet);

        if (reduced) cancelAnimationFrame(raf);
      };
      raf = requestAnimationFrame(draw);

      // ── interactivity ──
      const hit = (e) => {
        const rect = cvs.getBoundingClientRect();
        const x = e.clientX - rect.left, y = e.clientY - rect.top;
        let best = null, bd = 1e9;
        Object.keys(screenPos).forEach((k) => {
          const p = screenPos[k];
          const d = Math.hypot(x - p.x, y - p.y);
          if (d < p.r + 6 && d < bd) { bd = d; best = k; }
        });
        return best;
      };
      const onMove = (e) => { hoverKey = hit(e); cvs.style.cursor = hoverKey ? "pointer" : "default"; };
      const onClick = (e) => {
        const k = hit(e);
        if (k && stateRef.current.onSelect) stateRef.current.onSelect(k);
      };
      cvs.addEventListener("pointermove", onMove);
      cvs.addEventListener("click", onClick);

      return () => {
        dead = true; cancelAnimationFrame(raf);
        ro.disconnect(); io.disconnect();
        cvs.removeEventListener("pointermove", onMove);
        cvs.removeEventListener("click", onClick);
      };
    }, []);

    const ar = lang === "ar";
    return (
      <div className="solar-drift-wrap" ref={wrapRef}>
        <canvas ref={cvsRef} aria-label={ar ? "النظام الشمسي — الشمس تسبح في الفضاء وكواكبك تدور حولها" : "Solar system — the sun travels through space with your planets orbiting"}></canvas>
        <span className="sd-hint">{ar ? "اضغط على أي كوكب" : "Tap any planet"}</span>
      </div>
    );
  };

  function hexA(hex, a) {
    const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})/i.exec(hex || "#C4B5FF");
    const r = m ? parseInt(m[1], 16) : 196, g = m ? parseInt(m[2], 16) : 181, b = m ? parseInt(m[3], 16) : 255;
    return `rgba(${r},${g},${b},${Math.max(0, Math.min(1, a)).toFixed(3)})`;
  }
})();
