import React, { useEffect, useMemo, useRef } from 'react';
import PagerView from 'react-native-pager-view';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import type { TabsProps } from '.';
import SceneView from './SceneView';
import type { ScrollableTabHeaderProps } from './ScrollableTabsHeader/ScrollableTabsHeader';
import ScrollableTabHeader from './ScrollableTabsHeader/ScrollableTabsHeader';
import { TabContainer } from './StyledScrollableTabs';
import useHandlePageScroll from './useHandlePageScroll';
import { ScreenContext, TabContext } from './useIsFocused';

export interface ScrollableTabProps extends Omit<TabsProps, 'header'> {
  variant?: 'underlined' | 'highlighted';
  header?: (props: ScrollableTabHeaderProps) => React.ReactElement | null;
}

const ScrollableTab = ({
  onTabPress,
  selectedTabKey,
  tabs,
  containerStyle,
  barStyle,
  lazy = false,
  lazyPreloadDistance = 1,
  swipeEnabled = true,
  testID: componentTestID,
  variant = 'highlighted',
  header,
}: ScrollableTabProps) => {
  const pagerViewRef = useRef<PagerView>(null);
  const insets = useSafeAreaInsets();
  const selectedTabIndex = tabs.findIndex(
    (item) => item.key === selectedTabKey
  );

  const { hasScrolled, onPageScrollStateChanged } = useHandlePageScroll();

  useEffect(() => {
    let timeoutHandle: ReturnType<typeof setTimeout>;
    if (selectedTabIndex !== -1) {
      // If the selected tab is changed too quickly, the setPage is crashed and not work anymore
      // We apply throttle to prevent this issue https://github.com/Thinkei/hero-design/issues/1715
      timeoutHandle = setTimeout(() => {
        // use no animation to prevent unexpected behavior if users select tab too quickly
        pagerViewRef.current?.setPageWithoutAnimation(selectedTabIndex);
      }, 200);
    }

    return () => {
      if (timeoutHandle) {
        clearTimeout(timeoutHandle);
      }
    };
  }, [selectedTabIndex, pagerViewRef]);

  const tabContextProviderValue = useMemo(
    () => ({
      selectedTabKey,
    }),
    [selectedTabKey]
  );

  const headerProps = useMemo(
    () => ({
      tabs,
      selectedIndex: selectedTabIndex,
      onTabPress,
      barStyle,
      insets,
      testID: componentTestID ? `${componentTestID}-tab-bar` : undefined,
      variant,
    }),
    [
      tabs,
      selectedTabIndex,
      onTabPress,
      barStyle,
      insets,
      componentTestID,
      variant,
    ]
  );

  return (
    <TabContext.Provider value={tabContextProviderValue}>
      <TabContainer style={containerStyle} testID={componentTestID}>
        {header ? (
          header(headerProps)
        ) : (
          <ScrollableTabHeader {...headerProps} />
        )}
        <PagerView
          initialPage={selectedTabIndex}
          ref={pagerViewRef}
          onPageScrollStateChanged={onPageScrollStateChanged}
          onPageSelected={(e) => {
            const index = e.nativeEvent.position;
            const selectedItem = tabs[index];
            if (hasScrolled.current && selectedItem) {
              setTimeout(() => {
                onTabPress(selectedItem.key);
              });
            }
          }}
          scrollEnabled={swipeEnabled}
          style={{ flex: 1 }}
        >
          {tabs.map((tab, index) => {
            const { key, component, testID } = tab;

            return (
              <ScreenContext.Provider value={key} key={key}>
                <SceneView
                  testID={testID}
                  index={index}
                  selectedIndex={selectedTabIndex}
                  lazy={lazy}
                  lazyPreloadDistance={lazyPreloadDistance}
                >
                  {component}
                </SceneView>
              </ScreenContext.Provider>
            );
          })}
        </PagerView>
      </TabContainer>
    </TabContext.Provider>
  );
};

export default ScrollableTab;
