import React, { useState, useRef, useEffect } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Manager, Reference } from 'react-popper';
import { modifierCSS, usePopper } from '../../../helpers';

const propTypes = {
  children: PropTypes.node,
  className: PropTypes.string,
  color: PropTypes.oneOf(['', 'primary', 'secondary', 'success', 'warning', 'danger', 'light', 'dark', 'new']),
  defaultClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
  /**
   * Add a delay before closing the tooltip
   */
  hideDelay: PropTypes.bool,
  /**
   * The number of second before the closing of the tooltip when hideDelay is set to true
   */
  hideDelayCustomTimeOut: PropTypes.oneOf([
    0.05, 0.1, 0.2, 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
  ]),
  /**
   * Automatically display the tooltip on first render
   */
  autoDisplay: PropTypes.bool,
  /**
   * The number of seconds before closing the tooltip when autoDisplay is set to true
   */
  autoDisplayCustomTimeOut: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
  isLight: PropTypes.bool, /* deprecated 0.65 */
  isPortalDisabled: PropTypes.bool,
  label: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
  portalTarget: PropTypes.instanceOf(Element),
  defaultPlacement: PropTypes.oneOf(['auto', 'top', 'right', 'bottom', 'left']),
  size: PropTypes.oneOf(['', 'sm', 'md', 'lg']),
  tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
  wrapperTag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
};

const defaultProps = {
  children: '',
  className: '',
  color: '',
  defaultClassName: 'sui-a-tooltip',
  hideDelay: false,
  hideDelayCustomTimeOut: 2,
  autoDisplay: false,
  autoDisplayCustomTimeOut: 6,
  isLight: false,
  isPortalDisabled: false,
  label: '',
  portalTarget: document.body,
  defaultPlacement: 'auto',
  size: '',
  tag: 'div',
  wrapperTag: 'div',
};

export const Tooltip = ({
  children,
  className,
  color,
  defaultClassName,
  autoDisplay,
  autoDisplayCustomTimeOut,
  hideDelay,
  hideDelayCustomTimeOut,
  isLight,
  isPortalDisabled,
  label,
  portalTarget,
  defaultPlacement,
  size,
  tag: Tag,
  wrapperTag: WrapperTag,
  ...attributes
}) => {
  const [isOpen, setIsOpen] = useState(autoDisplay || false);
  const [isMouseOver, setIsMouseOver] = useState(false);

  const exitTimeoutRef = useRef();
  const autoDisplayTimeoutRef = useRef();

  const { mountPopperNode } = usePopper(defaultPlacement,
    { target: portalTarget, isDisabled: isPortalDisabled });

  useEffect(() => () => clearTimeout(exitTimeoutRef.current), []);

  useEffect(() => {
    if (!autoDisplay) {
      return () => {};
    }

    autoDisplayTimeoutRef.current = setTimeout(() => {
      // Don't hide the tooltip if mouse is over
      if (isMouseOver) {
        return;
      }

      setIsOpen(false);
    }, autoDisplayCustomTimeOut * 1000);

    return () => clearTimeout(autoDisplayTimeoutRef.current);
  },
  [autoDisplay, setIsOpen]);

  const handleClose = () => {
    if (hideDelay) {
      exitTimeoutRef.current = setTimeout(() => setIsOpen(false), hideDelayCustomTimeOut * 1000);
      return;
    }

    setIsOpen(false);
  };

  const wrappedChildren = React.isValidElement(children)
    ? children
    : <WrapperTag>{children}</WrapperTag>;

  const handleWrapperFocus = () => {
    clearTimeout(exitTimeoutRef.current);
    clearTimeout(autoDisplayTimeoutRef.current);
    setIsOpen(true);
  };

  const handleTooltipHover = () => {
    clearTimeout(exitTimeoutRef.current);
    clearTimeout(autoDisplayTimeoutRef.current);
    setIsMouseOver(true);
  };

  return (
    <Manager>
      <Reference>
        {({ ref }) => React.cloneElement(wrappedChildren, {
          ref,
          onMouseOver: handleWrapperFocus,
          onFocus: handleWrapperFocus,
          onMouseLeave: handleClose,
          onBlur: handleClose,
        })}
      </Reference>
      {isOpen && mountPopperNode(({ ref, style, placement }) => {
        const classes = classnames(
          className,
          defaultClassName,
          isLight ? 'as--light' : '',
          modifierCSS(color),
          modifierCSS(placement, 'placement')
        );

        const innerClasses = classnames(
          'sui-a-tooltip__inner',
          modifierCSS(size),
        );

        const onMouseEnterCallback = hideDelay ? handleTooltipHover : null;
        const onMouseLeaveCallback = hideDelay ? handleClose : null;

        return (
          <Tag
            {...attributes}
            className={classes}
            ref={ref}
            style={style}
            role="tooltip"
            onMouseEnter={onMouseEnterCallback}
            onFocus={onMouseEnterCallback}
            onMouseLeave={onMouseLeaveCallback}
            onBlur={onMouseLeaveCallback}
          >
            <div className="sui-a-tooltip__arrow" />
            <div className={innerClasses}>
              {label}
            </div>
          </Tag>
        );
      })}
    </Manager>
  );
};

Tooltip.propTypes = propTypes;
Tooltip.defaultProps = defaultProps;
