"use client";

import * as React from "react";
import { cn } from "@/lib/utils";

interface FadeInProps {
  children: React.ReactNode;
  className?: string;
  direction?: "up" | "down" | "left" | "right";
  delay?: number;
  duration?: number;
}

const directionOffset: Record<string, { x: string; y: string }> = {
  up:    { x: "0",    y: "2rem" },
  down:  { x: "0",    y: "-2rem" },
  left:  { x: "2rem", y: "0" },
  right: { x: "-2rem", y: "0" },
};

function FadeIn({
  children,
  className,
  direction = "up",
  delay = 0,
  duration = 600,
}: FadeInProps) {
  const [useFallback, setUseFallback] = React.useState(false);
  const [isVisible, setIsVisible] = React.useState(false);
  const ref = React.useRef<HTMLDivElement>(null);

  const { x, y } = directionOffset[direction];

  React.useEffect(() => {
    // If scroll-driven animations are natively supported, CSS handles
    // everything — including the reduced-motion override.
    const supportsScrollDriven =
      typeof CSS !== "undefined" && CSS.supports("animation-timeline", "view()");
    if (supportsScrollDriven) return;

    // Fallback path: IntersectionObserver + Tailwind transitions. State
    // flips happen in async callbacks (rAF/observer), never synchronously
    // in the effect body.
    const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const raf = requestAnimationFrame(() => {
      setUseFallback(true);
      if (reduceMotion) setIsVisible(true);
    });

    const element = ref.current;
    if (reduceMotion || !element) return () => cancelAnimationFrame(raf);

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setIsVisible(true);
          observer.disconnect();
        }
      },
      { threshold: 0.1 }
    );

    observer.observe(element);
    return () => {
      cancelAnimationFrame(raf);
      observer.disconnect();
    };
  }, []);

  const directionStyles: Record<string, string> = {
    up: "translate-y-8",
    down: "-translate-y-8",
    left: "translate-x-8",
    right: "-translate-x-8",
  };

  return (
    <div
      ref={ref}
      className={cn(
        "scroll-fade",
        useFallback && [
          "transition-all ease-out",
          isVisible ? "translate-x-0 translate-y-0 opacity-100" : `opacity-0 ${directionStyles[direction]}`,
        ],
        className
      )}
      style={{
        "--fade-x": x,
        "--fade-y": y,
        "--fade-duration": `${duration}ms`,
        "--fade-delay": `${delay}ms`,
        ...(useFallback
          ? { transitionDuration: `${duration}ms`, transitionDelay: `${delay}ms` }
          : {}),
      } as React.CSSProperties}
    >
      {children}
    </div>
  );
}

export { FadeIn };
