import { jsx } from 'react/jsx-runtime';
import React__default, { useRef } from 'react';
import { useReducedMotion, useInView, motion } from 'motion/react';
import { cn } from '../../../utils/cn.js';

/* ------------------------------------------------------------------ */
/*  Animation presets                                                   */
/* ------------------------------------------------------------------ */
const PRESET_VARIANTS = {
    fadeUp: {
        hidden: { opacity: 0, y: 32 },
        visible: { opacity: 1, y: 0 },
    },
    fadeDown: {
        hidden: { opacity: 0, y: -32 },
        visible: { opacity: 1, y: 0 },
    },
    fadeLeft: {
        hidden: { opacity: 0, x: -32 },
        visible: { opacity: 1, x: 0 },
    },
    fadeRight: {
        hidden: { opacity: 0, x: 32 },
        visible: { opacity: 1, x: 0 },
    },
    scaleUp: {
        hidden: { opacity: 0, scale: 0.85 },
        visible: { opacity: 1, scale: 1 },
    },
    blur: {
        hidden: { opacity: 0, filter: 'blur(8px)' },
        visible: { opacity: 1, filter: 'blur(0px)' },
    },
};
/* ------------------------------------------------------------------ */
/*  Component                                                           */
/* ------------------------------------------------------------------ */
/**
 * ScrollReveal
 *
 * Intersection-observer wrapper that triggers an entrance animation when
 * its children scroll into the viewport.
 *
 * Supports six built-in presets, custom variants, stagger-children timing,
 * and respects the `prefers-reduced-motion` media query.
 *
 * @example
 * ```tsx
 * <ScrollReveal preset="fadeUp">
 *   <h2>Hello world</h2>
 * </ScrollReveal>
 * ```
 *
 * @example
 * ```tsx
 * // Stagger children
 * <ScrollReveal preset="fadeUp" stagger={0.12}>
 *   <Card />
 *   <Card />
 *   <Card />
 * </ScrollReveal>
 * ```
 */
const ScrollReveal = React__default.forwardRef(({ preset = 'fadeUp', variants: customVariants, threshold = 0.1, rootMargin = '0px 0px -50px 0px', once = true, delay = 0, duration = 0.6, stagger = 0, className, children, 
// Destructure HTML event handlers that conflict with motion's API
onDrag: _onDrag, onDragStart: _onDragStart, onDragEnd: _onDragEnd, onAnimationStart: _onAnimationStart, ...restProps }, ref) => {
    const shouldReduceMotion = useReducedMotion();
    const internalRef = useRef(null);
    const isInView = useInView(internalRef, {
        once,
        amount: threshold,
        margin: rootMargin,
    });
    // When reduced motion is preferred, render content immediately.
    if (shouldReduceMotion) {
        return (jsx("div", { ref: (node) => {
                internalRef.current = node;
                if (typeof ref === 'function')
                    ref(node);
                else if (ref)
                    ref.current = node;
            }, className: className, ...restProps, children: children }));
    }
    // Build variants --------------------------------------------------
    const presetData = customVariants !== null && customVariants !== void 0 ? customVariants : PRESET_VARIANTS[preset];
    const motionVariants = {
        hidden: presetData.hidden,
        visible: {
            ...presetData.visible,
            transition: {
                duration,
                delay,
                ease: [0.25, 0.1, 0.25, 1], // cubic-bezier easeOut
                ...(stagger > 0
                    ? { staggerChildren: stagger, delayChildren: delay }
                    : {}),
            },
        },
    };
    // When stagger is used, each direct child needs to be a motion element.
    // We wrap each child in a motion.div that inherits parent variants.
    const content = stagger > 0
        ? React__default.Children.map(children, (child) => (jsx(motion.div, { variants: {
                hidden: presetData.hidden,
                visible: {
                    ...presetData.visible,
                    transition: { duration, ease: [0.25, 0.1, 0.25, 1] },
                },
            }, children: child })))
        : children;
    return (jsx(motion.div, { ref: (node) => {
            internalRef.current = node;
            if (typeof ref === 'function')
                ref(node);
            else if (ref)
                ref.current = node;
        }, className: cn(className), variants: motionVariants, initial: "hidden", animate: isInView ? 'visible' : 'hidden', ...restProps, children: content }));
});
ScrollReveal.displayName = 'ScrollReveal';

export { ScrollReveal };
