"use client";

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

type HtmlTag = "div" | "ul";
type Direction = "up" | "down" | "left" | "right";

export interface StaggerGridProps {
  children: ReactNode;
  className?: string;
  as?: HtmlTag;
  /** Seconds between each direct child's entrance (default 0.1 — tighter than QueueSection, cards read faster). */
  stagger?: number;
  delay?: number;
  amount?: number;
  once?: boolean;
  direction?: Direction;
  distance?: number;
  duration?: number;
  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 };

/**
 * Like `QueueSection`, but purpose-built for a list of repeated items (event
 * cards, banners, sponsor logos, gallery thumbnails): it auto-wraps each
 * direct child in its own animated wrapper instead of requiring the caller
 * to hand-wrap every card in a `QueueItem` — `<StaggerGrid><Card/>...</StaggerGrid>`
 * is enough. Triggers its own `whileInView` (once, by default) rather than
 * relying on an ancestor `QueueSection`, since a grid is usually the whole
 * content of its section.
 */
export function StaggerGrid({
  children,
  className,
  as = "div",
  stagger = 0.1,
  delay = 0,
  amount = 0.2,
  once = true,
  direction = "up",
  distance = 24,
  duration = 0.5,
  blur = true,
}: StaggerGridProps) {
  const reduced = useReducedMotionSafe();
  const Container = motion[as];
  const axis = AXIS[direction];
  const offset = distance * SIGN[direction];

  const itemVariants = 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 },
        },
      };

  const items = Children.toArray(children).filter(isValidElement);

  if (reduced) {
    return (
      <Container className={className} initial={false}>
        {items}
      </Container>
    );
  }

  return (
    <Container
      className={className}
      initial="hidden"
      whileInView="visible"
      viewport={{ once, amount }}
      variants={{ hidden: {}, visible: { transition: { staggerChildren: stagger, delayChildren: delay } } }}
    >
      {items.map((item, i) => (
        <motion.div key={item.key ?? i} variants={itemVariants}>
          {item}
        </motion.div>
      ))}
    </Container>
  );
}
