import { useCallback, useRef, useState } from 'react';

import type { PaginatedDotsApi } from '../../lib/PaginatedDots';
import type { PageSectionComponent } from '../../types';
import type { VideoSectionProps } from '../types';

import Box from '~/src/components/Box';
import HorizontalScroller from '~/src/components/Scroller2/HorizontalScroller';
import Text from '~/src/components/Text';
import useDebounce from '~/src/hooks/useDebounce';
import useIsLargeScreen from '~/src/hooks/useIsLargeScreen';
import { usePageTheme } from '../../../hooks/theme';
import PaginatedDots from '../../lib/PaginatedDots';
import { getReadyItems } from '../utils';
import VideoPlayer from './components/VideoPlayer';

const VideoSectionView: PageSectionComponent<Required<VideoSectionProps>> = ({
  items,
}) => {
  const scrollerRef = useRef<HTMLDivElement>(null);
  const dotsRef = useRef<PaginatedDotsApi>(null);

  const isLargeScreen = useIsLargeScreen();
  const pageTheme = usePageTheme();
  const [activeIndex, setActiveIndex] = useState(0);

  const scrollTo = useCallback(
    (index: number, behavior: ScrollBehavior) => {
      const scroller = scrollerRef.current;

      if (!scroller || !items.length) return;
      if (index < 0 || index > items.length - 1) return;

      scroller.scrollTo({
        behavior,
        left: index * Math.round(scroller.scrollWidth / items.length),
      });
    },
    [items.length]
  );

  const onScrollDebounced = useDebounce(
    ({ x, maxX }) => {
      if (items.length <= 1) return;

      const itemWidth = maxX / (items.length - 1);
      const itemIndex = Math.round(x / itemWidth);

      setActiveIndex(itemIndex);
      dotsRef.current?.setIndex(itemIndex);
    },
    100,
    [items.length]
  );

  return (
    <Box
      testId="videoSection"
      padding={`0 ${isLargeScreen ? '1.2rem' : '1.6rem'}`}
    >
      <Box positionRelative>
        <HorizontalScroller
          zIndex={1}
          withSnapping
          scrollerRef={scrollerRef}
          gradientColor="transparent"
          overflowStyle={
            isLargeScreen && items.length > 1 ? 'outside' : undefined
          }
          forceOverflowing={items.length > 1}
          scrollerStyle={{
            border: '1px solid #333',
            borderRadius: '1rem',
            overflow: 'hidden',
          }}
          contentStyle={{
            minWidth: 'calc(100% + 2px)',
            margin: '-1px',
            height: 'auto',
          }}
          onScroll={onScrollDebounced}
          renderContent={({ snapItemStyle }) =>
            items.map((item, index) => (
              <div
                key={item.storyId}
                data-testid="videoSectionItem"
                style={{
                  ...snapItemStyle,
                  width: '100%',
                  flexShrink: 0,
                  aspectRatio: '16 / 9',
                  overflow: 'hidden',
                }}
              >
                <VideoPlayer item={item} isActive={index === activeIndex} />
              </div>
            ))
          }
        />
      </Box>
      {items[activeIndex]?.title && (
        <Box padding="1rem 2rem">
          <Text
            size="1.4rem"
            lineHeight="1.8rem"
            color={pageTheme.textColor}
            centered
            withEllipsis
          >
            {items[activeIndex].title}
          </Text>
        </Box>
      )}
      {items.length > 1 && (
        <Box testId="videoSectionPagination" padding="1rem">
          <PaginatedDots
            apiRef={dotsRef}
            total={items.length}
            onItemClick={(index) => scrollTo(index, 'smooth')}
          />
        </Box>
      )}
    </Box>
  );
};

export const VideoSection: PageSectionComponent<VideoSectionProps> = (
  props
) => {
  const { items = [] } = props;

  const readyItems = getReadyItems(items);

  if (readyItems.length > 0) {
    return <VideoSectionView {...props} items={readyItems} />;
  }

  return null;
};
