'use client';

import React, { useMemo } from 'react';

import 'swiper/css';
import 'swiper/css/effect-coverflow';
import 'swiper/css/effect-creative';
import 'swiper/css/effect-fade';
import {
  A11y,
  Autoplay,
  EffectCoverflow,
  EffectCreative,
  EffectFade,
  Keyboard,
} from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';
import type { SwiperProps } from 'swiper/react';

import {
  HOMEPAGE_CAROUSEL_INTERVAL_MS,
  HOMEPAGE_CAROUSEL_STOP_ON_INTERACTION,
} from '@/config/homepageCarousel';

import type { AppSwiperController } from './useAppSwiper';

type PassThroughProps = Omit<SwiperProps, 'modules' | 'loop' | 'autoplay' | 'keyboard' | 'a11y'>;

interface AppSwiperProps {
  children: React.ReactNode;
  slideCount: number;
  controller?: AppSwiperController;
  loop?: boolean;
  autoplay?: boolean;
  intervalMs?: number;
  stopOnInteraction?: boolean;
  enableKeyboard?: boolean;
  enableA11y?: boolean;
  swiperOptions?: PassThroughProps;
}

const callBoth = <T extends unknown[]>(
  first?: (...args: T) => void,
  second?: (...args: T) => void
) => {
  return (...args: T) => {
    first?.(...args);
    second?.(...args);
  };
};

const AppSwiper: React.FC<AppSwiperProps> = ({
  children,
  slideCount,
  controller,
  loop,
  autoplay = true,
  intervalMs = HOMEPAGE_CAROUSEL_INTERVAL_MS,
  stopOnInteraction = HOMEPAGE_CAROUSEL_STOP_ON_INTERACTION,
  enableKeyboard = true,
  enableA11y = true,
  swiperOptions,
}) => {
  const resolvedLoop = (loop ?? slideCount > 1) && slideCount > 1;
  const autoplayConfig =
    autoplay && slideCount > 1
      ? {
          delay: intervalMs,
          disableOnInteraction: stopOnInteraction,
          pauseOnMouseEnter: true,
        }
      : false;

  const modules = useMemo(
    () => [A11y, Keyboard, Autoplay, EffectCreative, EffectCoverflow, EffectFade],
    []
  );

  return (
    <Swiper
      {...swiperOptions}
      modules={modules}
      loop={resolvedLoop}
      autoplay={autoplayConfig}
      keyboard={enableKeyboard ? { enabled: true, onlyInViewport: true } : false}
      a11y={enableA11y ? { enabled: true } : false}
      onSwiper={callBoth(controller?.bind.onSwiper, swiperOptions?.onSwiper)}
      onSlideChange={callBoth(controller?.bind.onSlideChange, swiperOptions?.onSlideChange)}
      onReachBeginning={callBoth(
        controller?.bind.onReachBeginning,
        swiperOptions?.onReachBeginning
      )}
      onReachEnd={callBoth(controller?.bind.onReachEnd, swiperOptions?.onReachEnd)}
      onFromEdge={callBoth(controller?.bind.onFromEdge, swiperOptions?.onFromEdge)}
    >
      {children}
    </Swiper>
  );
};

export const AppSwiperSlide = SwiperSlide;

export default AppSwiper;
