"use client";

import { useEffect, useRef, useState } from "react";
import Image from "next/image";

type ParallaxImageProps = {
  src: string;
  alt: string;
  sizes: string;
  /** Classes for the outer frame (size, radius, border). */
  className?: string;
  /** Classes for the image (object-position etc). */
  imageClassName?: string;
  /** Max vertical drift in px while scrolling. */
  strength?: number;
  priority?: boolean;
};

/**
 * Image that wipes in when first scrolled into view and drifts slightly as the page scrolls.
 * Both effects are skipped for reduced motion.
 */
export default function ParallaxImage({
  src,
  alt,
  sizes,
  className = "",
  imageClassName = "",
  strength = 18,
  priority = false,
}: ParallaxImageProps) {
  const frameRef = useRef<HTMLDivElement>(null);
  const imgRef = useRef<HTMLDivElement>(null);
  const [visible, setVisible] = useState(false);

  useEffect(() => {
    const frame = frameRef.current;
    if (!frame) return;
    const io = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setVisible(true);
          io.disconnect();
        }
      },
      { threshold: 0.2 },
    );
    io.observe(frame);
    return () => io.disconnect();
  }, []);

  useEffect(() => {
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    const frame = frameRef.current;
    const inner = imgRef.current;
    if (!frame || !inner) return;

    let raf = 0;
    function update() {
      raf = 0;
      const rect = frame!.getBoundingClientRect();
      // -1 when the frame is entering from below, +1 when leaving above
      const progress = (rect.top + rect.height / 2 - window.innerHeight / 2) / (window.innerHeight / 2 + rect.height / 2);
      const clamped = Math.max(-1, Math.min(1, progress));
      inner!.style.transform = `translate3d(0, ${(-clamped * strength).toFixed(1)}px, 0) scale(1.12)`;
    }
    function onScroll() {
      if (!raf) raf = requestAnimationFrame(update);
    }
    update();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll, { passive: true });
    return () => {
      if (raf) cancelAnimationFrame(raf);
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
    };
  }, [strength]);

  return (
    <div ref={frameRef} className={`relative overflow-hidden ${visible ? "animate-image-reveal" : "opacity-0"} ${className}`}>
      <div ref={imgRef} className="absolute inset-0 will-change-transform" style={{ transform: "scale(1.12)" }}>
        <Image src={src} alt={alt} fill sizes={sizes} priority={priority} className={`object-cover ${imageClassName}`} />
      </div>
    </div>
  );
}
