/** @jsxImportSource @emotion/react */
import React, { FunctionComponent } from 'react';
import tw, { css, styled } from 'twin.macro';

/**
 * The amount of time in milliseconds for the
 * drawer in/out transition to complete.
 * This const is used to determine when to apply
 * the hidden state.
 */
const TRANSITION_DURATION = 600;

type TransitionState = 'entering' | 'entered' | 'exiting' | 'exited';

type DrawerProps = {
  isOpen: boolean;
  onClose: () => void;
  anchor: 'left' | 'right';
};

type DrawerContentProps = Omit<DrawerProps, 'onClose'> & {
  transitionState: TransitionState;
};

const DrawerUnderlay = styled.div(
  ({ isOpen = false }: Partial<DrawerProps>) => [
    tw`fixed inset-0 bg-white bg-opacity-10 z-40`,
    css`
      transition: backdrop-filter ${TRANSITION_DURATION}ms ease 0s,
        opacity 200ms ease 0s;
    `,
    isOpen && tw`opacity-100 backdrop-blur-[10px]`,
    !isOpen && tw`opacity-0 backdrop-blur-0 pointer-events-none`,
  ],
);

const DrawerContent = styled.div(
  ({
    isOpen = false,
    transitionState = 'exited',
    anchor = 'right',
  }: DrawerContentProps) => [
    tw`fixed top-0 bottom-0 bg-white bg-opacity-10 z-50 transform`,
    css`
      transition: transform 600ms cubic-bezier(0, 0.25, 0, 1) 0s;
    `,
    anchor === 'left' && tw`left-0`,
    anchor === 'right' && tw`right-0`,

    transitionState === 'entered' && tw`translate-x-0`,

    (transitionState === 'entering' || transitionState === 'exiting') &&
      anchor === 'left' &&
      tw`-translate-x-1/1`,
    (transitionState === 'entering' || transitionState === 'exiting') &&
      anchor === 'right' &&
      tw`translate-x-1/1`,

    transitionState === 'exited' &&
      anchor === 'left' &&
      tw`-translate-x-1/1 hidden`,
    transitionState === 'exited' &&
      anchor === 'right' &&
      tw`translate-x-1/1 hidden`,
  ],
);

export const Drawer: FunctionComponent<DrawerProps> = ({
  isOpen = false,
  anchor = 'right',
  onClose,
  children,
  ...props
}) => {
  const [transitionState, setTransitionState] = React.useState<TransitionState>(
    isOpen ? 'entered' : 'exited',
  );
  React.useEffect(() => {
    let timeout = setTimeout(() => {
      setTransitionState((transitionState) => {
        if (transitionState === 'entering') {
          return 'entered';
        }
        if (transitionState === 'exiting') {
          return 'exited';
        }
      });
      timeout = null;
    }, TRANSITION_DURATION);
    return () => {
      if (!timeout) return;
      clearTimeout(timeout);
    };
  }, [isOpen, setTransitionState]);

  React.useEffect(() => {
    if (isOpen) {
      if (transitionState !== 'entered') setTransitionState('entering');
    } else {
      if (transitionState !== 'exited') setTransitionState('exiting');
    }
  }, [isOpen, setTransitionState]);
  return (
    <>
      <DrawerUnderlay isOpen={isOpen} onClick={onClose} />
      <DrawerContent
        isOpen={isOpen}
        transitionState={transitionState}
        anchor={anchor}
        {...props}
      >
        {children}
      </DrawerContent>
    </>
  );
};

export default Drawer;
