import { useEffect, useRef, useState } from "react";
import { updateWorld } from "./physics";
import { drawWorld } from "./drawing";
import { getDefaultMyWorld, type WorldState } from "./worlds";

export default function Pendulum() {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const [subStep, setSubStep] = useState(10); // number of sub-steps per frame
  const [constraintIterations, setConstraintIterations] = useState(1); // number of constraint iterations per sub-step

  // refs to hold pendulum instances and animation state so we can reset from UI
  const worldRef = useRef<WorldState | null>(null);
  const rafRef = useRef<number | null>(null);
  const prevTimeRef = useRef<number>(0);

  // Drag state
  const draggingRef = useRef<{ ballIdx: number | null, offset: [number, number] | null }>({ ballIdx: null, offset: null });
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
    const dpr = window.devicePixelRatio || 1;
    const resize = () => {
      const w = canvas.clientWidth || 600;
      const h = canvas.clientHeight || 400;
      canvas.width = Math.max(1, Math.round(w * dpr));
      canvas.height = Math.max(1, Math.round(h * dpr));
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    resize();
    window.addEventListener("resize", resize);
    if (!worldRef.current) {
      worldRef.current = getDefaultMyWorld();
    }
    prevTimeRef.current = performance.now();
    const animate = (time: number) => {
      const deltaTime = time - prevTimeRef.current;
      prevTimeRef.current = time;
      const dt = Math.min(0.1, deltaTime / 1000) / subStep;
      for (let i = 0; i < subStep; i++) {
        if (worldRef.current) {
          updateWorld(worldRef.current, dt, constraintIterations);
        }
      }
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      if (worldRef.current) {
        drawWorld(ctx, worldRef.current, worldRef.current.ballDrawers);
      }
      rafRef.current = requestAnimationFrame(animate);
    };
    rafRef.current = requestAnimationFrame(animate);
    // --- Drag interaction handlers ---
    function getPointerPos(evt: PointerEvent) {
      if (!canvas) return [0, 0];
      const rect = canvas.getBoundingClientRect();
      return [evt.clientX - rect.left, evt.clientY - rect.top] as [number, number];
    }

    function onPointerDown(e: PointerEvent) {
      if (!worldRef.current) return;
      const pos = getPointerPos(e);
      let minDist = Infinity;
      let closestIdx: number | null = null;
      worldRef.current.balls.forEach((ball, idx) => {
        const dx = ball.pos[0] - pos[0];
        const dy = ball.pos[1] - pos[1];
        const dist = Math.sqrt(dx * dx + dy * dy);
        if (dist < 25 && dist < minDist && !ball.isFixed) { // Only allow dragging non-fixed balls
          minDist = dist;
          closestIdx = idx;
        }
      });
      if (closestIdx !== null) {
        draggingRef.current.ballIdx = closestIdx;
        draggingRef.current.offset = [
          worldRef.current.balls[closestIdx].pos[0] - pos[0],
          worldRef.current.balls[closestIdx].pos[1] - pos[1],
        ];
        // Pause animation while dragging
        if (rafRef.current) cancelAnimationFrame(rafRef.current);
      }
    }

    function onPointerMove(e: PointerEvent) {
      if (!worldRef.current) return;
      if (draggingRef.current.ballIdx === null) return;
      const pos = getPointerPos(e);
      const idx = draggingRef.current.ballIdx;
      const offset = draggingRef.current.offset || [0, 0];
      // Update ball position
      worldRef.current.balls[idx].pos = [pos[0] + offset[0], pos[1] + offset[1]];
      // Optionally update prevPos for stability
      worldRef.current.balls[idx].prevPos = [pos[0] + offset[0], pos[1] + offset[1]];
      // Redraw
      if (!ctx) return;
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      drawWorld(ctx, worldRef.current, worldRef.current.ballDrawers);
    }

    function onPointerUp() {
      if (draggingRef.current.ballIdx !== null) {
        draggingRef.current.ballIdx = null;
        draggingRef.current.offset = null;
        // Resume animation
        prevTimeRef.current = performance.now();
        rafRef.current = requestAnimationFrame(animate);
      }
    }

    canvas.addEventListener("pointerdown", onPointerDown);
    window.addEventListener("pointermove", onPointerMove);
    window.addEventListener("pointerup", onPointerUp);

    return () => {
      window.removeEventListener("resize", resize);
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
      canvas.removeEventListener("pointerdown", onPointerDown);
      window.removeEventListener("pointermove", onPointerMove);
      window.removeEventListener("pointerup", onPointerUp);
    };
  }, [constraintIterations, subStep]);

  // reset handler to re-create pendulums and avoid large dt on next frame
  const reset = () => {
    worldRef.current = getDefaultMyWorld();
    prevTimeRef.current = performance.now();
  };

  return (
    <div className="w-full h-full flex flex-col">
      <div className="p-2">
        <button
          onClick={reset}
          className="px-3 py-1.5 rounded border border-gray-300 bg-white text-sm hover:bg-gray-50 focus:outline-none"
        >
          리셋
        </button>
        <label className="ml-4 text-sm">
          서브스텝:
          <input
            type="number"
            value={subStep}
            onChange={(e) => setSubStep(Math.max(1, Math.min(100, Number(e.target.value))))}
            className="ml-2 w-16 px-2 py-1 border border-gray-300 rounded focus:outline-none"
          />
        </label>
        <label className="ml-4 text-sm">
          제약 반복 횟수:
          <input
            type="number"
            value={constraintIterations}
            onChange={(e) => setConstraintIterations(Math.max(1, Math.min(200, Number(e.target.value))))}
            className="ml-2 w-16 px-2 py-1 border border-gray-300 rounded focus:outline-none"
          />
        </label>
      </div>
      <div className="flex-1 min-h-0">
        <canvas
          style={{ touchAction: "none" }}
          ref={canvasRef}
          className="w-full h-full"
        />
      </div>
    </div>
  );
}