import React, { useRef, useEffect, useState } from 'react';
import propTypes from 'prop-types';
import ReactDOM from 'react-dom';
import classnames from 'classnames';
import styles from './styles.module.scss';

const Modal: React.FC<any> = ({
  visible,
  width, 
  height,
  children,
  onBlur,
  onEscape,
}: {
  visible: boolean,
  children: React.ReactNode,
  width?: string | number,
  height?: string | number,
  onBlur?: () => void,
  onEscape?: () => void,
}) => {
  const [modalState, setModalState] = useState<
    | 'norender'
    | 'invisible'
    | 'visible'
  >('norender');

  const dialog = useRef<HTMLDivElement>(null);
  const container = useRef<HTMLDivElement>(null);

  // Manage internal visibility/render state
  // This is needed to make animations behave properly
  useEffect(() => {
    let unmounted = false;
    if (visible) {
      setModalState('visible');
    } else if (modalState !== 'norender') {
      setModalState('invisible');
      setTimeout(() => !unmounted && setModalState('norender'), 200);
    }
    return () => unmounted = true;
  }, [visible]);

  // Focus the dialog whenever the modal state changes
  useEffect(() => {
    if (dialog.current) { dialog.current.focus(); }
    if (container.current) { container.current.scrollTop = 0; }
  }, [modalState]);

  const inlineStyle = {} as any;
  if (width) {
    inlineStyle.width = '100%';
    inlineStyle.maxWidth = width;
  }
  if (height) {
    inlineStyle.height = height;
  }

  return modalState === 'norender' ? null : ReactDOM.createPortal(
    <div
      tabIndex={0}
      onKeyDown={e => e.keyCode === 27 && onEscape && onEscape()}
      onMouseDown={onBlur}
      ref={container}
      className={classnames(
        styles.dashboardModalBackdrop,
        {[styles.visible]: modalState === 'visible'}
      )}
    >
      <div
        ref={dialog}
        tabIndex={0}
        className={styles.dashboardModalDialog}
        style={inlineStyle}
        onMouseDown={e => e.stopPropagation()}
      >
        {children}
      </div>
    </div>,
    document.body,
  );
}

Modal.propTypes = {
  visible: propTypes.bool.isRequired,
  children: propTypes.node.isRequired,
  width: propTypes.oneOfType([propTypes.string, propTypes.number]),
  height: propTypes.oneOfType([propTypes.string, propTypes.number]),
  onBlur: propTypes.func,
  onEscape: propTypes.func,
};
Modal.displayName = 'Modal';
export default Modal;
