"use client"

import { cx } from "class-variance-authority"
import useEmblaCarousel from "embla-carousel-react"
import { useCallback, useEffect, useState } from "react"

import { CarouselContent } from "./CarouselContent"
import { CarouselContext } from "./CarouselContext"
import { CarouselDots } from "./CarouselDots"
import { CarouselItem } from "./CarouselItem"
import { CarouselNext, CarouselPrevious } from "./CarouselNavigation"

import styles from "./carousel.module.css"

import type { CarouselApi, CarouselProps } from "./types"

function Carousel({
  opts,
  setApi,
  plugins,
  className,
  children,
  scrollToIdx = 0,
  align = "start",
  onScrollSelect,
}: CarouselProps) {
  const [carouselRef, api] = useEmblaCarousel(
    {
      containScroll: "trimSnaps",
      align,
      axis: "x",
      ...opts,
    },
    plugins
  )
  const [selectedIndex, setSelectedIndex] = useState(scrollToIdx)

  const onSelect = useCallback(
    (api: CarouselApi) => {
      if (!api) return
      setSelectedIndex(api.selectedScrollSnap())
      onScrollSelect?.(api.selectedScrollSnap())
    },
    [onScrollSelect]
  )

  function scrollPrev() {
    api?.scrollPrev()
  }

  function scrollNext() {
    api?.scrollNext()
  }

  function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
    if (event.key === "ArrowLeft") {
      event.preventDefault()
      scrollPrev()
    } else if (event.key === "ArrowRight") {
      event.preventDefault()
      scrollNext()
    }
  }

  useEffect(() => {
    if (!api || !setApi) return
    setApi(api)
  }, [api, setApi])

  useEffect(() => {
    if (!api) return
    // eslint-disable-next-line react-hooks/set-state-in-effect
    onSelect(api)
    api.on("reInit", onSelect)
    api.on("select", onSelect)

    return () => {
      api.off("select", onSelect)
    }
  }, [api, onSelect])

  useEffect(() => {
    if (!api || scrollToIdx === -1) return
    api.reInit()
    api.scrollTo(scrollToIdx)
  }, [api, scrollToIdx])

  return (
    <CarouselContext.Provider
      value={{
        carouselRef,
        api,
        opts,
        plugins,
        setApi,
        children,
        scrollPrev,
        scrollNext,
        canScrollPrev: api?.canScrollPrev.bind(api) ?? (() => false),
        canScrollNext: api?.canScrollNext.bind(api) ?? (() => false),
        selectedIndex,
      }}
    >
      <div
        onKeyDownCapture={handleKeyDown}
        className={cx(styles.root, className)}
        role="region"
        aria-roledescription="carousel"
      >
        {children}
      </div>
    </CarouselContext.Provider>
  )
}

Carousel.Content = CarouselContent
Carousel.Item = CarouselItem
Carousel.Next = CarouselNext
Carousel.Previous = CarouselPrevious
Carousel.Dots = CarouselDots

export { Carousel }
