import React, { createContext, useContext, useEffect } from "react"
import PropTypes from "prop-types"
import {
  usePopoverState,
  Popover as BasePopover,
  PopoverDisclosure,
  PopoverArrow,
} from "reakit/Popover"
import Portal from "../portal"
import cx from "classnames"
import Button from "../button"
import usePrevious from "../../hooks/use-previous"

export function usePopover(...args) {
  return usePopoverState(...args)
}

function Popover({ label, arrow = true, popover: providedPopover, children }) {
  const internalPopover = usePopoverState()

  const popover = providedPopover || internalPopover

  return (
    <PopoverContext.Provider value={{ popover, label, arrow }}>
      {children}
    </PopoverContext.Provider>
  )
}

Popover.propTypes = {
  children: PropTypes.node,
  className: PropTypes.string,
  label: PropTypes.string.isRequired,
  popover: PropTypes.object,
  arrow: PropTypes.bool,
}

export default Popover

export function PopoverButton({ children, ...props }) {
  const { popover } = useContext(PopoverContext)

  return (
    <PopoverDisclosure {...popover}>
      {disclosureProps =>
        React.cloneElement(
          <Button {...props}>{children}</Button>,
          disclosureProps
        )
      }
    </PopoverDisclosure>
  )
}

export function PopoverContent({ children, onClose, overlayStyles = {}, ...props }) {
  const { label, arrow, popover } = useContext(PopoverContext)

  const className = cx(
    "border border-gray-200 rounded shadow bg-white outline-none",
    props.className
  )

  const previouslyOpen = usePrevious(popover.visible)

  useEffect(() => {
    if (previouslyOpen && !popover.visible && onClose) {
      onClose()
    }
  }, [previouslyOpen, popover.visible, onClose])

  return (
    <Portal>
      {popover.visible && <PopoverOverlay onClick={popover.hide} overlayStyles={overlayStyles} />}
      <div style={{ position: "relative" }}>
        <BasePopover
          {...props}
          {...popover}
          className={className}
          aria-label={label}
          hideOnClickOutside={false}
        >
          {arrow && <PopoverArrow className="popover-arrow" {...popover} />}
          {children}
        </BasePopover>
      </div>
    </Portal>
  )
}

const PopoverContext = createContext({})

// PopoverOverlay is rendered so that clicking on it (outside the popover) will
// close the popover. reakit/Popover uses document event listeners, which can
// cause issues when clicking on our dropdown menus, because they technically
// render outside of the popover through portals.
function PopoverOverlay({overlayStyles, ...props}) {
  return (
    <div
      {...props}
      style={{
        position: "fixed",
        top: 0,
        right: 0,
        bottom: 0,
        left: 0,
        ...overlayStyles
      }}
    ></div>
  )
}
