import React, {ReactNode, useCallback, useEffect, useMemo, useRef} from 'react';
import {StyleProp, StyleSheet, ViewStyle} from 'react-native';
import {KeyboardController} from 'react-native-keyboard-controller';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {
  BottomSheetFooter,
  BottomSheetFooterProps,
  BottomSheetModal,
  BottomSheetModalProps,
} from '@gorhom/bottom-sheet';
import {useBackHandler} from '@hooks/useBackHandler';
import {windowDimensions} from '@shared/constants';
import {BORDER_RADIUS, SPACING, useTheme} from '@shared/theme';
import {isAndroid, isIos} from '@shared/utils';

import {Handle, HandleProps} from './components/HandleComponent';
import {BackDrop, BackDropProps} from './components/BackdropComponent';

export interface BottomModalRootProps {
  isVisible: boolean;
  onClose?: () => void;
  children?: ReactNode;
  enableDynamicSizing?: boolean;
  locked?: boolean;
  snapPoints?: (string | number)[];
  footerComponent?: ReactNode;
  fullScreen?: boolean;
  index?: number;
  enableContentPanningGesture?: boolean;
  withBackdrop?: boolean;
  onChange?: (index: number) => void;
  style?: StyleProp<ViewStyle>;
  stackBehavior?: BottomSheetModalProps['stackBehavior'];
}

export function BottomModalRoot({
  isVisible,
  children,
  onClose,
  snapPoints,
  footerComponent,
  fullScreen,
  enableDynamicSizing = true,
  locked = false,
  index = 0,
  enableContentPanningGesture = true,
  withBackdrop = true,
  onChange,
  style,
  stackBehavior,
}: BottomModalRootProps) {
  const modalRef = useRef<BottomSheetModal>(null);
  const {top} = useSafeAreaInsets();
  const {theme} = useTheme();
  /**
   * Sometimes the top is 0, so we need to set a default value
   */
  const maxSnapPoint = windowDimensions.height - (top || (isAndroid ? 48 : 56));

  /**
   * This is required to avoid overlaps on the phone's StatusBar
   */
  const fullScreenSnapPoint = useMemo(() => [maxSnapPoint], [maxSnapPoint]);

  const handleComponent = useCallback(
    (props: HandleProps) => <Handle {...props} />,
    [],
  );

  const backdropComponent = useCallback(
    (props: BackDropProps) =>
      withBackdrop ? (
        <BackDrop
          {...props}
          onPress={locked ? undefined : onClose}
          pressBehavior={locked ? 'none' : 'close'}
          accessible={false}
        />
      ) : null,
    [locked, onClose, withBackdrop],
  );

  const bottomSheetfooterComponent = useCallback(
    (props: BottomSheetFooterProps) =>
      footerComponent ? (
        <BottomSheetFooter {...props}>{footerComponent}</BottomSheetFooter>
      ) : null,
    [footerComponent],
  );

  const goBack = useCallback(() => {
    if (isVisible && !locked) {
      onClose?.();
      return true;
    }
  }, [isVisible, locked, onClose]);

  useBackHandler(goBack);

  useEffect(() => {
    if (isVisible) {
      modalRef.current?.present();
    } else {
      modalRef.current?.close();
    }
  }, [isVisible]);

  useEffect(() => {
    KeyboardController.dismiss();
  }, [isVisible]);

  return (
    <BottomSheetModal
      ref={modalRef}
      accessible={!isIos}
      enableDynamicSizing={!fullScreen && !snapPoints && enableDynamicSizing}
      enablePanDownToClose={!locked}
      enableContentPanningGesture={enableContentPanningGesture}
      enableOverDrag={!locked}
      enableHandlePanningGesture={!locked}
      snapPoints={fullScreen ? fullScreenSnapPoint : snapPoints}
      maxDynamicContentSize={maxSnapPoint}
      handleComponent={locked ? null : handleComponent}
      backdropComponent={backdropComponent}
      onDismiss={locked ? undefined : onClose}
      footerComponent={bottomSheetfooterComponent}
      style={[styles.modal, {borderColor: theme.border.neutral.default}, style]}
      backgroundStyle={{backgroundColor: theme.background.layout.tertiary}}
      handleStyle={styles.handle}
      index={index}
      // This is for fixing the overlap when the keyboard is open in iOS
      keyboardBehavior={fullScreen ? 'extend' : 'interactive'}
      onChange={onChange}
      stackBehavior={stackBehavior}>
      {children}
    </BottomSheetModal>
  );
}

const styles = StyleSheet.create({
  modal: {
    borderTopLeftRadius: BORDER_RADIUS.l,
    borderTopRightRadius: BORDER_RADIUS.l,
    paddingTop: SPACING.x1,
    paddingBottom: SPACING.x2,
    borderWidth: 1,
  },
  handle: {padding: 0},
});
