import type { ReactElement, ReactNode } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { Animated, Dimensions, Easing } from 'react-native';
import DragableDrawer from './DragableDrawer';

import {
  StyledBackdrop,
  StyledContainer,
  StyledDrawerContainer,
} from './StyledDrawer';

const BACKDROP_OPACITY = 0.56;

interface DrawerProps {
  /**
   * Drawer's visibility.
   */
  visible: boolean;
  /**
   * Drawer's content.
   */
  children?: ReactNode;
  /**
   * Enable the drawer's backdrop.
   */
  hasBackdrop?: boolean;
  /**
   * Callback when the drawer is dismissed by interacting outside of the drawer.
   */
  onDismiss?: () => void;
  /**
   * Testing id of the component.
   * */
  testID?: string;
}

const Drawer = ({
  visible,
  children,
  hasBackdrop = true,
  onDismiss,
  testID,
}: DrawerProps): ReactElement => {
  const animatedValue = useRef(new Animated.Value(visible ? 1 : 0)).current;
  const [height, setHeight] = useState(Dimensions.get('window').height);

  const enableShadow = visible && hasBackdrop;

  const interpolateTranslateY = animatedValue.interpolate({
    inputRange: [0, 1],
    outputRange: [-height, 0],
  });

  const interpolateBackdropOpacity = hasBackdrop
    ? animatedValue.interpolate({
        inputRange: [0, 1],
        outputRange: [0, BACKDROP_OPACITY],
      })
    : 0;

  useEffect(() => {
    const animation = Animated.timing(animatedValue, {
      toValue: visible ? 1 : 0,
      easing: Easing.inOut(Easing.cubic),
      useNativeDriver: true,
    });

    animation.start();

    return () => animation.stop();
  }, [visible]);

  return (
    <StyledContainer
      testID={testID}
      enableShadow={enableShadow}
      pointerEvents="box-none"
    >
      <StyledBackdrop
        testID={`${testID}-backdrop`}
        pointerEvents={visible ? 'auto' : 'box-none'}
        onPress={onDismiss}
        style={{ opacity: interpolateBackdropOpacity }}
      />
      <StyledDrawerContainer
        enableShadow={enableShadow}
        onLayout={({ nativeEvent }) => setHeight(nativeEvent.layout.height)}
        style={{
          transform: [{ translateY: interpolateTranslateY }],
        }}
      >
        {children}
      </StyledDrawerContainer>
    </StyledContainer>
  );
};

export default Object.assign(Drawer, {
  Dragable: DragableDrawer,
});
