/* eslint-disable @typescript-eslint/no-explicit-any */
"use client";

import React, { type ReactNode, type CSSProperties } from "react";
import { motion } from "framer-motion";

interface RevealProps {
  children: ReactNode;
  className?: string;
  stagger?: boolean;
  style?: CSSProperties;
}

export function Reveal({
  children,
  className = "",
  stagger = false,
  style,
}: RevealProps) {
  // Container variants for stagger animation
  const containerVariants = {
    hidden: { opacity: 0 },
    visible: {
      opacity: 1,
      transition: {
        staggerChildren: 0.1,
        delayChildren: 0.05,
      },
    },
  };

  // Item variants for stagger animation children
  const itemVariants = {
    hidden: { opacity: 0, y: 22 },
    visible: {
      opacity: 1,
      y: 0,
      transition: {
        duration: 0.55,
        ease: [0.22, 1, 0.36, 1] as const,
      },
    },
  };

  if (stagger) {
    const childrenArray = React.Children.toArray(children);

    return (
      <motion.div
        className={className}
        style={style}
        variants={containerVariants}
        initial="hidden"
        whileInView="visible"
        viewport={{ once: true, amount: 0.1 }}
      >
        {childrenArray.map((child, index) => {
          if (React.isValidElement(child)) {
            // If it is a native HTML element tag, we can dynamically convert it into a motion element
            // to keep the DOM structure completely flat and preserve all layout, flex, grid, and nth-child rules.
            if (typeof child.type === "string") {
              const MotionComponent = motion.create(child.type as any);
              return (
                <MotionComponent
                  key={child.key || index}
                  {...(child.props as any)}
                  variants={itemVariants}
                />
              );
            }
            // For React Components, we wrap them in a motion.div with display contents to apply variants safely
            return (
              <motion.div
                key={child.key || index}
                variants={itemVariants}
                style={{ display: "contents" }}
              >
                {child}
              </motion.div>
            );
          }
          return child;
        })}
      </motion.div>
    );
  }

  // Standard non-stagger fade-in-up transition
  return (
    <motion.div
      className={className}
      style={style}
      initial={{ opacity: 0, y: 28 }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true, amount: 0.1 }}
      transition={{ duration: 0.65, ease: [0.22, 1, 0.36, 1] }}
    >
      {children}
    </motion.div>
  );
}
