import React, {
  forwardRef,
  ReactNode,
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from 'react';
import {StyleProp, ViewStyle} from 'react-native';
import {TabView as RNTabView} from 'react-native-tab-view';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
} from 'react-native-reanimated';
import {getThemeValue, ThemeColorKey, useTheme} from '@shared/theme';

import styles from './styles';
import {AnimatedValueContext} from '../../hooks/useAnimatedValueContext';
import {
  RenderSceneProps,
  TabItem,
  TabsHeaderProps,
  TabsRef,
} from '../../interfaces';
import {buildRenderSceneWithActive} from '../../utils';
import {AnimatedTabsHeader} from '../AnimatedTabsHeader';
import {TabsHeader} from './components/TabsHeader';

interface Props {
  routes: TabItem[];
  initialIndex?: number;
  renderScene: (props: RenderSceneProps) => ReactNode;
  onTabChange?: (key: string, index: number) => void;
  showHeader?: boolean;
  renderLazyPlaceholder?: () => ReactNode;
  swipeEnabled?: boolean;
  lazy?: boolean;
  backgroundColor?: ThemeColorKey;
  tabContainerStyle?: StyleProp<ViewStyle>;
  withDivider?: boolean;
  fullWidth?: boolean;
  /** When false, pager uses `setPageWithoutAnimation` (react-native-pager-view on Android). */
  animationEnabled?: boolean;
  headerStyle?: StyleProp<ViewStyle>;
}

export const Tabs = forwardRef<TabsRef, Props>(
  (
    {
      routes,
      renderScene,
      onTabChange,
      renderLazyPlaceholder,
      swipeEnabled,
      lazy = true,
      initialIndex = 0,
      showHeader = true,
      backgroundColor = 'background.layout.tertiary',
      tabContainerStyle,
      withDivider = false,
      fullWidth,
      animationEnabled = true,
      headerStyle,
    },
    ref,
  ) => {
    const {theme} = useTheme();
    const [index, setIndex] = useState<number>(initialIndex);
    const indexRef = useRef(initialIndex);
    const tabAnimatedValue = useSharedValue(0);
    const headerTranslateY = useSharedValue(0);
    const navigationState = useMemo(() => ({index, routes}), [index, routes]);
    const style = useMemo(
      () => ({backgroundColor: getThemeValue(theme, backgroundColor)}),
      [backgroundColor, theme],
    );

    useImperativeHandle(
      ref,
      () => ({
        goToIndex: newIndex => {
          indexRef.current = newIndex;
          setIndex(newIndex);
        },
        goToRouteKey: (newKey: string) => {
          const newIndex = routes.findIndex(route => route.key === newKey);
          indexRef.current = newIndex;
          setIndex(newIndex);
        },
        currentIndex: index,
      }),
      [index, routes],
    );

    const onIndexChange = useCallback(
      (indexValue: number): void => {
        indexRef.current = indexValue;
        setIndex(indexValue);
        onTabChange?.(routes[indexValue].key, indexValue);
      },
      [onTabChange, routes],
    );

    const renderTabBar = useCallback(
      (props: TabsHeaderProps) => {
        if (!showHeader) {
          return null;
        }

        return (
          <AnimatedTabsHeader>
            <TabsHeader
              {...props}
              withDivider={withDivider}
              fullWidth={fullWidth}
              containerStyle={headerStyle}
            />
          </AnimatedTabsHeader>
        );
      },
      [showHeader, withDivider, fullWidth, headerStyle],
    );

    const renderSceneWithActive = useMemo(
      () => buildRenderSceneWithActive(routes, indexRef, renderScene),
      [renderScene, routes],
    );

    /**
     * Effect to ensure show the tab header when changing tabs
     */
    useEffect(() => {
      tabAnimatedValue.value = 0;
    }, [tabAnimatedValue, index]);

    const tabViewAnimatedStyle = useAnimatedStyle(() => {
      const translateY = headerTranslateY.value;
      return {
        transform: [{translateY}],
      };
    });

    const value = useMemo(
      () => ({tabAnimatedValue, headerTranslateY}),
      [tabAnimatedValue, headerTranslateY],
    );

    return (
      <AnimatedValueContext.Provider value={value}>
        <Animated.View
          style={[
            styles.tabsContainer,
            tabViewAnimatedStyle,
            tabContainerStyle,
          ]}>
          <RNTabView
            animationEnabled={animationEnabled}
            navigationState={navigationState}
            onIndexChange={onIndexChange}
            renderScene={renderSceneWithActive}
            renderTabBar={renderTabBar}
            renderLazyPlaceholder={renderLazyPlaceholder}
            swipeEnabled={swipeEnabled}
            lazy={lazy}
            style={style}
          />
        </Animated.View>
      </AnimatedValueContext.Provider>
    );
  },
);
