"use client";

import { motion, useReducedMotion } from "framer-motion";
import type { ReactNode } from "react";
import { EASE_OUT_EXPO, VIEWPORT } from "@/lib/motion";

/** Where the element travels from. `up` is the site default. */
type Direction = "up" | "down" | "left" | "right" | "scale" | "fade";

type Props = {
  children: ReactNode;
  /** Stagger helper — seconds added before the animation starts. */
  delay?: number;
  direction?: Direction;
  /** Seconds. Longer for large blocks, shorter for small ones. */
  duration?: number;
  className?: string;
};

const from: Record<Direction, Record<string, number>> = {
  up: { opacity: 0, y: 24 },
  down: { opacity: 0, y: -24 },
  left: { opacity: 0, x: -36 },
  right: { opacity: 0, x: 36 },
  scale: { opacity: 0, scale: 0.94 },
  fade: { opacity: 0 },
};

/**
 * Scroll-triggered entrance. The single animation primitive used across the
 * site so every section enters the same way — the direction only changes when
 * the layout gives it a reason to (a panel that sits on the right enters from
 * the right).
 * Honours `prefers-reduced-motion`: content is then rendered statically.
 */
export function Reveal({
  children,
  delay = 0,
  direction = "up",
  duration = 0.6,
  className,
}: Props) {
  const reduced = useReducedMotion();

  if (reduced) {
    return <div className={className}>{children}</div>;
  }

  return (
    <motion.div
      initial={from[direction]}
      whileInView={{ opacity: 1, x: 0, y: 0, scale: 1 }}
      viewport={VIEWPORT}
      transition={{ duration, delay, ease: EASE_OUT_EXPO }}
      className={className}
    >
      {children}
    </motion.div>
  );
}
