"use client";

import Image from "next/image";
import { useEffect, useRef, useState } from "react";
import { motion, AnimatePresence } from "framer-motion";

const CMS_BASE_URL =
  process.env.NEXT_PUBLIC_CMS_BASE_URL?.replace(/\/$/, "") ?? "";

type MediaSizes = {
  small?: { url?: string | null };
  medium?: { url?: string | null };
  large?: { url?: string | null };
  og?: { url?: string | null };
};

type MediaDocument = {
  url?: string | null;
  alt?: string | null;
  sizes?: MediaSizes | null;
};

type GalleryImage = {
  alt?: string | null;
  imageId?: number | null;
};

type GalleryBlock = {
  type?: string;
  props?: {
    images?: GalleryImage[];
    meta?: {
      anchorId?: string | null;
    } | null;
  } | null;
};

type ScillyPageData = {
  layout?: GalleryBlock[];
  included?: {
    media?: Record<string, MediaDocument>;
    globals?: {
      header?: {
        landingCTA?: {
          label?: string | null;
          href?: string | null;
        } | null;
      } | null;
    } | null;
  } | null;
};

type ResolvedGalleryImage = {
  id: string;
  src: string;
  alt: string;
};

function isGalleryBlock(block: GalleryBlock | undefined): block is GalleryBlock {
  return block?.type === "imageGalleryStripV1";
}

function toAbsoluteUrl(url?: string | null) {
  if (!url) return null;
  if (url.startsWith("http://") || url.startsWith("https://")) return url;
  if (!CMS_BASE_URL || !url.startsWith("/")) return url;
  return `${CMS_BASE_URL}${url}`;
}

function resolvePreferredImageUrl(media: MediaDocument | null) {
  return toAbsoluteUrl(
    media?.sizes?.medium?.url ??
    media?.sizes?.small?.url ??
    media?.sizes?.large?.url ??
    media?.url,
  );
}

const GAP = 10;
const SPEED = 60; // px per second

export default function GallerySection({ data }: { data: ScillyPageData }) {
  const [imgSize, setImgSize] = useState(300);
  const [isHovered, setIsHovered] = useState(false);
  const [isPaused, setIsPaused] = useState(false);
  const sectionRef = useRef<HTMLElement>(null);
  const [hoveredImage, setHoveredImage] = useState<{ alt: string; x: number; y: number } | null>(null);
  const hoverTimerRef = useRef<NodeJS.Timeout | null>(null);

  useEffect(() => {
    const handleResize = () => {
      setImgSize(window.innerWidth >= 1024 ? 360 : 300);
    };
    handleResize();
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  useEffect(() => {
    const el = sectionRef.current;
    if (!el) return;
    const observer = new IntersectionObserver(
      ([entry]) => setIsPaused(!entry.isIntersecting),
      { threshold: 0.1 },
    );
    observer.observe(el);
    return () => observer.disconnect();
  }, []);

  const galleryBlock = data.layout?.find(isGalleryBlock);
  const mediaMap = data.included?.media ?? {};

  const images =
    galleryBlock?.props?.images
      ?.map((item, index) => {
        const media =
          item.imageId != null ? mediaMap[String(item.imageId)] ?? null : null;
        const src = resolvePreferredImageUrl(media);
        if (!src) return null;
        return {
          id: String(item.imageId ?? index),
          src,
          alt: item.alt?.trim() || media?.alt?.trim() || `Gallery image ${index + 1}`,
        };
      })
      .filter((image): image is ResolvedGalleryImage => Boolean(image)) ?? [];

  const oneSetWidth = images.length * (imgSize + GAP);

  if (!galleryBlock || images.length === 0) return null;

  const copiesNeeded =
    oneSetWidth > 0
      ? Math.max(2, Math.ceil((1920 * 2) / oneSetWidth) + 1)
      : 2;
  const loopedImages = Array.from({ length: copiesNeeded }, () => images).flat();
  const trackWidth = loopedImages.length * (imgSize + GAP);
  const duration = oneSetWidth > 0 ? oneSetWidth / SPEED : 0;

  return (
    <section
      ref={sectionRef}
      id={galleryBlock?.props?.meta?.anchorId ?? undefined}
      className="w-full overflow-hidden"
    >
      <div
        className="flex"
        style={{
          width: trackWidth,
          "--gallery-shift": `-${oneSetWidth}px`,
          animationName: duration > 0 ? "gallery-scroll" : "none",
          animationDuration: `${duration}s`,
          animationTimingFunction: "linear",
          animationIterationCount: "infinite",
          animationPlayState: isPaused || isHovered ? "paused" : "running",
          willChange: "transform",
          transform: "translateZ(0)",
          backfaceVisibility: "hidden",
        } as React.CSSProperties}
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
      >
        {loopedImages.map((image, i) => (
          <div
            key={`${image.id}-${i}`}
            className="relative shrink-0 overflow-hidden"
            style={{ width: imgSize, height: imgSize, marginRight: GAP, backgroundColor: "#e8e0d5" }}
            onMouseMove={(e) => {
              const r = e.currentTarget.getBoundingClientRect();
              if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current);
              setHoveredImage(null);
              hoverTimerRef.current = setTimeout(() => setHoveredImage({ alt: image.alt, x: e.clientX - r.left, y: e.clientY - r.top }), 1000);
            }}
            onMouseLeave={() => {
              if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current);
              setHoveredImage(null);
            }}
          >
            <Image
              src={image.src}
              alt={image.alt}
              fill
              className="object-cover object-center"
              sizes="(max-width: 640px) 300px, (max-width: 1024px) 360px, 400px"
              loading={i < 2 ? "eager" : "lazy"}
              priority={i < 2}
              quality={65}
            />
            <AnimatePresence>
              {hoveredImage?.alt === image.alt && (
                <motion.div
                  initial={{ opacity: 0, scale: 0.95 }}
                  animate={{ opacity: 1, scale: 1 }}
                  exit={{ opacity: 0, scale: 0.95 }}
                  transition={{ duration: 0.12 }}
                  style={{
                    position: "absolute",
                    left: hoveredImage.x,
                    top: hoveredImage.y,
                    transform: "translate(-50%, calc(-100% - 8px))",
                    pointerEvents: "none",
                    zIndex: 100,
                    whiteSpace: "nowrap",
                  }}
                  className="rounded border border-black bg-white px-3 py-1.5 text-sm font-semibold text-black shadow-sm"
                >
                  {image.alt}
                </motion.div>
              )}
            </AnimatePresence>
          </div>
        ))}
      </div>
    </section>
  );
}
