import React, { useState, useCallback, useEffect, useRef } from 'react';
import {
  Animated,
  Dimensions,
  NativeScrollEvent,
  NativeSyntheticEvent,
  ScrollView,
} from 'react-native';
import { fp as _ } from '../../utils/fp';
import { getNextStepIndex } from '../../transducers';
import { TScrollToItem } from '../../types';
import { theme } from '../../../app/theme';
import { SCarouselDot } from '../../s-components/s-carousel-dot';
import { SRow } from '../../s-components/layout/s-row';
import { SBox } from '../../s-components/layout/s-box';
import { SBoxAnimated } from '../../s-components/layout/s-box-animated';
import { SCarouselLine } from '../../s-components/s-carousel-line';

const { width: DEVICE_WIDTH, height: DEVICE_HEIGHT } = Dimensions.get('window');
const ROUNDED_WIDTH = Math.floor(DEVICE_WIDTH);
const ROUNDED_HEIGHT = Math.floor(DEVICE_HEIGHT);

type TProps = {
  data: any[];
  renderItem: (item: any, i?: number) => React.ReactNode;
  keyExtractor: (item: any) => number | string;
  // initialScrollIndex?: number;
  // onEndReached?: () => void;
  itemHeight?: number;
  itemWidth?: number;
  withDots?: boolean;
  dotVariant?: 'top:line' | 'bottom:line' | 'top:round' | 'bottom:round';
  renderHeader?: (i: number) => React.ReactNode;
  renderFooter?: (i: number) => React.ReactNode;
  startIndex?: number | null;
  disableSwipe?: boolean;
};

export const CarouselFullscreen: React.FC<TProps> = props => {
  const {
    startIndex,
    itemHeight,
    itemWidth,
    data,
    keyExtractor,
    dotVariant,
    renderItem,
    renderHeader,
    renderFooter,
    withDots,
    disableSwipe,
  } = props;
  const [currentStepIndex, setCurrentStepIndex] = useState(0);
  const dotTopPosition = _.includes('top')(dotVariant);
  const isDisabled = !disableSwipe;

  let scrollRef = useRef<ScrollView | null>(null);

  const scrollX = useRef(new Animated.Value(0));

  const getItemWidth = useCallback(() => {
    return itemWidth! || ROUNDED_WIDTH;
  }, [itemWidth]);

  const scrollToItem: TScrollToItem = ({ stepNumber, withAnimation }) => {
    if (scrollRef && scrollRef) {
      // @ts-ignore
      scrollRef.scrollTo({
        x: stepNumber * getItemWidth(),
        y: 0,
        animated: withAnimation,
      });
      setCurrentStepIndex(stepNumber);
    }
  };

  useEffect(() => {
    if (startIndex !== 0) {
      setTimeout(() => {
        scrollToItem({ stepNumber: startIndex!, withAnimation: false });
      }, 0);
    }

    setTimeout(() => {
      scrollToItem({
        stepNumber: startIndex!,
        withAnimation: true,
      });
    }, 0);
  }, [startIndex, currentStepIndex]);

  const onMomentumScrollEnd = (
    event: NativeSyntheticEvent<NativeScrollEvent>
  ) => {
    const currentStepIndex = getNextStepIndex({
      currentOffset: event.nativeEvent.contentOffset.x,
      width: ROUNDED_WIDTH,
    });
    setCurrentStepIndex(currentStepIndex);
  };

  const getItemHeight = useCallback(() => {
    return itemHeight! || ROUNDED_HEIGHT;
  }, [itemHeight]);

  // const getDotsAnimations = (index: number) => {
  //   const itemWidth = getItemWidth();
  //   const inputRange = getDotsRange(index, itemWidth);
  //   return getAnimation({
  //     opacity: {
  //       inputRange,
  //       outputRange: [0, 1, 0],
  //     },
  //   })(scrollX.current);
  // };

  const renderDot = (variant: string, bg: string) => {
    const isRound = _.includes('round')(variant);
    return isRound ? <SCarouselDot bg={bg} /> : <SCarouselLine bg={bg} />;
  };

  const renderDots = useCallback(() => {
    if (data.length < 2) return null;

    return data.map((el, i) => {
      return (
        <SBox position="relative" key={keyExtractor(el)}>
          <SBoxAnimated
            position="absolute"
            style={[{ opacity: i <= currentStepIndex ? 1 : 0 }]}
          >
            {renderDot(dotVariant!, theme.colors.wildStrawberry)}
          </SBoxAnimated>
          {renderDot(dotVariant!, theme.colors.eastBay)}
        </SBox>
      );
    });
  }, [data, keyExtractor, dotVariant]);

  const renderItems = useCallback(() => {
    return data.map((el, i) => {
      return (
        <SBoxAnimated
          flex={1}
          width={getItemWidth()}
          height={getItemHeight()}
          key={keyExtractor(el)}
        >
          {renderItem(el, i)}
        </SBoxAnimated>
      );
    });
  }, [data, renderItem, keyExtractor]);

  return (
    <SBox
      flexDirection="column"
      flex={1}
      position="absolute"
      width="100%"
      height={ROUNDED_HEIGHT}
      zIndex={1000}
      bg="ebonyClay"
    >
      <SBox
        flex={0.15}
        width={1}
        justifyContent="center"
        alignItems="center"
        px={16}
      >
        {_.isFunction(renderHeader) ? renderHeader(currentStepIndex) : null}
      </SBox>
      {dotTopPosition && withDots ? (
        <SRow justifyContent="center" alignItems="center" flex={0.05} mt={-10}>
          {renderDots()}
        </SRow>
      ) : null}
      <SBox flex={0.6}>
        <Animated.ScrollView
          scrollEnabled={
            (disableSwipe && isDisabled) || (!disableSwipe && data.length > 1)
          }
          horizontal
          pagingEnabled
          snapToAlignment="start"
          // scroll by several slides per drug
          // snapToInterval={this.getItemWidth()}
          ref={(ref: any) => {
            // @ts-ignore
            scrollRef = ref as ScrollView;
          }}
          showsHorizontalScrollIndicator={false}
          onScroll={Animated.event(
            [
              {
                nativeEvent: { contentOffset: { x: scrollX.current } },
              },
            ],
            { useNativeDriver: true }
          )}
          scrollEventThrottle={16}
          onMomentumScrollEnd={onMomentumScrollEnd}
        >
          {renderItems()}
        </Animated.ScrollView>
      </SBox>
      {!dotTopPosition && withDots ? (
        <SRow justifyContent="center" alignItems="center" flex={0.05}>
          {renderDots()}
        </SRow>
      ) : null}

      <SBox
        flex={0.2}
        width={1}
        justifyContent="center"
        alignItems="center"
        px={16}
      >
        {_.isFunction(renderFooter) ? renderFooter(currentStepIndex) : null}
      </SBox>
    </SBox>
  );
};

CarouselFullscreen.defaultProps = {
  // initialScrollIndex: 0,
  // withButtons: false,
  withDots: false,
  disableSwipe: false,
  startIndex: 0,
};
