// AGENT_TARGET: gravity-slingshot — drag a rocket near a planet; gravity bends its path

const SLINGSHOT_PLANETS = [
  { id: "jupiter", name: "Jupiter", radius: 52, mass: 3200, color: "#c88b3a" },
  {
    id: "saturn",
    name: "Saturn",
    radius: 44,
    mass: 2400,
    color: "#e8d5a0",
    ring: true,
  },
  { id: "earth", name: "Earth", radius: 28, mass: 800, color: "#4a9fd4" },
  { id: "mars", name: "Mars", radius: 22, mass: 400, color: "#c1440e" },
];

const SL_G = 900; // gravitational constant tuned for canvas feel
const SL_DT = 0.55; // Euler integration timestep
const SL_TRAIL_MAX = 240;
const SL_PREVIEW_STEPS = 300;

// AGENT_TARGET: gravity-slingshot — Euler-step rocket position under planet gravity
function slingstepRocket(rx, ry, rvx, rvy, cx, cy, mass, radius) {
  const dx = cx - rx,
    dy = cy - ry;
  const dist = Math.sqrt(dx * dx + dy * dy);
  const r = Math.max(dist, radius + 4);
  const f = (SL_G * mass) / (r * r * r);
  return {
    x: rx + (rvx + f * dx * SL_DT) * SL_DT,
    y: ry + (rvy + f * dy * SL_DT) * SL_DT,
    vx: rvx + f * dx * SL_DT,
    vy: rvy + f * dy * SL_DT,
  };
}

// AGENT_TARGET: gravity-slingshot — compute preview trajectory for dotted path display
function computeSlingshotPreview(sx, sy, vx, vy, planet, W, H) {
  const cx = W / 2,
    cy = H / 2;
  const pts = [];
  let rx = sx,
    ry = sy,
    rvx = vx,
    rvy = vy;
  for (let i = 0; i < SL_PREVIEW_STEPS; i++) {
    const next = slingstepRocket(
      rx,
      ry,
      rvx,
      rvy,
      cx,
      cy,
      planet.mass,
      planet.radius,
    );
    rx = next.x;
    ry = next.y;
    rvx = next.vx;
    rvy = next.vy;
    pts.push({ x: rx, y: ry });
    if (rx < -100 || rx > W + 100 || ry < -100 || ry > H + 100) break;
  }
  return pts;
}

// AGENT_TARGET: gravity-slingshot — draw one animation frame onto the canvas
function drawSlingshotFrame(ctx, W, H, planet, trail, rocket, drag) {
  const cx = W / 2,
    cy = H / 2;

  ctx.clearRect(0, 0, W, H);
  ctx.fillStyle = "#060418";
  ctx.fillRect(0, 0, W, H);

  // Sparse star field (deterministic positions)
  ctx.fillStyle = "rgba(255,255,255,0.45)";
  for (let i = 0; i < 55; i++) {
    ctx.fillRect(
      Math.floor(((i * 137.508) % 1) * W),
      Math.floor(((i * 97.331) % 1) * H),
      1,
      1,
    );
  }

  // Gravity field hint rings
  ctx.lineWidth = 1;
  for (const mult of [2.0, 3.2, 5.0]) {
    ctx.strokeStyle = "rgba(180,200,255,0.07)";
    ctx.beginPath();
    ctx.arc(cx, cy, planet.radius * mult, 0, Math.PI * 2);
    ctx.stroke();
  }

  // Saturn ring
  if (planet.ring) {
    ctx.save();
    ctx.strokeStyle = "#b8a070";
    ctx.lineWidth = 7;
    ctx.globalAlpha = 0.4;
    ctx.beginPath();
    ctx.ellipse(
      cx,
      cy,
      planet.radius * 1.85,
      planet.radius * 0.32,
      0.3,
      0,
      Math.PI * 2,
    );
    ctx.stroke();
    ctx.restore();
  }

  // Planet body
  const grad = ctx.createRadialGradient(
    cx - planet.radius * 0.28,
    cy - planet.radius * 0.28,
    2,
    cx,
    cy,
    planet.radius,
  );
  grad.addColorStop(0, "#fff6ee");
  grad.addColorStop(0.35, planet.color);
  grad.addColorStop(1, "#00000055");
  ctx.beginPath();
  ctx.arc(cx, cy, planet.radius, 0, Math.PI * 2);
  ctx.fillStyle = grad;
  ctx.fill();

  // Planet name label
  ctx.fillStyle = "rgba(255,255,255,0.65)";
  ctx.font = "13px Inter, sans-serif";
  ctx.textAlign = "center";
  ctx.fillText(planet.name, cx, cy + planet.radius + 18);

  // Rocket trail
  if (trail.length > 1) {
    for (let i = 1; i < trail.length; i++) {
      const alpha = (i / trail.length) * 0.75;
      ctx.strokeStyle = `rgba(120,200,255,${alpha})`;
      ctx.lineWidth = 1.8;
      ctx.beginPath();
      ctx.moveTo(trail[i - 1].x, trail[i - 1].y);
      ctx.lineTo(trail[i].x, trail[i].y);
      ctx.stroke();
    }
  }

  // Preview dotted path while dragging
  if (drag) {
    const ddx = drag.sx - drag.cx,
      ddy = drag.sy - drag.cy;
    const dist = Math.sqrt(ddx * ddx + ddy * ddy);
    if (dist > 8) {
      const speed = Math.min(dist * 0.044, 5.8);
      const pvx = (ddx / dist) * speed,
        pvy = (ddy / dist) * speed;
      const preview = computeSlingshotPreview(
        drag.sx,
        drag.sy,
        pvx,
        pvy,
        planet,
        W,
        H,
      );

      ctx.save();
      ctx.setLineDash([4, 7]);
      ctx.strokeStyle = "rgba(255,240,140,0.5)";
      ctx.lineWidth = 1.5;
      ctx.beginPath();
      preview.forEach((p, i) =>
        i === 0 ? ctx.moveTo(p.x, p.y) : ctx.lineTo(p.x, p.y),
      );
      ctx.stroke();
      ctx.setLineDash([]);
      ctx.restore();

      // Aim dot + velocity arrow
      ctx.fillStyle = "#ffe070";
      ctx.beginPath();
      ctx.arc(drag.sx, drag.sy, 5, 0, Math.PI * 2);
      ctx.fill();
      ctx.strokeStyle = "#ffe070";
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.moveTo(drag.sx, drag.sy);
      ctx.lineTo(drag.sx + pvx * 16, drag.sy + pvy * 16);
      ctx.stroke();
    }
  }

  // Live rocket emoji
  if (rocket) {
    const angle = Math.atan2(rocket.vy, rocket.vx) + Math.PI / 2;
    ctx.save();
    ctx.translate(rocket.x, rocket.y);
    ctx.rotate(angle);
    ctx.font = "18px serif";
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillText("🚀", 0, 0);
    ctx.restore();
  }

  // Idle hint
  if (!rocket && !drag) {
    ctx.fillStyle = "rgba(180,210,255,0.5)";
    ctx.font = "14px Inter, sans-serif";
    ctx.textAlign = "center";
    ctx.fillText("Drag anywhere to launch a rocket", W / 2, H - 28);
  }
}

function GravitySlingshot({ onClose }) {
  // AGENT_TARGET: gravity-slingshot — GravitySlingshot main component
  const canvasRef = React.useRef(null);
  const simRef = React.useRef({
    planet: SLINGSHOT_PLANETS[0],
    rocket: null,
    trail: [],
    drag: null,
    animId: null,
  });
  const [planetId, setPlanetId] = React.useState(SLINGSHOT_PLANETS[0].id);
  const [status, setStatus] = React.useState(
    "Drag back and let go. The planet's gravity will bend the rocket path.",
  );
  const selectedPlanet =
    SLINGSHOT_PLANETS.find((pl) => pl.id === planetId) || SLINGSHOT_PLANETS[0];
  const pullStrength =
    (selectedPlanet.mass /
      Math.max(...SLINGSHOT_PLANETS.map((planet) => planet.mass))) *
    100;

  // Switch planet — reset sim
  React.useEffect(() => {
    const s = simRef.current;
    s.planet = selectedPlanet;
    s.rocket = null;
    s.trail = [];
    s.drag = null;
    setStatus(
      `${selectedPlanet.name} is ready. Bigger planets bend the path more.`,
    );
  }, [planetId, selectedPlanet]);

  // Animation loop
  const loop = React.useCallback(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const s = simRef.current;
    const W = canvas.width,
      H = canvas.height;
    const cx = W / 2,
      cy = H / 2;

    if (s.rocket) {
      const next = slingstepRocket(
        s.rocket.x,
        s.rocket.y,
        s.rocket.vx,
        s.rocket.vy,
        cx,
        cy,
        s.planet.mass,
        s.planet.radius,
      );
      s.rocket = next;
      s.trail.push({ x: next.x, y: next.y });
      if (s.trail.length > SL_TRAIL_MAX) s.trail.shift();
      if (
        next.x < -120 ||
        next.x > W + 120 ||
        next.y < -120 ||
        next.y > H + 120
      ) {
        s.rocket = null;
      }
    }

    drawSlingshotFrame(
      canvas.getContext("2d"),
      W,
      H,
      s.planet,
      s.trail,
      s.rocket,
      s.drag,
    );
    s.animId = requestAnimationFrame(loop);
  }, []);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    canvas.width = Math.min(window.innerWidth - 32, 520);
    canvas.height = Math.min(window.innerHeight * 0.7, 460);
    simRef.current.animId = requestAnimationFrame(loop);
    return () => {
      if (simRef.current.animId) cancelAnimationFrame(simRef.current.animId);
    };
  }, [loop]);

  // Pointer helpers
  const canvasPos = (e, canvas) => {
    const rect = canvas.getBoundingClientRect();
    const src = e.touches ? e.touches[0] : e;
    return {
      x: (src.clientX - rect.left) * (canvas.width / rect.width),
      y: (src.clientY - rect.top) * (canvas.height / rect.height),
    };
  };

  const onDown = (e) => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    e.preventDefault();
    const pos = canvasPos(e, canvas);
    const s = simRef.current;
    s.drag = { sx: pos.x, sy: pos.y, cx: pos.x, cy: pos.y };
    s.rocket = null;
    s.trail = [];
    setStatus("Pull back like a slingshot. The dotted path previews the curve.");
  };

  const onMove = (e) => {
    if (!simRef.current.drag) return;
    e.preventDefault();
    const canvas = canvasRef.current;
    if (!canvas) return;
    const pos = canvasPos(e, canvas);
    simRef.current.drag.cx = pos.x;
    simRef.current.drag.cy = pos.y;
  };

  const onUp = (e) => {
    const s = simRef.current;
    if (!s.drag) return;
    e.preventDefault();
    const { sx, sy, cx, cy } = s.drag;
    const dx = sx - cx,
      dy = sy - cy;
    const dist = Math.sqrt(dx * dx + dy * dy);
    if (dist > 8) {
      const speed = Math.min(dist * 0.044, 5.8);
      s.rocket = {
        x: sx,
        y: sy,
        vx: (dx / dist) * speed,
        vy: (dy / dist) * speed,
      };
      s.trail = [{ x: sx, y: sy }];
      setStatus("Launch! Gravity pulls sideways and bends the rocket path.");
    } else {
      setStatus("Try a bigger drag so the rocket has a clear push.");
    }
    s.drag = null;
  };

  const launchDemo = () => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const s = simRef.current;
    const startX = canvas.width * 0.16;
    const startY = canvas.height * 0.58;
    s.drag = null;
    s.trail = [{ x: startX, y: startY }];
    s.rocket = {
      x: startX,
      y: startY,
      vx: 4.2,
      vy: -1.15,
    };
    setStatus("Demo launch: watch the planet pull the rocket into a curve.");
  };

  return (
    <div
      className="slingshot-overlay"
      role="dialog"
      aria-label="Gravity Slingshot Launchpad"
    >
      <div className="slingshot-panel">
        <div className="slingshot-header">
          <span className="slingshot-title">⚡ Gravity Slingshot</span>
          <button
            className="slingshot-close"
            onClick={onClose}
            aria-label="Close slingshot"
          >
            ✕
          </button>
        </div>
        <div className="slingshot-planet-row">
          {SLINGSHOT_PLANETS.map((p) => (
            <button
              key={p.id}
              className={`slingshot-planet-btn${planetId === p.id ? " on" : ""}`}
              onClick={() => setPlanetId(p.id)}
            >
              {p.name}
            </button>
          ))}
        </div>
        <div className="slingshot-physics-card" role="status" aria-live="polite">
          <strong>Physics: gravity pulls</strong>
          <span>{status}</span>
          <div className="slingshot-pull-meter" aria-label="Selected planet pull strength">
            <small>{selectedPlanet.name} pull</small>
            <i>
              <b style={{ width: `${pullStrength}%` }} />
            </i>
          </div>
          <button onClick={launchDemo}>Show me</button>
        </div>
        <canvas
          ref={canvasRef}
          className="slingshot-canvas"
          onMouseDown={onDown}
          onMouseMove={onMove}
          onMouseUp={onUp}
          onMouseLeave={onUp}
          onTouchStart={onDown}
          onTouchMove={onMove}
          onTouchEnd={onUp}
          style={{ touchAction: "none" }}
        />
        <p className="slingshot-hint">
          Drag anywhere. Pick Jupiter, then Mars, and compare the curve.
        </p>
      </div>
    </div>
  );
}
