"use client";

/**
 * In-view reveal — the page's core entrance vocabulary.
 *  - Default: lift + fade + a touch of blur(4px -> 0) so content resolves INTO
 *    place instead of just sliding (Emil's blur-masked entrance). Never appears
 *    from nothing.
 *  - variant="clip": a premium clip-path inset() wipe (bottom -> full) for
 *    section/media reveals, paired with a small lift.
 *  - `stagger` cascades direct <RevealItem> children via variants (30–80ms).
 *  - Custom EASE_OUT curve everywhere; honors prefers-reduced-motion (keeps
 *    opacity/color, drops all movement + blur).
 */
import { motion, type Variants, useReducedMotion } from "motion/react";
import { EASE_OUT } from "./motion";

type Props = {
  children: React.ReactNode;
  className?: string;
  delay?: number;
  y?: number;
  stagger?: number;
  variant?: "lift" | "clip";
  as?:
    | "div"
    | "section"
    | "ul"
    | "ol"
    | "li"
    | "p"
    | "figure"
    | "header"
    | "span"
    | "h2";
};

const VIEWPORT = { once: true, margin: "0px 0px -12% 0px" } as const;

export default function Reveal({
  children,
  className,
  delay = 0,
  y = 28,
  stagger,
  variant = "lift",
  as = "div",
}: Props) {
  const reduce = useReducedMotion();
  const MotionTag = motion[as] as typeof motion.div;

  if (stagger) {
    const parent: Variants = {
      hidden: {},
      show: {
        transition: {
          staggerChildren: reduce ? 0 : stagger,
          delayChildren: delay / 1000,
        },
      },
    };
    return (
      <MotionTag
        className={className}
        variants={parent}
        initial="hidden"
        whileInView="show"
        viewport={VIEWPORT}
      >
        {children}
      </MotionTag>
    );
  }

  const hidden =
    variant === "clip"
      ? reduce
        ? { opacity: 1 }
        : { opacity: 0, y: y * 0.5, clipPath: "inset(0 0 100% 0)" }
      : reduce
        ? { opacity: 1 }
        : { opacity: 0, y, filter: "blur(4px)" };

  const shown =
    variant === "clip"
      ? { opacity: 1, y: 0, clipPath: "inset(0 0 0% 0)" }
      : { opacity: 1, y: 0, filter: "blur(0px)" };

  return (
    <MotionTag
      className={className}
      initial={hidden}
      whileInView={shown}
      viewport={VIEWPORT}
      transition={{ duration: 0.9, delay: delay / 1000, ease: EASE_OUT }}
    >
      {children}
    </MotionTag>
  );
}

/** A child item that participates in a parent <Reveal stagger>. */
export function RevealItem({
  children,
  className,
  y = 24,
  as = "div",
}: {
  children: React.ReactNode;
  className?: string;
  y?: number;
  as?: "div" | "li" | "p";
}) {
  const reduce = useReducedMotion();
  const MotionTag = motion[as] as typeof motion.div;
  const item: Variants = {
    hidden: reduce ? { opacity: 1 } : { opacity: 0, y, filter: "blur(4px)" },
    show: {
      opacity: 1,
      y: 0,
      filter: "blur(0px)",
      transition: { duration: 0.75, ease: EASE_OUT },
    },
  };
  return (
    <MotionTag className={className} variants={item}>
      {children}
    </MotionTag>
  );
}
