import React, { useContext } from "react"
import PropTypes from "prop-types"
import cx from "classnames"
import { DialogOverlay, DialogContent } from "@reach/dialog"
import LoadingAnimation from "../loading-animation"
import IconButton from "../button/icon-button"
import { PortalNode } from "../portal"
import { motion, AnimatePresence } from "framer-motion"
import ConfirmModal from "./confirm-modal"
import confirm from "./confirm"
import Action, { ActionProvider, Actions, ActionContext } from "./action"
import TitleBar from "./title-bar"

const AnimatedDialogContent = motion.custom(DialogContent)

const DEFAULT = "p-0 my-auto bg-white font-sans rounded-lg shadow max-h-screen"
const HEADER_DEFAULT = "flex items-center justify-between px-6"

const SIZE_CLASSES = {
  md: "max-w-2xl w-4/5",
  lg: "max-w-4xl w-4/5",
  full: "max-w-full w-4/5",
  fullscreen: "w-screen h-screen",
}

const SIZE_STYLES = {
  md: {},
  lg: {},
  full: {
    maxWidth: "1600px",
    width: "calc(100vw - 4rem)",
    margin: "4rem auto 4rem auto",
  },
  fullscreen: {
    margin: 0
  },
}

function Header({ children, className, separator }) {
  const { actions } = useContext(ActionContext)

  const classes = cx(HEADER_DEFAULT, className, {
    "border-b border-gray-200 py-5": actions.length > 0 || separator,
    "pt-6 pb-2": actions.length === 0 && !separator,
  })

  return <div className={classes}>{children}</div>
}

function Modal({
  children,
  label,
  ariaLabel,
  onClose,
  className,
  size = "md",
  loading = false,
  width,
  hideCloseButton = false,
  hideHeader = false,
  separator,
  ...props
}) {
  return (
    <ActionProvider>
      <DialogOverlay
        onDismiss={onClose}
        className={
          ["full", "fullscreen"].includes(size) ? "" : "flex justify-center items-center pt-8"
        }
        {...props}
      >
        <AnimatePresence>
          <AnimatedDialogContent
            key="modal-content"
            aria-label={ariaLabel || label}
            className={cx(className, DEFAULT, SIZE_CLASSES[size])}
            style={{ ...SIZE_STYLES[size], maxWidth: width }}
            initial={{ opacity: 0, y: size === "full" ? 15 : -15 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0 }}
          >
            {!hideHeader && (
              <Header className="gap-8" separator={separator}>
                {label ? <TitleBar content={label} /> : <div />}
                {!hideCloseButton && (
                  <IconButton
                    icon="close"
                    is="tertiary"
                    className="focus:outline-none hover:bg-gray-50"
                    label="Close"
                    onClick={onClose}
                  />
                )}
              </Header>
            )}
            {loading ? (
              <div className="flex justify-center">
                <LoadingAnimation />
              </div>
            ) : (
              <div className="bg-white rounded-b-lg">
                <PortalNode className="p-6 bg-white rounded-b-lg">
                  {children}
                </PortalNode>
                <Actions />
              </div>
            )}
          </AnimatedDialogContent>
        </AnimatePresence>
      </DialogOverlay>
    </ActionProvider>
  )
}

Modal.propTypes = {
  children: PropTypes.node,
  className: PropTypes.string,
  /** Typically a string, but you can use JSX for more customizability. */
  label: PropTypes.node,
  /** A label that describes the modal on screen readers. Add this if you don't provide a label, or if you provide a JSX label. */
  ariaLabel: PropTypes.string,
  onClose: PropTypes.func.isRequired,
  loading: PropTypes.bool,
  width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  /** You don't need to provide this if you set a `width`. */
  size: PropTypes.oneOf(["md", "lg", "full", "fullscreen", "custom"]),
  hideCloseButton: PropTypes.bool,
  /** Hides the header */
  hideHeader: PropTypes.bool,
  /** forces the separator under the title even when there are no Actions */
  separator: PropTypes.bool
}

export { Action, ConfirmModal, confirm }
export default Modal
