"use client";

import { motion, useReducedMotion, type Variants } from "motion/react";
import { Children, type CSSProperties, type ReactNode } from "react";
import { cn } from "@/lib/utils";

type MaskRevealProps = {
  /** Each item is a separate line with its own mask. */
  lines: ReactNode[];
  className?: string;
  delay?: number;
  stagger?: number;
  duration?: number;
  style?: CSSProperties;
  as?: "h1" | "h2" | "h3" | "p" | "div";
};

/**
 * Cinematic reveal: each line rises from below its own overflow mask.
 * Use for headlines that need physical weight.
 */
export function MaskReveal({
  lines,
  className,
  delay = 0,
  stagger = 0.12,
  duration = 0.85,
  style,
  as: Tag = "h2",
}: MaskRevealProps) {
  const reduce = useReducedMotion();

  const container: Variants = {
    hidden: {},
    show: {
      transition: {
        staggerChildren: reduce ? 0 : stagger,
        delayChildren: delay,
      },
    },
  };

  const line: Variants = reduce
    ? {
        hidden: { opacity: 0 },
        show: { opacity: 1, transition: { duration: 0.2 } },
      }
    : {
        hidden: { y: "115%", opacity: 0 },
        show: {
          y: "0%",
          opacity: 1,
          transition: { duration, ease: [0.22, 1, 0.36, 1] },
        },
      };

  const MotionTag = motion[Tag] as typeof motion.div;

  return (
    <MotionTag
      className={cn(className)}
      style={style}
      variants={container}
      initial="hidden"
      whileInView="show"
      viewport={{ once: true, amount: 0.3 }}
    >
      {Children.toArray(
        lines.map((content, i) => (
          <span
            key={i}
            className="relative block overflow-hidden"
            style={{ paddingBottom: "0.06em" }}
          >
            <motion.span variants={line} className="block will-change-transform">
              {content}
            </motion.span>
          </span>
        )),
      )}
    </MotionTag>
  );
}
