"use client";

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

import { withCDN } from "@/src/lib/utils";
import { slugFallback } from "@/src/lib/programSlugFallback";
import LanguageAwareLink from "@/src/lib/utils/LanguageAwareLink";
import { detailHref } from "@/src/lib/utils/detailHref";

interface SlideItem {
  id: number;
  image: string;
  text: string;
  title: string;
  logoImage?: string;
  age?: string;
  programId?: string;
  programSlug?: string;
  programName?: string;
}

interface ProgramsSliderFooterProps {
  bottomSliders?: any;
  slides?: SlideItem[];
  /**
   * Used when the page section has no "Years Old Text" of its own - the
   * program detail page passes its program's, since its sliders are a plain
   * list rather than a page section.
   */
  yearsOldText?: string | null;
}

type SlideDirection = "next" | "prev";

interface AnimationCustom {
  direction: SlideDirection;
}

const defaultSlides: SlideItem[] = [
  {
    id: 1,
    image: withCDN("/Program-detail/algo-buddy/pct%20(2).png"),
    logoImage: withCDN("/program-logo/logo_algo_buddy.svg"),
    age: "4-6",
    text: "Unlock the power of wind with perfectly coded sequences!",
    title: "Fan Robot",
  },
  {
    id: 2,
    image: withCDN("/Program-detail/algoc/footer/Goal%20Hitter%201.png"),
    logoImage: withCDN("/program-logo/logo_algo_c.svg"),
    age: "13-18",
    text: "Reading distance, reacting in commands, and striking with precision - Technology of the perfect hit!",
    title: "Goal Hitter",
  },
  {
    id: 3,
    image: withCDN("/Program-detail/Big-builders/footer/goose%201%20(1).png"),
    logoImage: withCDN("/program-logo/logo_big_builders.svg"),
    age: "4-6",
    text: "Let's fly together, as the birds show us the way on their migration journey!",
    title: "Bird's Migration",
  },
  {
    id: 4,
    image: withCDN("/Program-detail/footer/accordion%20robot%201.png"),
    logoImage: withCDN("/program-logo/logo_bricks_chalenge.svg"),
    age: "6-10",
    text: "The ratchet mechanism ensures my robot moves forward exclusively, without turning back!",
    title: "Accordion Robot",
  },
  {
    id: 5,
    image: withCDN("/Program-detail/algo-play/pct-5.png"),
    logoImage: withCDN("/program-logo/algo_play.svg"),
    age: "6-10",
    text: "Coding seamlessly orchestrates multiple transmission systems, enhancing their efficiency and adaptability.",
    title: "Fly Away",
  },
  {
    id: 6,
    image: withCDN(
      "/Program-detail/galileo%20technic/footer/Steamroller%201.png"
    ),
    logoImage: withCDN("/program-logo/logo_galileo_technic.svg"),
    age: "7-10",
    text: "Harnessing asymmetry and centrifugal force, the steamroller vibrates to smooth and compact the road surface efficiently!",
    title: "Steamroller",
  },
  {
    id: 7,
    image: withCDN(
      "/Program-detail/smartivo/Smartivo%20spotter_3%201.png"
    ),
    logoImage: withCDN("/program-logo/logo_smartivo.svg"),
    age: "4-6",
    text: "It’s a cosmic mission! Smartivo’s Distance Sensor lights up through event-based coding whenever a satellite is detected.",
    title: "Satellite Spotting Mission",
  },
  {
    id: 8,
    image: withCDN("/Program-detail/smartivo/zombie%201.png"),
    logoImage: withCDN("/program-logo/robo_toys.svg"),
    age: "9-12",
    text: "Watch the Zombie shuffle through commands, mastering interruptions and lighting up the night!",
    title: "Zombie",
  },
];

export default function ProgramsSliderFooter({
  bottomSliders,
  slides,
  yearsOldText,
}: ProgramsSliderFooterProps) {
  // Pages pass the whole "Bottom Sliders" section, whose option sits beside
  // its slider list; the program detail page passes a bare array.
  const sectionYearsOldText =
    bottomSliders && !Array.isArray(bottomSliders) && typeof bottomSliders.yearsOldText === "string"
      ? bottomSliders.yearsOldText.trim()
      : "";
  const yearsOldProgramLabel = sectionYearsOldText || yearsOldText?.trim() || "years old program";
  const parsedSliders = useMemo(() => {
    const base = slides && slides.length > 0 ? slides : defaultSlides;

    let apiSliders: any[] = [];

    if (Array.isArray(bottomSliders)) {
      apiSliders = bottomSliders;
    } else if (bottomSliders?.sliders) {
      try {
        apiSliders =
          typeof bottomSliders.sliders === "string"
            ? JSON.parse(bottomSliders.sliders)
            : bottomSliders.sliders;
      } catch (e) {
        console.error("Failed to parse bottomSliders", e);
      }
    }

    if (Array.isArray(apiSliders)) {
      apiSliders = apiSliders.filter(
        (s) =>
          s &&
          (s.program_id ||
            s.program_slug ||
            s.robot_image ||
            (s.tag && s.tag.toString().trim()) ||
            (s.title && s.title.toString().trim()))
      );
    }

    if (!Array.isArray(apiSliders) || apiSliders.length === 0) {
      return base;
    }

    // When the admin has slides, the API is the only source. The hard-coded
    // list above is used only if the API returns none at all.
    //
    // A slide's picture is its own robot_image, or failing that the picture of
    // the program the slide links to. It used to fall back further to the
    // hard-coded slide at the same POSITION, which belongs to a different
    // slide entirely - so a slide without an upload could show another
    // slide's picture under its own text.
    return apiSliders.map((apiSlide, index) => {
      const bySlug = slugFallback(apiSlide?.program_slug);

      return {
        id: index + 1,
        image:
          apiSlide?.robot_image ||
          bySlug?.image ||
          "",
        logoImage:
          apiSlide?.program_logo ||
          bySlug?.logoImage ||
          "",
        age: apiSlide?.age || "",
        title: apiSlide?.tag || "",
        text: apiSlide?.title || "",
        programId: apiSlide?.program_id || "",
        programSlug: apiSlide?.program_slug || "",
        programName: apiSlide?.program_name || "",
      } as SlideItem;
    });
  }, [bottomSliders, slides]);

  const pathname = usePathname();

  const isProgramInnerPage =
    pathname.startsWith("/programs/") &&
    pathname !== "/programs";

  const [isMobile, setIsMobile] = useState(false);

  useEffect(() => {
    const media = window.matchMedia("(max-width: 767px)");

    const updateMobile = () => {
      setIsMobile(media.matches);
    };

    updateMobile();

    media.addEventListener("change", updateMobile);

    return () => {
      media.removeEventListener("change", updateMobile);
    };
  }, []);

  const [currentIndex, setCurrentIndex] = useState(0);

  const [slideDirection, setSlideDirection] =
    useState<SlideDirection>("next");

  const [touchStart, setTouchStart] = useState<number | null>(null);
  const [touchEnd, setTouchEnd] = useState<number | null>(null);

  const [isHovered, setIsHovered] = useState(false);

  const [desktopFade, setDesktopFade] = useState(true);

  const [isAnimating, setIsAnimating] = useState(false);

  const animationTimerRef = useRef<ReturnType<typeof setTimeout> | null>(
    null
  );

  const slide =
    parsedSliders[currentIndex] ||
    parsedSliders[0] ||
    defaultSlides[0];

  useEffect(() => {
    if (!isMobile) {
      setDesktopFade(false);

      const frame = requestAnimationFrame(() => {
        setDesktopFade(true);
      });

      return () => cancelAnimationFrame(frame);
    }
  }, [currentIndex, isMobile]);

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

  const animationCustom: AnimationCustom = {
    direction: slideDirection,
  };

  /*
   * MOBILE ONLY
   *
   * Next:
   * New slide: 100% -> 0
   * Old slide: 0 -> -100%
   *
   * Previous:
   * New slide: -100% -> 0
   * Old slide: 0 -> 100%
   */
  const mobileVariants = {
    enter: ({ direction }: AnimationCustom) => ({
      x: direction === "next" ? "100%" : "-100%",
      scale: 0.8,
      opacity: 0.6,
    }),

    center: {
      x: "0%",
      scale: 1,
      opacity: 1,
    },

    exit: ({ direction }: AnimationCustom) => ({
      x: direction === "next" ? "-100%" : "100%",
      scale: 0.8,
      opacity: 0,
    }),
  };

  const startMobileAnimationLock = () => {
    setIsAnimating(true);

    if (animationTimerRef.current) {
      clearTimeout(animationTimerRef.current);
    }

    animationTimerRef.current = setTimeout(() => {
      setIsAnimating(false);
    }, 700);
  };

  const next = () => {
    if (parsedSliders.length <= 1) return;

    if (isMobile && isAnimating) return;

    setSlideDirection("next");

    if (isMobile) {
      startMobileAnimationLock();
    }

    setCurrentIndex((current) => {
      if (current >= parsedSliders.length - 1) {
        return 0;
      }

      return current + 1;
    });
  };

  const prev = () => {
    if (parsedSliders.length <= 1) return;

    if (isMobile && isAnimating) return;

    setSlideDirection("prev");

    if (isMobile) {
      startMobileAnimationLock();
    }

    setCurrentIndex((current) => {
      if (current <= 0) {
        return parsedSliders.length - 1;
      }

      return current - 1;
    });
  };

  useEffect(() => {
    if (parsedSliders.length <= 1) return;

    if (isHovered) return;

    const interval = setInterval(() => {
      if (isMobile && isAnimating) return;

      setSlideDirection("next");

      if (isMobile) {
        startMobileAnimationLock();
      }

      setCurrentIndex((current) => {
        if (current >= parsedSliders.length - 1) {
          return 0;
        }

        return current + 1;
      });
    }, 15000);

    return () => {
      clearInterval(interval);
    };
  }, [
    parsedSliders.length,
    isHovered,
    isMobile,
    isAnimating,
  ]);

  useEffect(() => {
    if (
      parsedSliders.length > 0 &&
      currentIndex >= parsedSliders.length
    ) {
      setCurrentIndex(0);
    }
  }, [parsedSliders.length, currentIndex]);

  const minSwipeDistance = 50;

  const pointerStartX = useRef<number | null>(null);

  const onPointerDown = (
    e: React.PointerEvent<HTMLDivElement>
  ) => {
    if (
      window.innerWidth < 768 ||
      e.pointerType !== "mouse" ||
      e.button !== 0
    ) {
      return;
    }

    if ((e.target as HTMLElement).closest("button, a")) {
      return;
    }

    pointerStartX.current = e.clientX;

    e.currentTarget.setPointerCapture(e.pointerId);
  };

  const onPointerUp = (
    e: React.PointerEvent<HTMLDivElement>
  ) => {
    if (pointerStartX.current === null) return;

    const distance = pointerStartX.current - e.clientX;

    pointerStartX.current = null;

    if (distance > minSwipeDistance) {
      next();
    }

    if (distance < -minSwipeDistance) {
      prev();
    }
  };

  const onPointerCancel = () => {
    pointerStartX.current = null;
  };

  const onTouchStart = (e: React.TouchEvent) => {
    if (isMobile && isAnimating) return;

    setTouchEnd(null);
    setTouchStart(e.targetTouches[0].clientX);
  };

  const onTouchMove = (e: React.TouchEvent) => {
    if (isMobile && isAnimating) return;

    setTouchEnd(e.targetTouches[0].clientX);
  };

  const onTouchEnd = () => {
    if (isMobile && isAnimating) {
      setTouchStart(null);
      setTouchEnd(null);
      return;
    }

    if (touchStart === null || touchEnd === null) {
      return;
    }

    const distance = touchStart - touchEnd;

    const isLeftSwipe = distance > minSwipeDistance;
    const isRightSwipe = distance < -minSwipeDistance;

    if (isLeftSwipe) {
      next();
    }

    if (isRightSwipe) {
      prev();
    }

    setTouchStart(null);
    setTouchEnd(null);
  };

  return (
    <div
      className="relative w-full overflow-hidden"
      aria-roledescription="carousel"
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
    >
      <div
        className="max-w-[1300px] mx-auto w-full relative flex flex-col md:flex-col items-center md:items-center justify-center md:justify-between gap-6 md:gap-5 px-2 md:px-12 lg:px-14 xl:px-5 py-8 md:py-0 mt-5 md:mt-13 xl:mt-26 carousel-wrapper md:cursor-grab md:active:cursor-grabbing md:select-none"
        onTouchStart={onTouchStart}
        onTouchMove={onTouchMove}
        onTouchEnd={onTouchEnd}
        onPointerDown={onPointerDown}
        onPointerUp={onPointerUp}
        onPointerCancel={onPointerCancel}
      >
        <div className="grid w-full">
          {isMobile ? (
            <AnimatePresence
              mode="sync"
              initial={false}
              custom={animationCustom}
            >
              <motion.div
                key={currentIndex}
                custom={animationCustom}
                variants={mobileVariants}
                initial="enter"
                animate="center"
                exit="exit"
                transition={{
                  duration: 0.50,
                  ease: [0.25, 0.1, 0.25, 1],
                }}
                className="col-start-1 row-start-1 flex w-full flex-col items-center"
                style={{
                  transformOrigin: "center center",
                }}
              >
                <div className="w-full sm:max-w-1/2 md:max-w-[40%] lg:max-w-[45%] flex items-center justify-center flex-col content-image-left">
                  <Image
                    src={
                      slide.image
                        ? withCDN(slide.image)
                        : "/placeholder.svg"
                    }
                    alt={`slide-${slide.id}`}
                    width={400}
                    height={300}
                    className="program-main-image object-contain w-[300px] h-[250px] md:w-[350px] md:h-[295px] lg:w-[580px] lg:h-[420px]"
                    unoptimized
                  />

                  {slide.title && (
                    <h3 className="program-main-image text-[#0097dc] text-[15px] md:text-[14px] lg:text-[15px] uppercase py-[10px] px-[30px] md:px-[24px] lg:px-[30px] rounded-full bg-white shadow-[6px_6px_14px_#00000040] w-fit mt-[-48px] mb-[50px] lg:mt-[-90px] lg:mb-[100px] lg:mr-[-100px]">
                      {slide.title}
                    </h3>
                  )}
                </div>

                <div className="content-slider-left sm:max-w-[100%] md:max-w-[60%] lg:max-w-[55%] max-[767px]:px-4 lg:pl-[30px]">
                  <div className="w-full mb-0 md:mb-0 text-center md:text-left text-[#0097DC] text-[20px] font-medium lg:text-[20px] xl:text-[20px] 2xl:text-[25px] tracking-[0.02em] xl:min-w-[570px] slide-description-txt">
                    {!isProgramInnerPage && (
                      <div className="flex items-center justify-center gap-[10px] md:gap-[20px] lg:gap-[30px] mb-[30px] max-[768px]:justify-center program-age-range">
                        {(() => {
                          const boxClass =
                            "w-[150px] h-[100px] shadow-[4px_4px_10px_#00000040] rounded-[33px] block";

                          const logo = (
                            <Image
                              src={
                                slide.logoImage ||
                                "/placeholder.svg"
                              }
                              alt={`slide-${slide.id}`}
                              width={150}
                              height={100}
                              className="object-cover w-[150px] h-[100px]"
                            />
                          );

                          if (!slide.programId) {
                            return (
                              <div className={boxClass}>
                                {logo}
                              </div>
                            );
                          }

                          return (
                            <LanguageAwareLink
                              href={detailHref(
                                "/programs",
                                slide.programId,
                                slide.programSlug
                              )}
                              aria-label={
                                slide.programName
                                  ? `Open the ${slide.programName} program page`
                                  : "Open the program page"
                              }
                              className={boxClass}
                            >
                              {logo}
                            </LanguageAwareLink>
                          );
                        })()}

                        <div>
                          <h3 className="text-[30px] md:text-[40px] text-[#58585A] font-bold">
                            {slide.age}
                          </h3>

                          <p className="text-[16px] text-[#58585A] font-light uppercase max-[768px]:w-[100px]">
                            {yearsOldProgramLabel}
                          </p>
                        </div>
                      </div>
                    )}

                    <div className="text-center description-content">
                      {slide.text}
                    </div>
                  </div>
                </div>
              </motion.div>
            </AnimatePresence>
          ) : (
            <div
              className={`col-start-1 row-start-1 flex w-full md:flex-row flex-col items-center transition-opacity duration-700 ease-out ${
                desktopFade ? "opacity-100" : "opacity-0"
              }`}
            >
              <div className="w-full sm:max-w-[50%] md:max-w-[40%] lg:max-w-[45%] flex items-center justify-center flex-col content-image-left">
                <Image
                  src={
                    slide.image
                      ? withCDN(slide.image)
                      : "/placeholder.svg"
                  }
                  alt={`slide-${slide.id}`}
                  width={400}
                  height={300}
                  className="program-main-image object-contain w-[300px] h-[250px] md:w-[350px] md:h-[295px] lg:w-[580px] lg:h-[420px]"
                  unoptimized
                />

                {slide.title && (
                  <h3 className="program-main-image text-[#0097dc] text-[15px] md:text-[14px] lg:text-[15px] uppercase py-[10px] px-[30px] md:px-[24px] lg:px-[30px] rounded-full bg-white shadow-[6px_6px_14px_#00000040] w-fit mt-[-48px] mb-[50px] lg:mt-[-90px] lg:mb-[100px] lg:mr-[-100px]">
                    {slide.title}
                  </h3>
                )}
              </div>

              <div className="content-slider-left sm:max-w-[50%] md:max-w-[60%] lg:max-w-[55%] max-[767px]:px-4 lg:pl-[30px]">
                <div className="w-full mb-0 md:mb-0 text-center md:text-left text-[#0097DC] text-[20px] font-medium lg:text-[20px] xl:text-[20px] 2xl:text-[25px] tracking-[0.02em] xl:min-w-[570px] slide-description-txt">
                  {!isProgramInnerPage && (
                    <div className="flex items-center justify-center gap-[10px] md:gap-[20px] lg:gap-[30px] mb-[30px] max-[768px]:justify-center program-age-range">
                      {(() => {
                        const boxClass =
                          "w-[150px] h-[100px] shadow-[4px_4px_10px_#00000040] rounded-[33px] block";

                        const logo = (
                          <Image
                            src={
                              slide.logoImage ||
                              "/placeholder.svg"
                            }
                            alt={`slide-${slide.id}`}
                            width={150}
                            height={100}
                            className="object-cover w-[150px] h-[100px]"
                          />
                        );

                        if (!slide.programId) {
                          return (
                            <div className={boxClass}>
                              {logo}
                            </div>
                          );
                        }

                        return (
                          <LanguageAwareLink
                            href={detailHref(
                              "/programs",
                              slide.programId,
                              slide.programSlug
                            )}
                            aria-label={
                              slide.programName
                                ? `Open the ${slide.programName} program page`
                                : "Open the program page"
                            }
                            className={boxClass}
                          >
                            {logo}
                          </LanguageAwareLink>
                        );
                      })()}

                      <div>
                        <h3 className="text-[30px] md:text-[40px] text-[#58585A] font-bold">
                          {slide.age}
                        </h3>

                        <p className="text-[16px] text-[#58585A] font-light uppercase max-[768px]:w-[100px]">
                          {yearsOldProgramLabel}
                        </p>
                      </div>
                    </div>
                  )}

                  <div className="text-center description-content">
                    {slide.text}
                  </div>
                </div>

                <div className="hidden md:flex items-center gap-3 lg:gap-5 justify-center mt-[10px] footer-slider-arrows">
                  <div className="flex">
                    <button
                      type="button"
                      onClick={prev}
                      aria-label="Previous slide"
                      className="transition-transform duration-300 hover:scale-110 active:scale-95 w-[30px] h-[30px] lg:w-[30px] lg:h-[30px] xl:w-[40px] xl:h-[40px]"
                    >
                      <Image
                        src={withCDN("/arrow-left.svg")}
                        alt="Previous"
                        width={40}
                        height={40}
                        className="object-contain cursor-pointer w-[30px] h-[30px] lg:w-[30px] lg:h-[30px] xl:w-[40px] xl:h-[40px]"
                        unoptimized
                      />
                    </button>
                  </div>

                  <div className="flex">
                    <button
                      type="button"
                      onClick={next}
                      aria-label="Next slide"
                      className="transition-transform duration-300 hover:scale-110 active:scale-95 w-[30px] h-[30px] lg:w-[30px] lg:h-[30px] xl:w-[40px] xl:h-[40px]"
                    >
                      <Image
                        src={withCDN("/arrow-right.svg")}
                        alt="Next"
                        width={40}
                        height={40}
                        className="object-contain cursor-pointer w-[30px] h-[30px] lg:w-[30px] lg:h-[30px] xl:w-[40px] xl:h-[40px]"
                        unoptimized
                      />
                    </button>
                  </div>
                </div>
              </div>
            </div>
          )}
        </div>
      </div>

      <div className="md:hidden flex items-center gap-5 justify-center">
        <div className="z-10">
          <button
            type="button"
            onClick={prev}
            aria-label="Previous slide"
            disabled={isAnimating}
            className="transition-transform duration-300 active:scale-90 disabled:opacity-100"
          >
            <Image
              src={withCDN("/arrow-left.svg")}
              alt="Previous"
              width={32}
              height={32}
              className="object-contain cursor-pointer"
              unoptimized
            />
          </button>
        </div>

        <div className="z-10">
          <button
            type="button"
            onClick={next}
            aria-label="Next slide"
            disabled={isAnimating}
            className="transition-transform duration-300 active:scale-90 disabled:opacity-100"
          >
            <Image
              src={withCDN("/arrow-right.svg")}
              alt="Next"
              width={32}
              height={32}
              className="object-contain cursor-pointer"
              unoptimized
            />
          </button>
        </div>
      </div>
    </div>
  );
}
