import * as React from 'react';

import { Body, Content, Footer, Line, Overlay } from './Modal.styled';
import { Box, Shelf } from '../Layout';
import { ZIndexProvider, useZIndex } from '../ZIndex';
import { bool, func, node, oneOf, string } from 'prop-types';

import Button from '../Button';
import { Heading } from '../Text';
import Icon from '../Icon';
import { Transition } from 'react-transition-group';
import css from '@styled-system/css';
/** @jsx jsx */
import { jsx } from '@emotion/core';
import { oneOfType } from 'prop-types';

const ModalContext = React.createContext(null);

const Modal = (props) => {
  const {
    open,
    toggle,
    footer,
    body,
    className,
    overlayClassName,
    size,
    onClosed,
    unmountOnExit = true,
    onEntered,
    children,
    disableClose,
    closeOnOutsideClick = true,
  } = props;
  const parentZIndex = useZIndex();
  const zIndex = parentZIndex + 20;
  if (children && (body || footer))
    throw new Error('Modal: provide only `children` or `body`/`footer`, not both');
  return (
    <ModalContext.Provider value={props}>
      <Transition
        in={open}
        timeout={{ enter: 500, exit: 200 }}
        unmountOnExit={unmountOnExit}
        onExited={onClosed}
        onEntered={onEntered}
      >
        {(state) => (
          <Overlay
            isOpen
            onDismiss={() => {
              if (!disableClose && closeOnOutsideClick) toggle(false);
            }}
            state={state}
            className={overlayClassName}
            style={{ zIndex }}
          >
            <Content state={state} aria-label="Dialog" size={size} className={className}>
              <ZIndexProvider value={zIndex}>
                {children}
                {body && <ModalBody>{body}</ModalBody>}
                {footer && <ModalFooter>{footer}</ModalFooter>}
              </ZIndexProvider>
            </Content>
          </Overlay>
        )}
      </Transition>
    </ModalContext.Provider>
  );
};
// eslint-disable-next-line react/prop-types
const ModalBody = ({ children }) => {
  const ctx = React.useContext(ModalContext);
  if (!ctx) throw new Error('ModalBody can only be used inside a Modal');
  const {
    title,
    toggle,
    bodyClassName,
    titleClass,
    titleDivider,
    bodyPadding,
    subtitle,
    disableClose,
  } = ctx;
  return (
    <Box p="large">
      {!disableClose && (
        <Button
          icon={<Icon name="close" size={16} />}
          appearance="minimal"
          aria-label="Close"
          onClick={() => toggle(false)}
          css={{
            cursor: 'pointer',
            position: 'absolute',
            top: '11px',
            right: '10px',
          }}
        />
      )}

      <Box
        css={css({
          '> * + *': {
            marginTop: 'small',
          },
        })}
        display="flex"
        flexDirection="column"
      >
        {title && (
          <React.Fragment>
            <Shelf alignItems="flex-end">
              <Heading level="h3" fontSize="heading.2" className={titleClass}>
                {title}
              </Heading>
              {subtitle && subtitle}
            </Shelf>
          </React.Fragment>
        )}
        {titleDivider && <Line />}
        <Body padding={bodyPadding} className={bodyClassName}>
          {children}
        </Body>
      </Box>
    </Box>
  );
};

// eslint-disable-next-line react/prop-types
const ModalFooter = ({ children }) => {
  const ctx = React.useContext(ModalContext);
  if (!ctx) throw new Error('ModalFooter can only be used inside a Modal');
  const { footerMargin } = ctx;
  return (
    <Footer
      p="medium"
      display="flex"
      justifyContent="space-between"
      alignItems="center"
      footerMargin={footerMargin}
    >
      {children}
    </Footer>
  );
};

Modal.propTypes = {
  children: node,
  subtitle: node,
  bodyClassName: string,
  overlayClassName: string,
  bodyPadding: oneOf(['none', 'medium']),
  footerMargin: oneOf(['none', 'left']),
  titleDivider: bool,
  open: bool,
  title: oneOfType([string, node]),
  toggle: func.isRequired,
  footer: node,
  body: node,
  className: string,
  titleClass: string,
  onClosed: func,
  disableClose: bool,
  size: oneOf(['small', 'medium', 'large', 'full']),
};

Modal.defaultProps = {
  children: undefined,
  footerMargin: 'left',
  subtitle: undefined,
  bodyPadding: 'medium',
  bodyClassName: undefined,
  overlayClassName: undefined,
  titleDivider: false,
  title: undefined,
  footer: undefined,
  body: undefined,
  className: '',
  titleClass: '',
  onClosed: () => {},
  disableClose: false,
  size: 'medium',
};

Modal.Body = ModalBody;
Modal.Footer = ModalFooter;

export default Modal;
