"use client";

import { cn } from "@/app/lib/cn";
import useEmblaCarousel from "embla-carousel-react";
import { ArrowLeft, ArrowRight } from "iconsax-reactjs";
import {
  createContext,
  useContext,
  useEffect,
  useState,
  type FC,
  type HTMLAttributes,
  type ReactNode,
} from "react";

type CarouselApi = {
  scrollPrev: () => void;
  scrollNext: () => void;
  canScrollPrev: boolean;
  canScrollNext: boolean;
  slidesPerView: number;
  gap: number;
};

type ViewportRef = (node: HTMLElement | null) => void;

const CarouselContext = createContext<CarouselApi | null>(null);
const CarouselViewportContext = createContext<ViewportRef | null>(null);

function useCarousel() {
  const context = useContext(CarouselContext);
  if (!context) {
    throw new Error("Carousel components must be used within <Carousel>");
  }
  return context;
}

type CarouselProps = {
  children: ReactNode;
  slidesPerView?: number;
  slidesToScroll?: number;
  gap?: number;
  direction?: "rtl" | "ltr";
  className?: string;
};

const Carousel: FC<CarouselProps> = ({
  children,
  slidesPerView = 5,
  slidesToScroll,
  gap = 40,
  direction = "rtl",
  className,
}) => {
  const [emblaRef, emblaApi] = useEmblaCarousel({
    align: "start",
    direction,
    slidesToScroll: slidesToScroll ?? slidesPerView,
    containScroll: "trimSnaps",
  });

  const [canScrollPrev, setCanScrollPrev] = useState(false);
  const [canScrollNext, setCanScrollNext] = useState(false);

  useEffect(() => {
    if (!emblaApi) return;

    const updateButtons = () => {
      setCanScrollPrev(emblaApi.canScrollPrev());
      setCanScrollNext(emblaApi.canScrollNext());
    };

    updateButtons();
    emblaApi.on("select", updateButtons);
    emblaApi.on("reInit", updateButtons);

    return () => {
      emblaApi.off("select", updateButtons);
      emblaApi.off("reInit", updateButtons);
    };
  }, [emblaApi]);

  return (
    <CarouselContext.Provider
      value={{
        scrollPrev: () => emblaApi?.scrollPrev(),
        scrollNext: () => emblaApi?.scrollNext(),
        canScrollPrev,
        canScrollNext,
        slidesPerView,
        gap,
      }}
    >
      <CarouselViewportContext.Provider value={emblaRef}>
        <div className={className}>{children}</div>
      </CarouselViewportContext.Provider>
    </CarouselContext.Provider>
  );
};

type CarouselControlsProps = {
  className?: string;
  prevLabel?: string;
  nextLabel?: string;
};

const CarouselControls: FC<CarouselControlsProps> = ({
  className,
  prevLabel = "قبلی",
  nextLabel = "بعدی",
}) => {
  const { scrollPrev, scrollNext, canScrollPrev, canScrollNext } = useCarousel();

  return (
    <div className={cn("flex gap-2", className)}>
      <button
        type="button"
        aria-label={prevLabel}
        disabled={!canScrollPrev}
        onClick={scrollPrev}
        className="size-8 bg-primary rounded-full flex justify-center items-center disabled:opacity-40 disabled:cursor-not-allowed transition-opacity"
      >
        <ArrowRight size={20} color="white" />
      </button>
      <button
        type="button"
        aria-label={nextLabel}
        disabled={!canScrollNext}
        onClick={scrollNext}
        className="size-8 bg-primary rounded-full flex justify-center items-center disabled:opacity-40 disabled:cursor-not-allowed transition-opacity"
      >
        <ArrowLeft size={20} color="white" />
      </button>
    </div>
  );
};

type CarouselTrackProps = {
  children: ReactNode;
  className?: string;
};

const CarouselTrack: FC<CarouselTrackProps> = ({ children, className }) => {
  const emblaRef = useContext(CarouselViewportContext);
  const { gap } = useCarousel();

  if (!emblaRef) {
    throw new Error("CarouselTrack must be used within <Carousel>");
  }

  return (
    <div className={cn("overflow-hidden", className)} ref={emblaRef}>
      <div className="flex touch-pan-y" style={{ gap }}>
        {children}
      </div>
    </div>
  );
};

type CarouselSlideProps = HTMLAttributes<HTMLDivElement> & {
  children: ReactNode;
};

const CarouselSlide: FC<CarouselSlideProps> = ({ children, className, style, ...rest }) => {
  const { slidesPerView, gap } = useCarousel();
  const totalGap = (slidesPerView - 1) * gap;

  return (
    <div
      className={cn("min-w-0 shrink-0 grow-0", className)}
      style={{
        flexBasis: `calc((100% - ${totalGap}px) / ${slidesPerView})`,
        ...style,
      }}
      {...rest}
    >
      {children}
    </div>
  );
};

export { Carousel, CarouselControls, CarouselSlide, CarouselTrack };
export default Carousel;
