"use client";

import { useEffect, useRef, useState } from "react";

type Variant =
  | "fade-up"
  | "fade-down"
  | "fade-in"
  | "fade-left"
  | "fade-right"
  | "scale-up";

interface AnimateInProps {
  children: React.ReactNode;
  variant?: Variant;
  /** Delay (ms) after the element enters the viewport before animating */
  delay?: number;
  /** Animation duration in ms */
  duration?: number;
  /** Extra classes to put on the wrapper div */
  className?: string;
  /** If true (default) the animation only fires once */
  once?: boolean;
}

const transforms: Record<Variant, { hidden: string; visible: string }> = {
  "fade-up":    { hidden: "opacity-0 translate-y-10", visible: "opacity-100 translate-y-0" },
  "fade-down":  { hidden: "opacity-0 -translate-y-10", visible: "opacity-100 translate-y-0" },
  "fade-in":    { hidden: "opacity-0",                visible: "opacity-100" },
  "fade-left":  { hidden: "opacity-0 -translate-x-10", visible: "opacity-100 translate-x-0" },
  "fade-right": { hidden: "opacity-0 translate-x-10", visible: "opacity-100 translate-x-0" },
  "scale-up":   { hidden: "opacity-0 scale-95",       visible: "opacity-100 scale-100" },
};

export default function AnimateIn({
  children,
  variant = "fade-up",
  delay = 0,
  duration = 650,
  className = "",
  once = true,
}: AnimateInProps) {
  const ref = useRef<HTMLDivElement>(null);
  const [visible, setVisible] = useState(false);

  useEffect(() => {
    // Respect the user's motion preference
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      setVisible(true);
      return;
    }

    const el = ref.current;
    if (!el) return;

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setVisible(true);
          if (once) observer.disconnect();
        } else if (!once) {
          setVisible(false);
        }
      },
      { threshold: 0.08, rootMargin: "0px 0px -60px 0px" },
    );

    observer.observe(el);
    return () => observer.disconnect();
  }, [once]);

  const { hidden, visible: vis } = transforms[variant];

  return (
    <div
      ref={ref}
      className={`${visible ? vis : hidden} ${className}`}
      style={{
        transition: `opacity ${duration}ms cubic-bezier(0.22,1,0.36,1) ${delay}ms, transform ${duration}ms cubic-bezier(0.22,1,0.36,1) ${delay}ms`,
        willChange: "opacity, transform",
      }}
    >
      {children}
    </div>
  );
}
