"use client";

import { motion } from "framer-motion";
import type { ReactNode } from "react";
import { useReducedMotionSafe } from "./use-reduced-motion-safe";

type HtmlTag = "div" | "span" | "h1" | "h2" | "h3" | "p" | "li";
type Direction = "up" | "down" | "left" | "right";

export interface QueueItemProps {
  children: ReactNode;
  className?: string;
  as?: HtmlTag;
  /** Which way the item travels in from (default "up"). */
  direction?: Direction;
  /** Travel distance in px (default 24). */
  distance?: number;
  /** Entrance duration in seconds (default 0.6). */
  duration?: number;
  /** Subtle blur-in alongside the fade/move (default true). */
  blur?: boolean;
}

const AXIS: Record<Direction, "x" | "y"> = { up: "y", down: "y", left: "x", right: "x" };
const SIGN: Record<Direction, 1 | -1> = { up: 1, down: -1, left: 1, right: -1 };

/**
 * A single entry in a `QueueSection`/`StaggerGrid` queue. Relies entirely on
 * Framer Motion's variant propagation — it never sets its own
 * `initial`/`whileInView`/`viewport`, it just declares "hidden"/"visible"
 * states matching whatever ancestor is orchestrating (`QueueSection` or
 * `StaggerGrid`), so nesting or reordering never needs index math here.
 *
 * Only `transform` (translate + scale) and `opacity` (+ a very subtle
 * `filter: blur()`) are animated — no layout properties — so this stays on
 * the GPU-accelerated path. The spring is tuned to be critically damped
 * (damping ≈ 2·√(stiffness·mass)) so it settles without any bounce/overshoot.
 *
 * `prefers-reduced-motion` swaps to a fade-only variant pair (no
 * translate/scale/blur) rather than just shortening the same animation.
 */
export function QueueItem({
  children,
  className,
  as = "div",
  direction = "up",
  distance = 24,
  duration = 0.6,
  blur = true,
}: QueueItemProps) {
  const reduced = useReducedMotionSafe();
  const Component = motion[as];
  const axis = AXIS[direction];
  const offset = distance * SIGN[direction];

  const variants = reduced
    ? {
        hidden: { opacity: 0 },
        visible: { opacity: 1, transition: { duration } },
      }
    : {
        hidden: {
          opacity: 0,
          scale: 0.98,
          [axis]: offset,
          ...(blur ? { filter: "blur(6px)" } : {}),
        },
        visible: {
          opacity: 1,
          scale: 1,
          [axis]: 0,
          ...(blur ? { filter: "blur(0px)" } : {}),
          transition: { type: "spring" as const, stiffness: 120, damping: 20, mass: 0.8, duration },
        },
      };

  return (
    <Component className={className} variants={variants}>
      {children}
    </Component>
  );
}
