import { cloneElement, forwardRef, isValidElement, memo, ReactElement, useCallback, useEffect, useState } from 'react';

import { Keyboard } from 'react-native';
import Animated, { Easing, SharedValue, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
import { Container, ContainerRef } from '@cleartrip/ct-design-container';
import { Overlay } from '@cleartrip/ct-design-overlay';
import { Portal } from '@cleartrip/ct-design-portal';
import { makeStyles, useStyles } from '@cleartrip/ct-design-style-manager';
import { Cross, ModalBack } from '@cleartrip/ct-design-icons';

import { ActionButtonVariantsType, IChildProps, IModalProps, ModalVariantTypes } from './type';
import { ActionButtonAlignment, ActionButtonVariant, ModalPlacement, ModalSize, ModalVariant } from './constants';
import { getActionButtonAlignment, getModalChildContainerStyle } from './style.native';
import { MODAL_ANIMATION_DURATION } from './modalUtils';

const staticStyles = makeStyles((theme) => ({
  modal: {
    position: 'absolute',
    height: '100%',
    margin: 'auto',
    width: '100%',
    justifyContent: 'center',
    alignItems: 'center',
  },
  modalContentContainer: {
    flex: 1,
    width: '100%',
    height: '100%',
  },
  modalContent: {
    position: 'relative',
    overflow: 'scroll',
    maxWidth: '90%',
    maxHeight: '90%',
    width: '90%',
    margin: 'auto',
    borderRadius: theme?.border?.radius?.[2],
    justifyContent: 'center',
  },
  overlayStyles: {
    position: 'absolute',
    left: 0,
    right: 0,
    justifyContent: 'center',
    alignItems: 'center',
    top: 0,
    zIndex: -1,
    bottom: 0,
    flex: 1,
  },
  modalBody: {
    backgroundColor: theme?.color?.background?.neutral,
    borderRadius: theme?.border?.radius?.[12],
  },
  actionButtonWrapper: {
    top: 0,
    height: 45,
  },
  actionButton: {
    marginLeft: 'auto',
    alignItems: 'center',
    backgroundColor: theme?.color?.background?.neutral,
    borderRadius: theme?.border?.radius?.[16],
    justifyContent: 'center',
    height: theme?.size?.[8],
    width: theme?.size?.[8],
  },
}));

const getActionIcon = ({
  actionButtonType,
  variant,
}: {
  actionButtonType: ActionButtonVariantsType;
  variant: ModalVariantTypes;
}): ReactElement => {
  if (actionButtonType === ActionButtonVariant.BACK) {
    return <ModalBack />;
  }

  return <Cross height={24} width={24} crossColor={variant === ModalVariant.DARK ? 'black' : '#1A1A1A'} />;
};

const Modal = forwardRef<ContainerRef, IModalProps>(
  (
    {
      actionButtonAlignment = ActionButtonAlignment.RIGHT,
      actionButtonType = ActionButtonVariant.CLOSE,
      allowBackdropClose = true,
      animationDuration = MODAL_ANIMATION_DURATION,
      backDropComponent,
      blur = true,
      children,
      onClose,
      open = false,
      placement = ModalPlacement.CENTER,
      size = ModalSize.MEDIUM,
      styleConfig,
      variant = ModalVariant.NEUTRAL,
    },
    ref,
  ) => {
    const [isModalVisible, setIsModalVisible] = useState<boolean>(open);
    const CloseIcon: ReactElement = getActionIcon({ actionButtonType, variant });
    const opacity: SharedValue<number> = useSharedValue(0);

    const {
      root: customRootStyles = [],
      backdropStyles: customOverlayStyles = [],
      modalContentStyles: customModalContentStyles = [],
    } = styleConfig || {};

    const modalContentAnimatedStyle = useAnimatedStyle(() => ({
      opacity: opacity.value,
    }));

    const actionButtonAlignmentStyles = useStyles(
      () => ({
        root: getActionButtonAlignment({ actionButtonAlignment }),
      }),
      [actionButtonAlignment],
    );

    const dynamicModalContainerStyle = useStyles(
      () => ({
        root: { justifyContent: placement === 'center' ? 'center' : 'flex-end', zIndex: 1000 },
      }),
      [placement],
    );

    const dynamicModalContentStyles = useStyles(
      (theme) => ({
        childContainer: getModalChildContainerStyle({ theme, size, blur }),
      }),
      [size, blur],
    );

    const handleBackdropClose = (): void => {
      if (allowBackdropClose) {
        onClose?.();
        setIsModalVisible(false);
      }
    };

    const getModalAnimation = useCallback((): void => {
      opacity.value = withTiming(opacity.value === 0 ? 1 : 0, {
        duration: animationDuration,
        easing: Easing.bezier(0.4, 0, 0.2, 1),
      });
    }, [animationDuration, opacity]);

    useEffect(() => {
      setIsModalVisible(open);
      getModalAnimation();
      if (Keyboard.isVisible()) Keyboard.dismiss();
      return () => {
        opacity.value = 0;
      };
    }, [open, animationDuration, opacity, getModalAnimation]);

    if (!isModalVisible) {
      return null;
    }

    return (
      <Portal id='global_modal'>
        <Container
          styleConfig={{
            root: [staticStyles.modal, dynamicModalContainerStyle.root, ...customRootStyles],
          }}
          ref={ref}
        >
          <Animated.View style={[modalContentAnimatedStyle, staticStyles.overlayStyles]}>
            {backDropComponent || (
              <Container styleConfig={{ root: [staticStyles.modalContentContainer] }} onClick={handleBackdropClose}>
                <Overlay blur={blur} styleConfig={{ root: [...customOverlayStyles] }} />
              </Container>
            )}
          </Animated.View>

          <Container
            styleConfig={{
              root: [staticStyles.modalContent, dynamicModalContentStyles?.childContainer, ...customModalContentStyles],
            }}
          >
            {actionButtonType !== ActionButtonVariant.NONE ? (
              <Container styleConfig={{ root: [staticStyles.actionButtonWrapper] }}>
                <Container
                  styleConfig={{
                    root: [staticStyles.actionButton, actionButtonAlignmentStyles.root],
                  }}
                  onClick={onClose}
                >
                  {CloseIcon}
                </Container>
              </Container>
            ) : null}

            <Container styleConfig={{ root: [staticStyles.modalBody] }}>
              {isValidElement<IChildProps>(children) && cloneElement(children, { onClose, ...(children.props || {}) })}
            </Container>
          </Container>
        </Container>
      </Portal>
    );
  },
);

Modal.displayName = 'Modal';
export default memo(Modal);
