import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { twMerge } from 'tailwind-merge';
import { SetOptional } from 'type-fest';

import ImpressionLogger, {
  ImpressionLoggerConfig,
} from '@/components/ImpressionLogger';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import DiscoverContestCard from '@/components/carousel/carouselCards/DiscoverContestCard';
import DiscoverHookCard from '@/components/carousel/carouselCards/DiscoverHookCard';
import DiscoverPlaylistCard from '@/components/carousel/carouselCards/DiscoverPlaylistCard';
import DiscoverSongCard from '@/components/carousel/carouselCards/DiscoverSongCard';
import { ChevronRightIcon } from '@/icons';
import CarouselEventType from '@/logging/eventTypes/CarouselEventType';
import {
  DiscoverCarouselSection,
  DiscoverSectionItemEntity,
} from '@/state/discoverStore';

import DiscoverCarousel, { DiscoverCarouselProps } from './DiscoverCarousel';

export type DiscoverCardCarouselProps<
  T extends
    DiscoverCarouselSection['section_type'] = DiscoverCarouselSection['section_type'],
  P extends object = object,
> = SetOptional<
  DiscoverCarouselProps<DiscoverSectionItemEntity<T>, P>,
  'renderItem'
> & {
  linkClassName?: string;
  index: number;
  styleType?: string;
  sectionType?: T;
  link?: string | null;
  carouselEventData?: Omit<CarouselEventType, 'actionName'>;
};

export type DiscoverCardCarouselRenderItem<
  T extends
    DiscoverCarouselSection['section_type'] = DiscoverCarouselSection['section_type'],
  P extends object = object,
> = DiscoverCarouselProps<DiscoverSectionItemEntity<T>, P>['renderItem'];

export type Props<
  T extends
    DiscoverCarouselSection['section_type'] = DiscoverCarouselSection['section_type'],
  P extends object = object,
> = Omit<
  React.HTMLAttributes<HTMLDivElement>,
  keyof DiscoverCardCarouselProps<T, P>
> &
  DiscoverCardCarouselProps<T, P>;

function isPlaylistItem(
  sectionType: DiscoverCarouselSection['section_type'],
  item: unknown
): item is DiscoverSectionItemEntity<'playlist_list'> {
  return sectionType === 'playlist_list';
}
function isSongItem(
  sectionType: DiscoverCarouselSection['section_type'],
  item: unknown
): item is DiscoverSectionItemEntity<'playlist'> {
  return sectionType === 'playlist';
}
function isHookItem(
  sectionType: DiscoverCarouselSection['section_type'],
  item: unknown
): item is DiscoverSectionItemEntity<'hooks'> {
  return sectionType === 'hooks';
}

function isContestItem(
  sectionType: DiscoverCarouselSection['section_type'],
  item: unknown
): item is DiscoverSectionItemEntity<'contest_list'> {
  return sectionType === 'contest_list';
}

export const DiscoverCardCarousel = <
  T extends
    DiscoverCarouselSection['section_type'] = DiscoverCarouselSection['section_type'],
  P extends object = object,
>(
  props: Props<T, P>
) => {
  const {
    linkClassName,
    itemClassName,
    index,
    styleType,
    sectionType,
    link,
    carouselEventData,
    ...restProps
  } = props;

  const { t } = useTranslation();

  const impressionLoggerConfigs = useMemo<ImpressionLoggerConfig[]>(
    () =>
      carouselEventData
        ? [
            {
              event: {
                ...carouselEventData,
                actionName: 'CarouselSeen',
              },
              threshold: 0.95,
            },
            {
              event: {
                ...carouselEventData,
                actionName: 'CarouselSeenPartially',
              },
              threshold: 0.25,
            },
          ]
        : [],
    [carouselEventData]
  );

  const renderItem = useCallback<
    DiscoverCarouselProps<DiscoverSectionItemEntity<T>, P>['renderItem']
  >(
    ({ item, index, ...restItemProps }) => {
      switch (true) {
        case isPlaylistItem(sectionType, item):
          return (
            <div key={item.id}>
              <DiscoverPlaylistCard
                playlist={item}
                index={index}
                {...restItemProps}
              />
            </div>
          );
        case isSongItem(sectionType, item):
          return (
            <div key={item.id}>
              <DiscoverSongCard clip={item} index={index} {...restItemProps} />
            </div>
          );
        case isHookItem(sectionType, item):
          return (
            <div key={item.id}>
              <DiscoverHookCard hook={item} index={index} {...restItemProps} />
            </div>
          );
        case isContestItem(sectionType, item):
          return (
            <div key={item.id}>
              <DiscoverContestCard
                contest={item}
                index={index}
                {...restItemProps}
              />
            </div>
          );
        default:
          return null;
      }
    },
    [sectionType]
  );

  return (
    <ImpressionLogger
      configs={impressionLoggerConfigs}
      className='h-full w-full'
    >
      <DiscoverCarousel
        itemClassName={twMerge(
          'max-md:max-w-[calc(100vw-4rem)]',
          itemClassName
        )}
        renderItem={renderItem}
        actions={
          link ? (
            <Button
              variant={ButtonVariant.Tertiary}
              size={ButtonSize.Mini}
              shape={ButtonShape.Rounded}
              className={linkClassName}
              href={link}
              iconEnd={ChevronRightIcon}
            >
              {t('actions.showMore')}
            </Button>
          ) : undefined
        }
        {...restProps}
      />
    </ImpressionLogger>
  );
};

export default DiscoverCardCarousel;
