"use client";

import Image from "next/image";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { motion, useScroll, useTransform, useSpring, AnimatePresence } from "framer-motion";
import { playfair as serif } from "@/lib/fonts";


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

import {
  type RichTextRoot,
  type RichTextChild,
  renderLexical,
  extractPlainText
} from "../utils";

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 SpecialItem = {
  id?: string;
  eyebrow?: RichTextRoot | string | null;
  title?: RichTextRoot | string | null;
  body?: RichTextRoot | null;
};

type SpecialBlock = {
  type?: string;
  props?: {
    heading?: RichTextRoot | null;
    intro?: string | null;
    variant?: string | null;
    items?: SpecialItem[];
    backgroundImageId?: number | null;
    meta?: {
      anchorId?: string | null;
      backgroundImageId?: number | null;
    } | null;
  } | null;
};

type ScillyPageData = {
  layout?: SpecialBlock[];
  included?: {
    media?: Record<string, MediaDocument>;
  } | null;
};

type Card = {
  id: string;
  number: string;
  title: string;
  description: React.ReactNode;
};

type HeadingSegment = {
  text: string;
  emphasized: boolean;
  format: number;
};

function isSpecialBlock(
  block: SpecialBlock | undefined,
): block is SpecialBlock {
  return (
    block?.type === "contentListV1" && block?.props?.variant === "feature-cards"
  );
}

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?.large?.url ??
    media?.sizes?.medium?.url ??
    media?.sizes?.small?.url ??
    media?.url,
  );
}

function extractHeadingSegments(
  heading?: RichTextRoot | null,
): HeadingSegment[] {
  const firstParagraph = heading?.root?.children?.find(
    (child) => child.type === "paragraph",
  );

  const segments = firstParagraph?.children ?? [];

  return segments
    .map((segment) => ({
      text: segment.text ?? "",
      emphasized: Boolean((segment.format ?? 0) & 2),
      format: segment.format ?? 0,
    }))
    .filter((segment) => segment.text.length > 0);
}

export default function SpecialSection({ data }: { data: ScillyPageData }) {
  const sectionRef = useRef<HTMLElement | null>(null);
  const mobileScrollRef = useRef<HTMLDivElement | null>(null);
  const mobileScrollReleaseRef = useRef<NodeJS.Timeout | null>(null);
  const mobileInteractionTimerRef = useRef<NodeJS.Timeout | null>(null);
  const hasInitialMobileSyncRef = useRef(false);
  const isProgrammaticMobileScrollRef = useRef(false);
  // Cached card positions — avoids forced reflow on every scroll tick
  const cardCenterCacheRef = useRef<{ left: number; width: number }[]>([]);
  const containerWidthRef = useRef<number | null>(null);

  const [activeIndex, setActiveIndex] = useState(1);
  const [isMobileUserInteracting, setIsMobileUserInteracting] = useState(false);
  const [isMobileLayout, setIsMobileLayout] = useState(() =>
    typeof window !== "undefined" ? window.innerWidth < 768 : false
  );
  const [tooltipPos, setTooltipPos] = useState<{ x: number; y: number } | null>(null);
  const hoverTimerRef = React.useRef<NodeJS.Timeout | null>(null);

  const specialBlock = data.layout?.find(isSpecialBlock);
  const mediaMap = data.included?.media ?? {};

  const headingSegments = useMemo(
    () => extractHeadingSegments(specialBlock?.props?.heading),
    [specialBlock?.props?.heading],
  );

  const intro = specialBlock?.props?.intro?.trim() ?? "";
  const backgroundImageId =
    specialBlock?.props?.backgroundImageId ??
    specialBlock?.props?.meta?.backgroundImageId ??
    null;
  const backgroundImage =
    backgroundImageId != null
      ? (mediaMap[String(backgroundImageId)] ?? null)
      : null;
  const backgroundImageSrc = resolvePreferredImageUrl(backgroundImage);
  const backgroundAlt = backgroundImage?.alt?.trim() || extractPlainText(specialBlock?.props?.heading) || "Special Features";

  const items = useMemo<Card[]>(() => {
    const sourceItems = specialBlock?.props?.items ?? [];

    return sourceItems
      .map((item, index) => ({
        id: item.id ?? String(index),
        number: extractPlainText(item.eyebrow),
        title: extractPlainText(item.title),
        description: renderLexical(item.body),
      }))
      .filter((item) => item.number || item.title || item.description);
  }, [specialBlock?.props?.items]);

  const itemCount = items.length;
  const safeActiveIndex = itemCount > 0 ? activeIndex % itemCount : 0;

  const { scrollYProgress } = useScroll({
    target: sectionRef,
    offset: ["start end", "end start"],
  });

  const smooth = useSpring(scrollYProgress, {
    stiffness: 90,
    damping: 20,
    mass: 0.3,
  });

  const imageY = useTransform(smooth, [0, 1], ["12%", "-6%"]);
  const imageScale = useTransform(smooth, [0, 1], [1.1, 1]);
  const textY = useTransform(smooth, [0, 1], ["0%", "-20%"]);
  const textOpacity = useTransform(smooth, [0, 0.3], [0, 1]);
  const cardsY = useTransform(smooth, [0.2, 1], ["10%", "0%"]);
  const cardsOpacity = useTransform(smooth, [0.3, 0.9], [0.95, 1]);

  const refreshCardCenterCache = useCallback(() => {
    const node = mobileScrollRef.current;
    if (!node) return;
    containerWidthRef.current = node.clientWidth;
    cardCenterCacheRef.current = Array.from(node.children).map((c) => {
      const el = c as HTMLElement;
      return { left: el.offsetLeft, width: el.offsetWidth };
    });
  }, []);

  const scrollCardIntoView = useCallback(
    (index: number, behavior: ScrollBehavior = "smooth") => {
      const node = mobileScrollRef.current;
      if (!node) return;

      const cached = cardCenterCacheRef.current[index];
      const containerWidth = containerWidthRef.current ?? node.clientWidth;
      const left = cached
        ? cached.left - (containerWidth - cached.width) / 2
        : 0;

      isProgrammaticMobileScrollRef.current = true;
      if (mobileScrollReleaseRef.current) {
        clearTimeout(mobileScrollReleaseRef.current);
      }

      node.scrollTo({
        left: Math.max(left, 0),
        behavior,
      });

      mobileScrollReleaseRef.current = setTimeout(
        () => {
          isProgrammaticMobileScrollRef.current = false;
        },
        behavior === "smooth" ? 500 : 80,
      );
    },
    [],
  );

  const handleMobileScroll = useCallback(() => {
    const node = mobileScrollRef.current;
    if (!node || isProgrammaticMobileScrollRef.current) return;

    const cache = cardCenterCacheRef.current;
    if (!cache.length) return;

    const scrollLeft = node.scrollLeft;
    const containerWidth = containerWidthRef.current ?? node.clientWidth;
    const viewportCenter = scrollLeft + containerWidth / 2;
    let nearestIndex = 0;
    let smallestDistance = Number.POSITIVE_INFINITY;

    cache.forEach(({ left, width }, index) => {
      const cardCenter = left + width / 2;
      const distance = Math.abs(cardCenter - viewportCenter);
      if (distance < smallestDistance) {
        smallestDistance = distance;
        nearestIndex = index;
      }
    });

    setActiveIndex((prev) => (prev === nearestIndex ? prev : nearestIndex));
  }, []);

  const pauseMobileAutoplay = useCallback(() => {
    if (mobileInteractionTimerRef.current) {
      clearTimeout(mobileInteractionTimerRef.current);
    }
    setIsMobileUserInteracting(true);
  }, []);

  const resumeMobileAutoplaySoon = useCallback(() => {
    if (mobileInteractionTimerRef.current) {
      clearTimeout(mobileInteractionTimerRef.current);
    }
    mobileInteractionTimerRef.current = setTimeout(() => {
      setIsMobileUserInteracting(false);
    }, 2200);
  }, []);

  useEffect(() => {
    const updateIsMobileLayout = () => {
      setIsMobileLayout(window.innerWidth < 768);
    };

    updateIsMobileLayout();
    window.addEventListener("resize", updateIsMobileLayout);

    return () => window.removeEventListener("resize", updateIsMobileLayout);
  }, []);

  // Cache card positions on mount and on resize — avoids live DOM reads during scroll
  useEffect(() => {
    const node = mobileScrollRef.current;
    if (!node) return;
    refreshCardCenterCache();
    if (typeof ResizeObserver === "undefined") return;
    const observer = new ResizeObserver(refreshCardCenterCache);
    observer.observe(node);
    return () => observer.disconnect();
  }, [refreshCardCenterCache, isMobileLayout]);

  useEffect(() => {
    if (!isMobileLayout || itemCount === 0) {
      hasInitialMobileSyncRef.current = false;
      return;
    }

    if (!hasInitialMobileSyncRef.current) {
      refreshCardCenterCache();
      scrollCardIntoView(safeActiveIndex, "auto");
      hasInitialMobileSyncRef.current = true;
    }
  }, [isMobileLayout, itemCount, safeActiveIndex, scrollCardIntoView, refreshCardCenterCache]);

  useEffect(() => {
    if (!isMobileLayout || itemCount <= 1 || isMobileUserInteracting) return;

    const interval = setInterval(() => {
      if (isProgrammaticMobileScrollRef.current) return;

      setActiveIndex((prev) => {
        const nextIndex = (prev + 1) % itemCount;
        scrollCardIntoView(nextIndex, "smooth");
        return nextIndex;
      });
    }, 4200);

    return () => clearInterval(interval);
  }, [
    isMobileLayout,
    isMobileUserInteracting,
    itemCount,
    scrollCardIntoView,
  ]);

  useEffect(() => {
    return () => {
      if (mobileScrollReleaseRef.current) {
        clearTimeout(mobileScrollReleaseRef.current);
      }
      if (mobileInteractionTimerRef.current) {
        clearTimeout(mobileInteractionTimerRef.current);
      }
    };
  }, []);

  if (!specialBlock || itemCount === 0 || !backgroundImageSrc) {
    return null;
  }

  return (
    <section
      id={specialBlock.props?.meta?.anchorId ?? undefined}
      ref={sectionRef}
      className="relative w-full overflow-hidden py-[64px] md:py-[120px]"
      onMouseMove={(e) => {
        const r = e.currentTarget.getBoundingClientRect();
        const x = e.clientX - r.left;
        const y = e.clientY - r.top;
        if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current);
        setTooltipPos((prev) => (prev !== null ? null : prev));
        hoverTimerRef.current = setTimeout(() => setTooltipPos({ x, y }), 1000);
      }}
      onMouseLeave={() => {
        if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current);
        setTooltipPos(null);
      }}
    >
      <motion.div
        style={isMobileLayout ? undefined : { y: imageY, scale: imageScale }}
        className={`z-[1] w-full overflow-hidden ${isMobileLayout
          ? "absolute inset-0 h-full"
          : "absolute inset-x-0 top-[-20%] h-[140%]"
          }`}
      >
        <Image
          src={backgroundImageSrc}
          alt={backgroundAlt}
          fill
          className="object-cover"
          sizes="100vw"
          loading="lazy"
        />

        <div className="absolute inset-0" />
      </motion.div>

      <AnimatePresence>
        {tooltipPos && backgroundAlt && (
          <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: tooltipPos.x,
              top: tooltipPos.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"
          >
            {backgroundAlt}
          </motion.div>
        )}
      </AnimatePresence>

      <div className="relative z-[2] mx-auto max-w-[1200px] px-4">

        <div className="text-center">
          {headingSegments.length > 0 ? (
            <h2 className={`leading-none text-[#85714D] ${serif.className}`}>
              {headingSegments.map((segment, index) =>
                segment.emphasized ? (
                  <span
                    key={`${segment.text}-${index}`}
                    className="font-snell text-[27px] italic sm:text-[54px] md:text-[65px]"
                    style={{ fontFamily: "Snell" }}
                  >
                    {segment.text}
                  </span>
                ) : (
                  <span
                    key={`${segment.text}-${index}`}
                    className={`text-[22px] sm:text-[34px] md:text-[40px] ${segment.format & 1 ? "font-bold" : "font-normal"} ${segment.format & 2 ? "italic" : ""}`}
                  >
                    {segment.text}
                  </span>
                ),
              )}
            </h2>
          ) : null}
          {intro ? (
            <p className="mx-auto mt-3 max-w-[600px] px-5 text-[14px] leading-[24px] font-normal text-[#85714D] sm:text-[18px] sm:leading-[30px] md:mt-4 md:px-0 md:text-[20px] md:leading-[32px]">
              {intro}
            </p>
          ) : null}
        </div>


        <div className="relative z-[3] mt-6">
          <div
            ref={mobileScrollRef}
            onScroll={() => {
              handleMobileScroll();
              if (!isProgrammaticMobileScrollRef.current) {
                pauseMobileAutoplay();
                resumeMobileAutoplaySoon();
              }
            }}
            onTouchStart={pauseMobileAutoplay}
            onTouchEnd={resumeMobileAutoplaySoon}
            style={{ touchAction: "pan-x pan-y" }}
            className="flex snap-x snap-mandatory gap-2 overflow-x-auto px-[34px] pb-2 md:hidden [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
          >
            {items.map((item) => (
              <div
                key={item.id}
                className="flex h-[209px] w-[248px] shrink-0 snap-center flex-col items-center rounded-[20px] bg-[#85714D] px-4 pt-4 text-center text-white"
              >
                {item.number ? (
                  <div className={`text-[52px] leading-none ${serif.className}`}>
                    {item.number}
                  </div>
                ) : null}
                {item.title ? (
                  <div className={`${serif.className} mt-4 text-[16px] italic leading-[1.3] font-light`}>
                    {item.title}
                  </div>
                ) : null}
                {item.description ? (
                  <p className="mt-4 text-[12px] leading-[1.35] whitespace-pre-line text-white/90">
                    {item.description}
                  </p>
                ) : null}
              </div>
            ))}
          </div>

          {itemCount > 1 ? (
            <div className="mt-4 flex justify-center gap-2 md:hidden">
              {items.map((item, index) => (
                <button
                  key={item.id}
                  type="button"
                  aria-label={`Go to special item ${index + 1}`}
                  onClick={() => {
                    pauseMobileAutoplay();
                    setActiveIndex(index);
                    scrollCardIntoView(index);
                    resumeMobileAutoplaySoon();
                  }}
                  className={`h-2.5 w-2.5 rounded-full transition-colors ${safeActiveIndex === index ? "bg-[#85714D]" : "bg-white/70"}`}
                />
              ))}
            </div>
          ) : null}
        </div>


        <motion.div
          style={{ y: cardsY }}
          className="relative z-[3] mt-[30px] hidden md:block"
        >
          <div className="flex justify-center gap-[20px] md:flex-wrap lg:flex-nowrap">
            {items.map((item, index) => (
              <motion.div
                key={item.id}
                initial={{ opacity: 0, y: 40 }}
                whileInView={{ opacity: 1, y: 0 }}
                transition={{ duration: 0.7, delay: index * 0.15 }}
                whileHover={{ y: -8, scale: 1.02 }}
                className="flex min-h-[240px] w-[220px] flex-col items-center rounded-[20px] bg-[#85714D] px-4 pt-4 text-center text-white backdrop-blur-md lg:min-h-[275px] lg:w-[280px]"
                style={{ backfaceVisibility: "hidden", transformStyle: "preserve-3d", willChange: "transform", WebkitFontSmoothing: "antialiased" }}
              >
                {item.number ? (
                  <div className={`text-[60px] leading-none lg:text-[80px] ${serif.className}`} style={{ backfaceVisibility: "hidden" }}>
                    {item.number}
                  </div>
                ) : null}
                {item.title ? (
                  <div className={`${serif.className} mt-[14px] text-center text-[18px] leading-[24px] font-light italic lg:mt-[18px] lg:text-[22px] lg:leading-[28px]`} style={{ backfaceVisibility: "hidden" }}>
                    {item.title}
                  </div>
                ) : null}
                {item.description ? (
                  <p className="mt-[14px] text-[14px] leading-[1.4] whitespace-pre-line text-white/90" style={{ backfaceVisibility: "hidden" }}>
                    {item.description}
                  </p>
                ) : null}
              </motion.div>
            ))}
          </div>
        </motion.div>
      </div>
    </section>
  );
}
