// @flow
import React, { useEffect, useCallback } from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
import { UnstyledButton } from '../../behaviors';
import { Resets } from '../../../themes/patchwork-theme-provider';
import { Box } from '../../../primitives';
import { Head5 } from '../../typography';
import { SmallChevronLeft, Remove } from '../../icon';
import { useFocusTrap } from './use-focus-trap';
import type { ModalProps } from './modal.proptypes';
import {
  getBackgroundColor,
  getContentBackground,
  getBorderColor,
  getContentBoxShadowColor,
  getModalWidth,
  getModalHeaderPadding,
} from './modal.css-rules';

export const ModalBackground = styled(Box)`
  display: block;
  position: fixed;
  z-index: 1;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: ${getBackgroundColor};
`;

export const ModalHeader = styled(Box)`
  height: ${getModalHeaderPadding};
  width: 100%;
  padding-top: 20px;
`;

export const ModalContent = styled(Box)`
  max-width: ${getModalWidth};
  background-color: ${getContentBackground};
  box-shadow: 0 5px 15px 0 ${getContentBoxShadowColor};
  border: solid 1px ${getBorderColor};
  border-radius: 15px;
  z-index: 2;
  margin: 15vh auto;
  width: 80%;

  &:focus {
    outline: none;
  }
`;

export const ModalHeaderText = styled(Head5)`
  padding-left: 42px;
  padding-right: 42px;
`;

// keeping the buttons separate for testability
export const ModalCloseButton = styled(UnstyledButton)`
  padding: 30px;
`;
export const ModalBackButton = styled(UnstyledButton)`
  padding: 30px;
`;

function getBody() {
  const documentElement =
    typeof document !== 'undefined' ? document : undefined;
  return documentElement ? documentElement.body : null;
}

function lockBodyOverflow() {
  const body = getBody();

  if (body !== null && body.dataset.initialOverflow === undefined) {
    body.dataset.initialOverflow = body.style.overflow;
    body.style.overflow = 'hidden';
  }
}

function unlockBodyOverflow() {
  const body = getBody();

  if (body !== null && body.dataset.initialOverflow !== undefined) {
    body.style.overflow = body.dataset.initialOverflow;
    delete body.dataset.initialOverflow;
  }
}

export const Modal = ({
  show,
  persistent = false,
  onBack,
  onClose,
  size = 'lg',
  children,
  className = '',
  spacing,
  headerText,
  hideHeader = false,
  refToRestoreFocus,
  stacked,
  align,
  justify,
  wrap,
  'data-qa': dataQa,
  'data-cy': dataCy,
  id,
  backButtonLabel = 'back',
  closeButtonLabel = 'close',
  ...props
}: ModalProps) => {
  const modalRef = useFocusTrap({ show, refToRestoreFocus });

  const body = getBody();

  useEffect(() => {
    if (body) {
      return () => {
        unlockBodyOverflow();
      };
    }
  }, [body]);

  const handleBackgroundClick = useCallback(
    (event) => {
      event.preventDefault();
      if (!persistent) {
        onClose();
      }
    },
    [onClose, persistent],
  );

  const handleContentClick = useCallback((event) => {
    event.stopPropagation();
  }, []);

  const handleBackClick = useCallback(
    (event) => {
      event.stopPropagation();
      if (onBack) onBack();
    },
    [onBack],
  );

  const handleCloseClick = useCallback(
    (event) => {
      event.stopPropagation();
      onClose();
    },
    [onClose],
  );

  const handleKeyPress = useCallback(
    (event) => {
      if (show && !persistent && event.code === 'Escape') {
        onClose();
      }
    },
    [onClose, show, persistent],
  );

  useEffect(() => {
    if (show && !persistent) {
      window.addEventListener('keydown', handleKeyPress);
    }

    return () => {
      window.removeEventListener('keydown', handleKeyPress);
    };
  }, [handleKeyPress, show, persistent]);

  if (body == null) return null;

  if (show) {
    lockBodyOverflow();
  } else {
    unlockBodyOverflow();
  }

  return (
    show &&
    ReactDOM.createPortal(
      <Resets face="sans">
        <ModalBackground onClick={handleBackgroundClick}>
          <ModalContent
            onClick={handleContentClick}
            size={size}
            className={className}
            ref={modalRef}
            role="dialog"
            aria-modal="true"
            data-cy={dataCy}
            data-qa={dataQa}
            id={id}
            {...props}
          >
            {!hideHeader && (
              <ModalHeader
                stacked="row"
                justify="space-between"
                align="center"
                size={size}
              >
                <Box basis={72} justify="center" align="center">
                  {onBack && (
                    <ModalBackButton
                      insetFocus
                      onClick={handleBackClick}
                      aria-label={backButtonLabel}
                    >
                      <SmallChevronLeft colorName="greyscale-dark" />
                    </ModalBackButton>
                  )}
                </Box>

                {headerText != null && (
                  <ModalHeaderText fontSize="f0">{headerText}</ModalHeaderText>
                )}
                <Box basis={72} justify="center" align="center">
                  {!persistent && (
                    <ModalCloseButton
                      insetFocus
                      onClick={handleCloseClick}
                      aria-label={closeButtonLabel}
                    >
                      <Remove size={12} color="greyscale-dark" />
                    </ModalCloseButton>
                  )}
                </Box>
              </ModalHeader>
            )}

            <Box
              spacing={spacing || ['ph6', 'pb4']}
              {...{ stacked, align, justify, wrap }}
            >
              {children}
            </Box>
          </ModalContent>
        </ModalBackground>
      </Resets>,
      body,
    )
  );
};

export { useModal } from './use-modal';
