import React, { useMemo, useState } from 'react';

import type { ReactElement, ReactNode } from 'react';
import {
  StyledDragableContainer,
  StyledDragableDrawerContainer,
  StyledHandler,
  StyledHandlerContainer,
} from '../StyledDrawer';
import DragableDrawerContext from './DragableDrawerContext';
import useDragablePan from './useDragablePan';

export interface DragableDrawerProps {
  /**
   * Drawer's content.
   */
  children?: ReactNode;
  /**
   * Initial visible height percentage of the drawer. Can be used to programmatically control the drawer height. Range: [0,100].
   */
  initialHeightPercentage?: number;
  /**
   * Mininum visible height percentage of the drawer. This will be the lowest point in snap points list. Range: [0,100].
   */
  minimumHeightPercentage?: number;
  /**
   * Callback function is called when the drawer expand to max position.
   */
  onExpanded?: () => void;
  /**
   * Callback function is called when the drawer collapsed to min position.
   */
  onCollapsed?: () => void;
  /**
   * Testing id of the component.
   */
  testID?: string;
  /**
   * Nearest height snap points that the drawer will attach to on release gesture. Range: [0,100]
   */
  snapPoints?: number[];
}

const DragableDrawer = ({
  children,
  initialHeightPercentage,
  minimumHeightPercentage = 10,
  snapPoints = [],
  onExpanded,
  onCollapsed,
  testID,
}: DragableDrawerProps): ReactElement => {
  const [height, setHeight] = useState(0);

  const {
    pan,
    isAtMaxHeight,
    scrollYRef,
    onScrollY,
    beginPan,
    movePan,
    releasePan,
    panHandlers,
  } = useDragablePan({
    height,
    initialHeightPercentage,
    minimumHeightPercentage,
    snapPoints,
    onExpanded,
    onCollapsed,
  });

  const contextValue = useMemo(
    () => ({
      isAtMaxHeight,
      scrollYRef,
      onScrollY,
      beginPan,
      movePan,
      releasePan,
    }),
    [isAtMaxHeight, onScrollY, beginPan, movePan, releasePan]
  );

  return (
    <DragableDrawerContext.Provider value={contextValue}>
      <StyledDragableContainer
        testID={testID}
        enableShadow
        pointerEvents="box-none"
      >
        <StyledDragableDrawerContainer
          enableShadow
          style={{
            transform: [{ scaleY: height > 0 ? 1 : 0 }, { translateY: pan }],
          }}
          onLayout={({ nativeEvent }) => {
            setHeight(nativeEvent.layout.height);
          }}
        >
          <StyledHandlerContainer {...panHandlers}>
            <StyledHandler />
          </StyledHandlerContainer>
          {children}
        </StyledDragableDrawerContainer>
      </StyledDragableContainer>
    </DragableDrawerContext.Provider>
  );
};

export default DragableDrawer;
