"use client";

import { useEffect, useRef, useState, type ElementType, type ReactNode } from "react";
import { cn } from "@/lib/utils";

type Props = {
  children: ReactNode;
  className?: string;
  /** Stagger siblings: ms before this one starts. */
  delay?: number;
  as?: ElementType;
};

/**
 * Fades + lifts its children in the first time they scroll into view.
 *
 * Content is visible by default (no JS, reduced motion, or an old browser all
 * get the static page); the hidden starting state is only applied once the
 * observer is known to work, so nothing can get stuck invisible.
 */
export default function Reveal({ children, className, delay = 0, as: Tag = "div" }: Props) {
  const ref = useRef<HTMLElement>(null);
  const [state, setState] = useState<"static" | "hidden" | "shown">("static");

  useEffect(() => {
    const el = ref.current;
    if (!el || typeof IntersectionObserver === "undefined") return;
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    // Already on screen at load (e.g. above the fold): don't animate it.
    const rect = el.getBoundingClientRect();
    if (rect.top < window.innerHeight * 0.9) return;

    setState("hidden");
    // Starts before the block reaches the screen (positive bottom margin), so a
    // quick scroll never lands on an empty, still-transparent area (4.10).
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries.some((e) => e.isIntersecting)) {
          setState("shown");
          observer.disconnect();
        }
      },
      { rootMargin: "0px 0px 15% 0px", threshold: 0 }
    );
    observer.observe(el);
    return () => observer.disconnect();
  }, []);

  return (
    <Tag
      ref={ref}
      style={state === "shown" && delay ? { transitionDelay: `${delay}ms` } : undefined}
      className={cn(
        state !== "static" && "transition-[opacity,transform] duration-500 ease-out will-change-transform",
        state === "hidden" && "translate-y-3 opacity-0",
        state === "shown" && "translate-y-0 opacity-100",
        className
      )}
    >
      {children}
    </Tag>
  );
}
