import React, { useEffect, useState } from 'react';
import {
  Carousel,
  CarouselProps,
  COLOR_TOKENS,
  Box,
} from '@wix/design-system';
import { SuggestionsState } from '../../state/Suggestions/SuggestionsState';
import { observer } from 'mobx-react-lite';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import { MarketingCardSkeleton } from './MarketingCard';
import { SuggestionsProps } from './types';
import { VisibilityTrackedCard } from './VisibilityTrackedCard';
import { SuggestionsProvider } from './SuggestionsContext';

const defaultCarouselProps: CarouselProps = {
  dots: false,
  infinite: false,
  variableWidth: true,
  slideSpacing: 24,
  controlsPosition: 'overlay',
  showControlsShadow: true,
  gradientColor: COLOR_TOKENS['--wsr-color-D70'],
  gradient: true,
  controlsStartEnd: 'hidden',
};

interface SuggestionsContainerProps {
  count: number;
  children: React.ReactNode;
  carouselProps?: CarouselProps;
  dataHook: string;
  dataState: 'idle' | 'loading';
  maxInlineItems: number;
}

export interface SuggestionItemProps {
  children: React.ReactNode;
  dataId?: string;
}

export interface NonNullableElementCard<T> {
  key: string;
  offerGuid: string | undefined;
  element: T;
}

const SuggestionsContainer: React.FC<SuggestionsContainerProps> = ({
  count,
  children,
  carouselProps,
  dataHook,
  dataState,
  maxInlineItems,
}) => {
  if (count <= maxInlineItems) {
    return (
      <div data-hook={dataHook}>
        <Box
          direction="horizontal"
          gap="SP4"
          dataHook={`suggestions-container-${dataState}`}
        >
          {children}
        </Box>
      </div>
    );
  }

  return (
    <div data-hook={dataHook}>
      <Carousel
        {...defaultCarouselProps}
        {...carouselProps}
        dataHook={`suggestions-carousel-${dataState}`}
      >
        {children}
      </Carousel>
    </div>
  );
};

export const SuggestionItem: React.FC<SuggestionItemProps> = ({
  children,
  dataId,
}) => (
  <div
    data-hook="suggestion-item"
    data-id={dataId}
    style={{ display: 'contents' }}
  >
    {children}
  </div>
);

export const Suggestions: React.FC<SuggestionsProps> = observer(
  ({
    placementId,
    renderCard,
    CardSkeleton = MarketingCardSkeleton,
    carouselProps,
    skeletonsNumber = 4,
    dataHook = 'suggestions',
    maxInlineItems = 2,
  }) => {
    const container = useWixPatternsContainer();

    const [state] = useState(
      () => new SuggestionsState({ placementId, container }),
    );

    useEffect(() => {
      return state.init();
    }, [state]);

    if (state.hasOffers) {
      // use initial cards count for container, to match the count the cards get rendered with
      const cardCount = state.offers.length;
      const cards = state.offers
        .map((offer, index) => {
          const key = offer.offerGuid || `suggestion-${index}`;
          return {
            key,
            offerGuid: offer.offerGuid,
            element: renderCard({
              offer,
              index,
              totalOffers: cardCount,
            }),
          };
        })
        .filter(
          (card): card is NonNullableElementCard<React.ReactElement> =>
            card.element != null,
        );

      if (cards.length === 0) {
        return null;
      }

      return (
        <SuggestionsProvider onOfferClicked={state.onOfferClicked}>
          <SuggestionsContainer
            count={cardCount}
            carouselProps={carouselProps}
            dataHook={dataHook}
            dataState="idle"
            maxInlineItems={maxInlineItems}
          >
            {cards.map(({ key, offerGuid, element }) => (
              <SuggestionItem key={key} dataId={key}>
                <VisibilityTrackedCard
                  itemKey={key}
                  element={element}
                  onObserved={() => offerGuid && state.onOfferViewed(offerGuid)}
                />
              </SuggestionItem>
            ))}
          </SuggestionsContainer>
        </SuggestionsProvider>
      );
    }

    if (state.isFetching) {
      const skeletons = Array.from({ length: skeletonsNumber }).map(
        (_, index) => (
          <SuggestionItem key={index}>
            <CardSkeleton index={index} totalOffers={skeletonsNumber} />
          </SuggestionItem>
        ),
      );

      return (
        <SuggestionsProvider onOfferClicked={state.onOfferClicked}>
          <SuggestionsContainer
            count={skeletonsNumber}
            carouselProps={{ ...carouselProps, controlsPosition: 'none' }}
            dataHook={dataHook}
            dataState="loading"
            maxInlineItems={maxInlineItems}
          >
            {skeletons}
          </SuggestionsContainer>
        </SuggestionsProvider>
      );
    }

    return null;
  },
);
