'use client';

import { observer } from 'mobx-react-lite';
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { twMerge } from 'tailwind-merge';

import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import SidebarAura from '@/components/sidebar/SidebarAura';
import SidebarCarousel from '@/components/sidebar/SidebarCarousel';
import SpinnerSVG from '@/components/svg/SpinnerSVG';

export type PromoCarouselConfig<K extends PropertyKey = string> = {
  id?: string;
  slides: Record<K, React.ReactNode>;
  slideOrder: K[];
  defaultSlide?: K;
};

export type Props = React.ComponentProps<typeof SidebarCarousel> &
  Partial<PromoCarouselConfig> & {
    loadingContent?:
      | React.ReactNode
      | React.ComponentType<{ className?: string }>;
    hiddenContent?:
      | React.ReactNode
      | React.ComponentType<{ className?: string }>;
    isHidden?: boolean;
    isLoading?: boolean;
    onHide?: (id?: string) => void;
    onShow?: (id?: string) => void;
    onSlideInit?: (id: string, index: number) => void;
    onSlideChange?: (id: string, index: number) => void;
  };

export const PromoCarouselLoading: React.FC<
  React.HTMLAttributes<HTMLDivElement>
> = (props) => (
  <div
    {...props}
    className={twMerge(
      'flex flex-col items-center justify-center text-foreground-primary/40',
      props.className
    )}
  >
    <SpinnerSVG className='text-current' />
    {props.children}
  </div>
);

const PromoCarousel: React.FC<Props> = observer((props) => {
  const {
    className,
    hiddenContent,
    loadingContent,
    isHidden,
    isLoading,
    id: carouselId,
    onHide,
    onShow,
    onSlideInit,
    onSlideChange,
    ...restProps
  } = props;

  const { t } = useTranslation();

  const [currentSlide, setCurrentSlide] = useState(
    props.defaultSlide ?? props.slideOrder?.[0]
  );

  const handleSlideInit = useCallback(
    (id: string, index: number) => {
      setCurrentSlide(id);
      onSlideInit?.(id, index);
    },
    [onSlideInit]
  );

  const handleSlideChange = useCallback(
    (id: string, index: number) => {
      setCurrentSlide(id);
      onSlideChange?.(id, index);
    },
    [onSlideChange]
  );

  return (
    <div
      className={twMerge(
        '@container relative flex flex-col items-center justify-start',
        className
      )}
    >
      {isHidden ? (
        typeof hiddenContent === 'function' ? (
          React.createElement(hiddenContent, { className: 'absolute inset-0' })
        ) : (
          hiddenContent || <SidebarAura className='absolute inset-0' />
        )
      ) : isLoading ? (
        typeof loadingContent === 'function' ? (
          React.createElement(loadingContent, { className: 'absolute inset-0' })
        ) : (
          loadingContent || (
            <PromoCarouselLoading className='absolute inset-0' />
          )
        )
      ) : (
        <SidebarCarousel
          className='absolute inset-0'
          defaultSlide={currentSlide}
          onSlideInit={handleSlideInit}
          onSlideChange={handleSlideChange}
          {...restProps}
        />
      )}
      {isHidden && onShow ? (
        <Button
          className='absolute end-2 top-2 opacity-50 transition duration-150 hover:opacity-100'
          onClick={() => {
            onShow(carouselId ? `${carouselId}:${currentSlide}` : carouselId);
          }}
          variant={ButtonVariant.Glass}
          size={ButtonSize.Mini}
          shape={ButtonShape.Pill}
        >
          {t('sidebar.show')}
        </Button>
      ) : !isHidden && onHide ? (
        <Button
          className='absolute end-2 top-2 opacity-50 transition duration-150 hover:opacity-100'
          onClick={() => {
            onHide(carouselId ? `${carouselId}:${currentSlide}` : carouselId);
          }}
          variant={ButtonVariant.Glass}
          size={ButtonSize.Mini}
          shape={ButtonShape.Pill}
        >
          {t('sidebar.hide')}
        </Button>
      ) : null}
    </div>
  );
});

export default PromoCarousel;
