import React from 'react';
import { TouchableWithoutFeedback } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import type { ReactElement, ReactNode } from 'react';
import type { StyleProp, ViewStyle, ViewProps } from 'react-native';
import Icon from '../Icon';
import { isHeroIcon } from '../Icon/utils';
import {
  BottomBar,
  BottomBarItem,
  BottomBarWrapper,
  BottomNavigationContainer,
  BottomNavigationTab,
  ContentWrapper,
  StyledBottomBarText,
} from './StyledBottomNavigation';
import { isIOS } from '../../utils/helpers';
import type { IconName } from '../Icon';
import Count from '../Badge/Count';

export type BottomNavigationTabType = {
  key: string;
  title?: string;
  icon: IconName;
  component: ReactNode;
  testID?: string;
  /**
   * Badge to display on the tab icon.
   */
  badge?: {
    /** The number to display on the badge. */
    count: number;
    /** Maximum number before showing `${max}+`. Defaults to 99. */
    max?: number;
    /** Testing id for the badge wrapper. */
    testID?: string;
  };
};
interface BottomNavigationProps extends ViewProps {
  /**
   * Callback which is called on tab press, receiving key of upcoming active Tab.
   */
  onTabPress: (key: string) => void;
  /**
   * Whether inactive tabs should be removed and unmounted in React.
   * Defaults to `false`.
   */
  renderActiveTabOnly?: boolean;
  /**
   * Current selected tab key.
   */
  selectedTabKey: string;
  /**
   * List of Tabs to be rendered. Each Tab must have an unique key.
   */
  tabs: BottomNavigationTabType[];
  /**
   * Additional style.
   */
  style?: StyleProp<ViewStyle>;
  /**
   * Testing id of the component.
   */
  testID?: string;
}

const getInactiveIcon = (icon: IconName): IconName => {
  const inactiveIcon = `${icon}-outlined`;
  return isHeroIcon(inactiveIcon) ? inactiveIcon : icon;
};

const BottomNavigation = ({
  onTabPress,
  renderActiveTabOnly = false,
  selectedTabKey,
  tabs,
  ...nativeProps
}: BottomNavigationProps): ReactElement => {
  const insets = useSafeAreaInsets();

  /**
   * List of loaded tabs, tabs will be loaded when navigated to.
   */
  const [loaded, setLoaded] = React.useState([selectedTabKey]);

  if (!loaded.includes(selectedTabKey)) {
    // Set the current tab to be loaded if it was not loaded before
    setLoaded((loadedState) => [...loadedState, selectedTabKey]);
  }

  return (
    <BottomNavigationContainer {...nativeProps}>
      <ContentWrapper>
        {tabs.map((tab) => {
          const { key, component, testID } = tab;
          const active = selectedTabKey === key;

          if (renderActiveTabOnly && !active) {
            return null;
          }

          if (!loaded.includes(key)) {
            // Don't render a screen if we've never navigated to it
            return null;
          }

          return (
            <BottomNavigationTab
              key={key}
              testID={testID ? `route-screen-${testID}` : undefined}
              pointerEvents={active ? 'auto' : 'none'}
              accessibilityElementsHidden={!active}
              importantForAccessibility={
                active ? 'auto' : 'no-hide-descendants'
              }
              collapsable={false}
              removeClippedSubviews={
                // On iOS, set removeClippedSubviews to true only when not focused
                // This is an workaround for a bug where the clipped view never re-appears.
                isIOS ? selectedTabKey !== key : true
              }
              themeVisibility={active}
            >
              {component}
            </BottomNavigationTab>
          );
        })}
      </ContentWrapper>
      <BottomBarWrapper themeInsets={insets}>
        <BottomBar>
          {tabs.map((tab) => {
            const { key, icon, title, testID, badge } = tab;
            const active = selectedTabKey === key;
            const inactiveIcon = getInactiveIcon(icon);

            return (
              <TouchableWithoutFeedback
                key={key}
                onPress={() => onTabPress(key)}
                testID={testID}
              >
                <BottomBarItem>
                  <Count
                    content={badge?.count ?? 0}
                    visible={!!badge && badge.count > 0}
                    max={badge?.max}
                    testID={badge?.testID ?? `bottom-nav-badge-${key}`}
                  >
                    <Icon
                      icon={active ? icon : inactiveIcon}
                      intent={active ? 'primary' : 'muted'}
                      testID={`hero-icon-${icon}`}
                    />
                  </Count>
                  {!!title && (
                    <StyledBottomBarText
                      intent={active ? 'primary' : 'muted'}
                      numberOfLines={1}
                    >
                      {title}
                    </StyledBottomBarText>
                  )}
                </BottomBarItem>
              </TouchableWithoutFeedback>
            );
          })}
        </BottomBar>
      </BottomBarWrapper>
    </BottomNavigationContainer>
  );
};

export default BottomNavigation;
