"use client";

/**
 * Magnetic wrapper — the child is pulled toward the cursor while hovered, then
 * springs back with momentum on leave (loose spring => visible overshoot, the
 * "alive" feel). The label inside also drifts at a deeper strength for a subtle
 * parallax between the button and its text.
 * Transform-only (GPU). No-op on coarse pointers and with prefers-reduced-motion
 * so keyboard/touch users get a static, fully-clickable element.
 */
import { useRef } from "react";
import { motion, useMotionValue, useSpring, useTransform } from "motion/react";
import { SPRING } from "./motion";

export default function Magnetic({
  children,
  strength = 0.35,
  className,
}: {
  children: React.ReactNode;
  strength?: number;
  className?: string;
}) {
  const ref = useRef<HTMLSpanElement>(null);
  const x = useMotionValue(0);
  const y = useMotionValue(0);
  const sx = useSpring(x, SPRING.magnetic);
  const sy = useSpring(y, SPRING.magnetic);
  // Inner content drifts a touch further => parallax depth between shell + label.
  const innerX = useTransform(sx, (v) => v * 0.35);
  const innerY = useTransform(sy, (v) => v * 0.35);

  const onMove = (e: React.PointerEvent) => {
    if (e.pointerType !== "mouse") return;
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    x.set((e.clientX - (r.left + r.width / 2)) * strength);
    y.set((e.clientY - (r.top + r.height / 2)) * strength);
  };

  const reset = () => {
    x.set(0);
    y.set(0);
  };

  return (
    <motion.span
      ref={ref}
      className={className}
      onPointerMove={onMove}
      onPointerLeave={reset}
      style={{ x: sx, y: sy, display: "inline-block" }}
    >
      <motion.span style={{ x: innerX, y: innerY, display: "inline-block" }}>
        {children}
      </motion.span>
    </motion.span>
  );
}
