import { useState, useEffect, useRef } from "react"
import { Box, useTheme, useMediaQuery } from "@mui/material"
import classNames from "classnames"

import SliderSlick from "react-slick"

import arrowLeftIcon from "@root/assets/Icons/arrow_left.svg"
import arrowRightIcon from "@root/assets/Icons/arrow_right.svg"

import "slick-carousel/slick/slick.css"
import "slick-carousel/slick/slick-theme.css"
import "./slider.css"

import type { ReactNode } from "react"
import type { CustomArrowProps } from "react-slick"

type SliderProps = {
  items: ReactNode[];
};

type ArrowProps = CustomArrowProps & {
  icon: ReactNode;
};

export const Slider = ({ items }: SliderProps) => {
	const [range, setRange] = useState<number>(3)
	const [activeRange, setActiveRange] = useState<number[]>([0, 1, 2])
	const [marginLeft, setMarginLeft] = useState<number>(0)
	const sliderRef = useRef()
	const theme = useTheme()
	const isMiddle = useMediaQuery(theme.breakpoints.down(1200))
	const isTablet = useMediaQuery(theme.breakpoints.down(830))
	const gridTablet = useMediaQuery(theme.breakpoints.down(1000))
	const isMobileHeader = useMediaQuery(theme.breakpoints.down(900))

	useEffect(() => {
		if (isTablet) {
			setRange(1)
			setActiveRange([0])

			return
		}

		if (isMiddle) {
			setRange(2)
			setActiveRange([0, 1])

			return
		}

		setRange(3)
		setActiveRange([0, 1, 2])
	}, [isMiddle, isTablet])

	useEffect(() => {
		const onSliderResize = ([item]: ResizeObserverEntry[]) => {
			const width = item.contentRect.width

			if (width < 830) {
				const margin = (width - 340 * range - (range - 1) * 40) / 2

				setMarginLeft(margin)

				return
			}

			if (width < 1160) {
				const margin = (width - 360 * range - (range - 1) * 40) / 2

				setMarginLeft(margin)

				return
			}

			setMarginLeft(0)
		}

		const resizeObserver = new ResizeObserver(onSliderResize)

		if (sliderRef.current) {
			resizeObserver.observe(sliderRef.current)
		}

		return () => resizeObserver.disconnect()
	}, [sliderRef, range])

	const calculateRange = (activeItem: number, itemsLength: number): number[] => {
		if (isTablet) {
			return [activeItem + 1 > itemsLength ? 0 : activeItem]
		}

		return [
			activeItem,
			activeItem + 1 >= itemsLength ? 0 : activeItem + 1,
			activeItem + range - 1 === itemsLength ? 0 : activeItem + range - 1 >= itemsLength ? 1 : activeItem + range - 1,
		]
	}

	const Arrow = ({ currentSlide, slideCount, icon, ...props }: ArrowProps) => <Box {...props}>{icon}</Box>

	return (
		<Box
			className="slider-wrapper"
			sx={{ "& .slick-track": { marginLeft: marginLeft + "px", columnGap: items.length === 1 ? "0px" : "40px" } }}
			ref={sliderRef}
		>
			{(items.length < 4 && !isMiddle && !isTablet) ||
      (items.length < 3 && isMiddle && !isTablet) ||
      (items.length < 1 && isTablet) ? (
					<Box
						sx={{
							mt: "40px",
							mb: "30px",
							display: "grid",
							gap: "40px",
							gridTemplateColumns: `repeat(auto-fit, minmax(300px, ${gridTablet ? "436px" : "360px"}))`,
							margin: isTablet ? "40px auto" : null,
						}}
					>
						{items}
					</Box>
				) : (
					<SliderSlick
						className="slider"
						dots
						infinite
						variableWidth
						lazyLoad={isMobileHeader ? "progressive" : undefined}
						slidesToShow={range}
						prevArrow={<Arrow icon={<img src={arrowLeftIcon} alt="prev" />} />}
						nextArrow={<Arrow icon={<img src={arrowRightIcon} alt="next" />} />}
						beforeChange={(_, active) => setActiveRange(calculateRange(active, items.length))}
						customPaging={(slideNumber) => (
							<Box
								className={classNames("dot", {
									active: activeRange.includes(slideNumber),
								})}
							/>
						)}
					>
						{items}
					</SliderSlick>
				)}
		</Box>
	)
}
