import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import {
  NavigationContainer,
  NavigationIndependentTree,
  useFocusEffect,
} from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import React, { useContext, useEffect, useLayoutEffect, useRef } from 'react';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
  Animated,
  Platform,
  StatusBar,
  StyleSheet,
  useWindowDimensions,
  View,
} from 'react-native';
import { Colors } from '../../Consts';
import { Icon } from '../../Icon';
import { exportFontFamily, Text } from '../../Text';
import StackScreen from '../StackScreen';
import { BottomTabProps } from '../types';
import { getOptions, getStackOptions, useAppState } from '../utils';
import BottomTabBar from './BottomTabBar';
import { ApplicationContext, MiniAppContext } from '../../Context';

const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();

const TabScreen: React.FC<any> = ({ route, navigation }) => {
  const { navigator } = useContext(ApplicationContext);
  const context = useContext<any>(MiniAppContext);
  const { nested, options, screen, initialParams } = route?.params;
  const insets = useSafeAreaInsets();

  const opacityValue = 0.3;
  const scaleValue = 0.97;
  const opacity = useRef(new Animated.Value(opacityValue)).current;
  const scale = useRef(new Animated.Value(scaleValue)).current;
  const screenName = screen?.name || screen?.type?.name || 'Invalid';
  const { isBackgroundToForeground } = useAppState();

  const onScreenNavigated = (pre: string, current: string) => {
    if (!isBackgroundToForeground) {
      const data: any = {
        preScreenName: pre,
        screenName: current,
        componentName: 'Screen',
        state: 'navigated',
        action: 'push',
      };

      context?.autoTracking?.({
        ...context,
        ...data,
      });

      /**
       * debug toast
       */
      navigator?.maxApi?.showToastDebug?.({
        appId: context.appId,
        message: `${screenName} screen_navigated`,
        type: 'ERROR',
      });
    }
  };

  useFocusEffect(
    React.useCallback(
      () => {
        Animated.parallel([
          Animated.timing(opacity, {
            toValue: 1,
            duration: 200,
            useNativeDriver: true,
          }),
          Animated.timing(scale, {
            toValue: 1,
            duration: 200,
            useNativeDriver: true,
          }),
        ]).start();

        setTimeout(() => {
          navigator?.maxApi?.getDataObserver?.(
            'current_screen',
            (data: any) => {
              onScreenNavigated(data?.screenName, screenName);
              navigator?.maxApi?.setObserver?.('current_screen', {
                screenName,
              });
            },
          );
        }, 100);

        return () => {
          if (navigation.getState().index !== route?.params.index) {
            Animated.parallel([
              Animated.timing(opacity, {
                toValue: opacityValue,
                duration: 200,
                useNativeDriver: true,
              }),
              Animated.timing(scale, {
                toValue: scaleValue,
                duration: 200,
                useNativeDriver: true,
              }),
            ]).start();
          }
        };
      },
      // eslint-disable-next-line react-hooks/exhaustive-deps
      [],
    ),
  );

  useEffect(
    () => {
      const onFocusApp = navigator?.maxApi?.listen?.('onFocusApp', () => {
        if (navigation.isFocused()) {
          navigator?.maxApi?.getDataObserver?.(
            'current_screen',
            (data: any) => {
              onScreenNavigated(data?.screenName, screenName);
              navigator?.maxApi?.setObserver?.('current_screen', {
                screenName,
              });
            },
          );
        }
      });

      return () => {
        onFocusApp?.remove?.();
      };
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [],
  );

  let stackOptions = {};
  if (options) {
    stackOptions = getOptions(options);
  }

  if (nested) {
    return (
      <Animated.View
        style={[
          styles.container,
          {
            opacity,
            transform: [{ scale }],
          },
        ]}
      >
        <Stack.Navigator
          screenOptions={{
            headerStyle: {
              height: 52 + insets.top,
            },
          }}
        >
          <Stack.Screen
            name="Stack"
            component={StackScreen}
            initialParams={{
              screen,
              options: stackOptions,
              initialParams,
              bottomTab: 'nested',
            }}
            options={{ ...getStackOptions() }}
          />
        </Stack.Navigator>
      </Animated.View>
    );
  }

  return (
    <Animated.View
      style={[
        styles.container,
        {
          opacity,
          transform: [{ scale }],
        },
      ]}
    >
      <NavigationIndependentTree>
        <NavigationContainer>
          <Stack.Navigator
            screenOptions={{
              headerStyle: {
                height: 52 + insets.top,
              },
            }}
          >
            <Stack.Screen
              name="Stack"
              component={StackScreen}
              initialParams={{
                screen,
                options: stackOptions,
                initialParams,
                bottomTab: 'default',
              }}
              options={{ ...getStackOptions(), ...options }}
            />
          </Stack.Navigator>
        </NavigationContainer>
      </NavigationIndependentTree>
    </Animated.View>
  );
};

const BottomTab: React.FC<BottomTabProps> = ({
  nested,
  tabs,
  listeners,
  navigation,
  initialRouteName,
  floatingButton,
}) => {
  const { theme, navigator } = useContext(ApplicationContext);
  const dimensions = useWindowDimensions();
  const insets = useSafeAreaInsets();
  const initialIndex = tabs.findIndex(i => i.name === initialRouteName);
  const indicatorAnimated = useRef(new Animated.Value(0));
  const activeIndex = useRef(initialIndex > 0 ? initialIndex : 0);
  const itemWidth = dimensions.width / tabs.length;

  useLayoutEffect(() => {
    navigation?.setOptions({
      headerShown: false,
      headerTransparent: true,
      headerBackground: undefined,
    });
  }, [navigation]);

  useEffect(() => {
    Animated.timing(indicatorAnimated.current, {
      toValue: itemWidth * activeIndex.current,
      useNativeDriver: true,
      duration: 200,
    }).start();
  }, [itemWidth]);

  const onFocus = (e: any) => {
    activeIndex.current = tabs.findIndex(i => e.target.includes(i.name));
    Animated.timing(indicatorAnimated.current, {
      toValue: itemWidth * activeIndex.current,
      useNativeDriver: true,
      duration: 200,
    }).start();
  };

  const handler: {
    tabPress?: (e: any) => void;
    focus?: (e: any) => void;
    blur?: (e: any) => void;
    state?: (e: any) => void;
  } = {
    tabPress: e => {
      navigator?.maxApi?.triggerEventVibration?.('light');
      listeners?.tabPress?.(e);
    },
    focus: e => {
      onFocus(e);
      StatusBar.setBarStyle('dark-content', true);
      listeners?.focus?.(e);
    },
    blur: e => {
      listeners?.blur?.(e);
    },
  };

  return (
    <Tab.Navigator
      screenOptions={{
        headerShown: false,
        headerTransparent: true,
        headerBackground: undefined,
        tabBarLabelPosition: 'below-icon',
        tabBarBackground: () => (
          <View
            style={[
              styles.container,
              {
                backgroundColor: theme.colors.background.surface,
              },
            ]}
          >
            <Animated.View
              style={[
                styles.indicatorContainer,
                {
                  width: itemWidth,
                  transform: [{ translateX: indicatorAnimated.current }],
                },
              ]}
            >
              <View
                style={[
                  styles.indicator,
                  { backgroundColor: theme.colors.primary },
                ]}
              />
            </Animated.View>
          </View>
        ),
      }}
      tabBar={props => (
        <BottomTabBar
          {...props}
          floatingButton={floatingButton}
          inactiveTintColor={theme.colors.text.hint}
          activeTintColor={theme.colors.primary}
          style={[
            {
              height: 64 + Math.min(insets.bottom, 21),
            },
          ]}
        />
      )}
      initialRouteName={initialRouteName}
    >
      {tabs.map((item, index) => {
        const isNum = !isNaN(parseInt(`${item?.badgeLabel}`, 10));
        const isDot = typeof item?.badgeLabel === 'string' && !item?.badgeLabel;
        const isNumZero = isNum && Number(item.badgeLabel) === 0;

        let badgeLabel = item?.badgeLabel;
        if (isNumZero) {
          badgeLabel = undefined;
        }

        let badgeStyle: {
          marginRight: number;
          top: number;
          backgroundColor: string;
          width?: number;
        } = {
          marginRight: -8,
          top: -4,
          backgroundColor: Colors.orange_03,
        };

        if (isNum) {
          badgeStyle = {
            marginRight: -4,
            top: -4,
            backgroundColor: Colors.red_03,
          };
        }
        if (isDot) {
          badgeStyle = {
            marginRight: -2,
            top: -2,
            backgroundColor: Colors.orange_03,
            width: 12,
          };
        }

        return (
          <Tab.Screen
            key={`BottomTab-${item.name}`}
            name={item.name}
            component={TabScreen}
            initialParams={{ ...item, nested, index }}
            listeners={handler}
            options={{
              tabBarLabel: ({ focused, color }) => {
                return (
                  <Text
                    numberOfLines={1}
                    maxScaleRate={1.4}
                    typography={
                      focused ? 'label_xs_medium' : 'description_xs_regular'
                    }
                    color={color}
                  >
                    {item.label}
                  </Text>
                );
              },
              title: item.label,
              tabBarStyle: [
                {
                  height: 64,
                },
                styles.tabStyle,
              ],
              tabBarBadge: badgeLabel,
              tabBarBadgeStyle: [
                {
                  borderColor: 'white',
                  borderWidth: 2,
                  fontSize: 10,
                  lineHeight: 14,
                  fontWeight: 'bold',
                  alignSelf: 'center',
                  fontFamily: exportFontFamily('bold'),
                },
                badgeStyle,
              ],
              tabBarIcon: ({ color }) => (
                <Icon source={item.icon} color={color} size={28} />
              ),
              ...item,
            }}
          />
        );
      })}
    </Tab.Navigator>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1 },
  indicatorContainer: { position: 'absolute', top: 0 },
  indicator: {
    height: 2,
    width: 48,
    alignSelf: 'center',
    borderBottomLeftRadius: 2,
    borderBottomRightRadius: 2,
  },
  tabBarStyle: {
    ...Platform.select({
      ios: {
        shadowColor: Colors.black_10,
        shadowOffset: { width: 0, height: 4 },
        shadowOpacity: 1,
        shadowRadius: 4,
      },
      android: {
        elevation: 4,
      },
    }),
  },
  tabStyle: {
    paddingVertical: 4,
  },
});

export default BottomTab;
