import _defineProperty from "@babel/runtime-corejs3/helpers/defineProperty";
import _extends from "@babel/runtime-corejs3/helpers/extends";
import _slicedToArray from "@babel/runtime-corejs3/helpers/slicedToArray";
import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat";
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
import _Promise from "@babel/runtime-corejs3/core-js-stable/promise";
import React, { useEffect, useState, useCallback, useRef, cloneElement } from 'react';
import ReactDOM from 'react-dom';
import { tuple } from '../_utils/type';
import debounce from 'lodash/debounce';
import classNames from 'classnames';
import devWarning from '../_utils/devwarning';
import { useResizeObserver } from '../_utils/hooks';
export var Placements = tuple('top', 'left', 'right', 'bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight', 'leftTop', 'leftBottom', 'rightTop', 'rightBottom');
export var Triggers = tuple('hover', 'focus', 'click', 'contextMenu');
var _getOffsetPos = function getOffsetPos(el) {
  var elPos = {
    top: el.offsetTop,
    left: el.offsetLeft
  };
  if (el.offsetParent) {
    var parentPos = _getOffsetPos(el.offsetParent);
    elPos.top += parentPos.top;
    elPos.left += parentPos.left;
  }
  return elPos;
};
var _getScrollDist = function getScrollDist(el) {
  var elScroll = {
    top: el.scrollTop,
    left: el.scrollLeft
  };
  if (el.parentElement && el.parentElement !== document.body) {
    var parentScroll = _getScrollDist(el.parentElement);
    elScroll.top += parentScroll.top;
    elScroll.left += parentScroll.left;
  }
  return elScroll;
};
function usePopper(locatorElement, popperElement, props) {
  var _context, _context2;
  var prefixCls = props.prefixCls,
    onTrigger = props.onTrigger,
    popperStyle = props.popperStyle,
    _props$arrow = props.arrow,
    arrow = _props$arrow === void 0 ? false : _props$arrow,
    onVisibleChange = props.onVisibleChange,
    popperClassName = props.popperClassName,
    _props$arrowOffset = props.arrowOffset,
    arrowOffset = _props$arrowOffset === void 0 ? 12 : _props$arrowOffset,
    _props$arrowSize = props.arrowSize,
    arrowSize = _props$arrowSize === void 0 ? 4.25 : _props$arrowSize,
    locatorClassName = props.locatorClassName,
    _props$disabled = props.disabled,
    disabled = _props$disabled === void 0 ? false : _props$disabled,
    _props$trigger = props.trigger,
    trigger = _props$trigger === void 0 ? 'click' : _props$trigger,
    _props$placement = props.placement,
    placement = _props$placement === void 0 ? 'top' : _props$placement,
    _props$gap = props.gap,
    defalutGap = _props$gap === void 0 ? 4 : _props$gap,
    _props$scrollHidden = props.scrollHidden,
    scrollHidden = _props$scrollHidden === void 0 ? false : _props$scrollHidden,
    _props$mouseEnterDela = props.mouseEnterDelay,
    mouseEnterDelay = _props$mouseEnterDela === void 0 ? 0.1 : _props$mouseEnterDela,
    _props$mouseLeaveDela = props.mouseLeaveDelay,
    mouseLeaveDelay = _props$mouseLeaveDela === void 0 ? 0.1 : _props$mouseLeaveDela,
    _props$defaultVisible = props.defaultVisible,
    defaultVisible = _props$defaultVisible === void 0 ? false : _props$defaultVisible,
    _props$getTriggerElem = props.getTriggerElement,
    getTriggerElement = _props$getTriggerElem === void 0 ? function (locatorNode) {
      return locatorNode;
    } : _props$getTriggerElem,
    _props$getPopupContai = props.getPopupContainer,
    getPopupContainer = _props$getPopupContai === void 0 ? function () {
      return document.body;
    } : _props$getPopupContai;
  var arrowWidth = Math.sqrt(2 * Math.pow(arrowSize, 2));
  var componentName = (prefixCls === null || prefixCls === void 0 ? void 0 : prefixCls.split('-')[1]) || '';
  devWarning(Placements.indexOf(placement) === -1, componentName, _concatInstanceProperty(_context = "cannot found ".concat(componentName, " placement '")).call(_context, placement, "'"));
  var isWrongTrigger = Array.isArray(trigger) ? trigger.some(function (v) {
    return !_includesInstanceProperty(Triggers).call(Triggers, v);
  }) : Triggers.indexOf(trigger) === -1;
  devWarning(isWrongTrigger, componentName, _concatInstanceProperty(_context2 = "cannot found ".concat(componentName, " trigger '")).call(_context2, trigger, "'"));
  var locatorEl = useRef();
  var popperEl = useRef();
  var locatorRef = locatorElement.ref || locatorEl;
  var popperRef = popperElement.ref || popperEl;
  var container = getPopupContainer(locatorRef.current);
  _Promise.resolve().then(function () {
    var triggerNode = getTriggerElement(locatorRef.current);
    var container = getPopupContainer(locatorRef.current);
    devWarning(!triggerNode, componentName, 'getTriggerElement() must return a HTMLElement, but now it does not return anything');
    devWarning(!container, componentName, 'getPopupContainer() must return a HTMLElement, but now it does not return anything');
  });
  var initPos = {
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    x: 0,
    y: 0,
    height: 0,
    width: 0
  };
  var initAlign = {
    top: 0,
    left: 0
  };
  var gap = defalutGap + (arrow ? 10 : 0);
  var _useState = useState(initPos),
    _useState2 = _slicedToArray(_useState, 2),
    mousePos = _useState2[0],
    setMousePos = _useState2[1];
  var _useState3 = useState(initAlign),
    _useState4 = _slicedToArray(_useState3, 2),
    arrowPos = _useState4[0],
    setArrowPos = _useState4[1];
  var _useState5 = useState(!!props.visible || defaultVisible),
    _useState6 = _slicedToArray(_useState5, 2),
    exist = _useState6[0],
    setExist = _useState6[1];
  var _useState7 = useState(false),
    _useState8 = _slicedToArray(_useState7, 2),
    visible = _useState8[0],
    setVisible = _useState8[1];
  useEffect(function () {
    setVisible(!!props.visible);
  }, [props.visible]);
  var _useState9 = useState(''),
    _useState0 = _slicedToArray(_useState9, 2),
    evType = _useState0[0],
    setEvType = _useState0[1];
  var _useState1 = useState(!!props.visible || defaultVisible),
    _useState10 = _slicedToArray(_useState1, 2),
    canAlign = _useState10[0],
    setCanAlign = _useState10[1];
  var _useState11 = useState(initAlign),
    _useState12 = _slicedToArray(_useState11, 2),
    align = _useState12[0],
    setAlign = _useState12[1];
  var _useState13 = useState(placement),
    _useState14 = _slicedToArray(_useState13, 2),
    currentPlacement = _useState14[0],
    setCurrentPlacement = _useState14[1];
  var alignPopper = useCallback(function () {
    if ((locatorRef === null || locatorRef === void 0 ? void 0 : locatorRef.current) && (popperRef === null || popperRef === void 0 ? void 0 : popperRef.current) && evType) {
      var _popperRef$current$ge = popperRef.current.getBoundingClientRect(),
        popperWidth = _popperRef$current$ge.width,
        popperHeight = _popperRef$current$ge.height;
      var _locatorRef$current$g = locatorRef.current.getBoundingClientRect(),
        top = _locatorRef$current$g.top,
        bottom = _locatorRef$current$g.bottom,
        left = _locatorRef$current$g.left,
        right = _locatorRef$current$g.right,
        height = _locatorRef$current$g.height,
        width = _locatorRef$current$g.width;
      var _getOffsetPos2 = _getOffsetPos(container),
        containerTop = _getOffsetPos2.top,
        containerLeft = _getOffsetPos2.left;
      var _getOffsetPos3 = _getOffsetPos(locatorRef.current),
        locatorTop = _getOffsetPos3.top,
        locatorLeft = _getOffsetPos3.left;
      var _getScrollDist2 = _getScrollDist(locatorRef.current),
        scrollTop = _getScrollDist2.top,
        scrollLeft = _getScrollDist2.left;
      var locatorPos = {
        width: width,
        height: height,
        y: locatorTop - containerTop - scrollTop,
        x: locatorLeft - containerLeft - scrollLeft,
        top: locatorTop - containerTop - scrollTop,
        left: locatorLeft - containerLeft - scrollLeft,
        right: locatorLeft + width - containerLeft - scrollLeft,
        bottom: locatorTop + height - containerTop - scrollTop
      };
      var currentPos = evType === 'contextmenu' ? mousePos : locatorPos;
      var _currentPlacement = placement;
      if (top - gap - popperHeight < 0) {
        _currentPlacement = _currentPlacement.replace('top', 'bottom');
      }
      if (bottom + gap + popperHeight > document.body.clientHeight) {
        _currentPlacement = _currentPlacement.replace('bottom', 'top');
      }
      if (left + popperWidth > document.body.clientWidth) {
        _currentPlacement = _currentPlacement.replace('Left', 'Right');
      }
      if (right - popperWidth < 0) {
        _currentPlacement = _currentPlacement.replace('Right', 'Left');
      }
      if (top + popperHeight > document.body.clientHeight) {
        _currentPlacement = _currentPlacement.replace('Top', 'Bottom');
      }
      if (bottom - popperHeight < 0) {
        _currentPlacement = _currentPlacement.replace('Bottom', 'Top');
      }
      if (left - gap - popperWidth < 0) {
        _currentPlacement = _currentPlacement.replace('left', 'right');
      }
      if (right + gap + popperWidth > document.body.clientWidth) {
        _currentPlacement = _currentPlacement.replace('right', 'left');
      }
      var leftLeft = currentPos.left - popperWidth - gap;
      var topTop = currentPos.top - gap - popperHeight;
      var bottomTop = currentPos.top + currentPos.height + gap;
      var rightLeft = currentPos.left + currentPos.width - popperWidth;
      var centerLeft = currentPos.left + (currentPos.width - popperWidth) / 2;
      var centerTop = currentPos.top - (popperHeight - currentPos.height) / 2;
      var topBottom = currentPos.bottom - popperHeight;
      var leftRight = currentPos.right + gap;
      var mapAlign = {
        topLeft: {
          left: currentPos.left,
          top: topTop
        },
        top: {
          left: centerLeft,
          top: topTop
        },
        topRight: {
          left: rightLeft,
          top: topTop
        },
        bottomLeft: {
          left: currentPos.left,
          top: bottomTop
        },
        bottom: {
          left: centerLeft,
          top: bottomTop
        },
        bottomRight: {
          left: rightLeft,
          top: bottomTop
        },
        leftTop: {
          left: leftLeft,
          top: currentPos.top
        },
        left: {
          left: leftLeft,
          top: centerTop
        },
        leftBottom: {
          left: leftLeft,
          top: topBottom
        },
        rightTop: {
          left: leftRight,
          top: currentPos.top
        },
        right: {
          left: leftRight,
          top: centerTop
        },
        rightBottom: {
          left: leftRight,
          top: topBottom
        }
      };
      var alignPos = mapAlign[_currentPlacement];
      var _arrowPos = {
        top: 0,
        left: 0
      };
      if (/left/.test(_currentPlacement) || /right/.test(_currentPlacement)) {
        if (/Top/.test(_currentPlacement)) {
          _arrowPos.top = arrowOffset;
        } else if (/Bottom/.test(_currentPlacement)) {
          _arrowPos.top = popperHeight - arrowOffset - 2 * arrowSize;
        } else {
          _arrowPos.top = (popperHeight - arrowWidth) / 2;
        }
        if (top <= 0) {
          alignPos.top = locatorPos.top;
          _arrowPos.top = arrowOffset;
        } else if (bottom - height / 4 >= document.body.clientHeight) {
          alignPos.top = locatorPos.bottom - popperHeight;
          _arrowPos.top = popperHeight - arrowOffset - 2 * arrowSize;
        } else {
          var _scrollTop = alignPos.top - window.pageYOffset;
          var scrollBottom = alignPos.top + popperHeight - 5 - window.pageYOffset;
          if (_scrollTop < 0) {
            alignPos.top -= _scrollTop;
            _arrowPos.top += _scrollTop;
          }
          if (scrollBottom > document.body.clientHeight) {
            alignPos.top += document.body.clientHeight - scrollBottom;
            _arrowPos.top += scrollBottom - document.body.clientHeight;
          }
        }
      }
      if (/top/.test(_currentPlacement) || /bottom/.test(_currentPlacement)) {
        if (/Left/.test(_currentPlacement)) {
          _arrowPos.left = arrowOffset;
        } else if (/Right/.test(_currentPlacement)) {
          _arrowPos.left = popperWidth - arrowOffset - 2 * arrowSize;
        } else {
          _arrowPos.left = (popperWidth - arrowWidth) / 2;
        }
      }
      setAlign(alignPos);
      setArrowPos(_arrowPos);
      setCurrentPlacement(_currentPlacement);
    }
  }, [locatorRef, popperRef, container, evType, mousePos, placement, gap, arrowOffset, arrowSize, arrowWidth]);
  useEffect(function () {
    if (canAlign) {
      alignPopper();
      setCanAlign(false);
      props.visible === undefined && setVisible(true);
      onVisibleChange && onVisibleChange(true);
    }
  }, [alignPopper, canAlign, onVisibleChange, props]);
  var arrowStyle = {
    '--arrowSize': arrowSize + 'px',
    '--arrowTop': arrowPos.top + 'px',
    '--arrowLeft': arrowPos.left + 'px',
    '--arrowOffset': arrowSize / -1.2 + 'px'
  };
  var popperContainerStyle = _extends(_extends(_extends({
    position: 'absolute'
  }, popperStyle), align), arrow ? arrowStyle : {});
  var locatorProps = {
    disabled: disabled,
    ref: locatorRef,
    style: locatorElement.props.style,
    className: classNames(locatorClassName, locatorElement.props.className)
  };
  var popperProps = {
    ref: popperRef,
    style: popperContainerStyle,
    className: classNames(prefixCls, popperClassName, currentPlacement, _defineProperty({
      arrow: arrow,
      hidden: !visible
    }, "".concat(currentPlacement, "-active"), visible))
  };
  var popperNode = popperRef.current;
  var locatorNode = locatorRef.current;
  useResizeObserver(popperNode, alignPopper);
  useResizeObserver(locatorNode, alignPopper);
  useEffect(function () {
    if (exist && visible) {
      var mouseleaveTimer;
      var handleHidePopper = function handleHidePopper(e) {
        mouseleaveTimer && clearTimeout(mouseleaveTimer);
        var triggerNode = getTriggerElement(locatorRef.current);
        var triggerRect = triggerNode.getBoundingClientRect();
        var popperRect = popperRef.current.getBoundingClientRect();
        var left = /left/.test(currentPlacement) ? popperRect.right : triggerRect.left;
        var right = /right/.test(currentPlacement) ? popperRect.left : triggerRect.right;
        var top = /top/.test(currentPlacement) ? popperRect.bottom : triggerRect.top;
        var bottom = /bottom/.test(currentPlacement) ? popperRect.top : triggerRect.bottom;
        var X = e.clientX,
          Y = e.clientY;
        var inTriggerRect = X > left - 2 && X < right + 2 && Y > top - 2 && Y < bottom + 2;
        var inPopperRect = X > popperRect.left && X < popperRect.right && Y > popperRect.top && Y < popperRect.bottom;
        var ableArea = evType === 'click' || evType === 'contextmenu' ? inPopperRect : inTriggerRect || inPopperRect;
        var hidePopper = function hidePopper() {
          setEvType('');
          props.visible === undefined && setVisible(false);
          onVisibleChange && onVisibleChange(false);
        };
        if (ableArea) {
          evType === 'focus' && triggerNode.focus();
        } else {
          evType === 'mouseenter' ? mouseleaveTimer = window.setTimeout(hidePopper, mouseLeaveDelay * 1000) : hidePopper();
        }
      };
      var debounceHidePopper = debounce(handleHidePopper, 10);
      if (evType === 'mouseenter') {
        document.addEventListener('mousemove', debounceHidePopper);
      } else {
        document.addEventListener('click', handleHidePopper);
      }
      return function () {
        if (evType === 'mouseenter') {
          document.removeEventListener('mousemove', debounceHidePopper);
        } else {
          document.removeEventListener('click', handleHidePopper);
        }
      };
    }
  }, [props, exist, evType, trigger, visible, popperRef, locatorRef, mouseLeaveDelay, onVisibleChange, currentPlacement, getTriggerElement]);
  useEffect(function () {
    if (visible) {
      var scrollAlign = debounce(function () {
        if (scrollHidden) {
          props.visible === undefined && setVisible(false);
          onVisibleChange && onVisibleChange(false);
        }
        alignPopper();
      }, 10);
      window.addEventListener('resize', alignPopper);
      document.addEventListener('scroll', scrollAlign, true);
      locatorNode === null || locatorNode === void 0 ? void 0 : locatorNode.addEventListener('DOMSubtreeModified', alignPopper);
      exist && (popperNode === null || popperNode === void 0 ? void 0 : popperNode.addEventListener('DOMSubtreeModified', alignPopper));
      return function () {
        window.removeEventListener('resize', alignPopper);
        document.removeEventListener('scroll', scrollAlign, true);
        locatorNode === null || locatorNode === void 0 ? void 0 : locatorNode.removeEventListener('DOMSubtreeModified', alignPopper);
        exist && (popperNode === null || popperNode === void 0 ? void 0 : popperNode.removeEventListener('DOMSubtreeModified', alignPopper));
      };
    }
  }, [alignPopper, exist, onVisibleChange, popperNode, props.visible, scrollHidden, locatorNode, visible]);
  React.useEffect(function () {
    var triggerNode = getTriggerElement(locatorRef.current);
    if (triggerNode) {
      var mouseenterTimer;
      var clearMouseLeave = function clearMouseLeave() {
        return clearTimeout(mouseenterTimer);
      };
      var addAction = function addAction(action) {
        if (action === 'hover') {
          triggerNode.addEventListener('mouseenter', handleShowPopper);
          triggerNode.addEventListener('mouseleave', clearMouseLeave);
        } else {
          triggerNode.addEventListener(action.toLowerCase(), handleShowPopper);
        }
      };
      var removeAction = function removeAction(action) {
        if (action === 'hover') {
          triggerNode.removeEventListener('mouseenter', handleShowPopper);
          triggerNode.removeEventListener('mouseleave', clearMouseLeave);
        } else {
          triggerNode.removeEventListener(action.toLowerCase(), handleShowPopper);
        }
      };
      var handleShowPopper = function handleShowPopper(e) {
        e.preventDefault();
        var evType = e.type;
        if (evType === 'contextmenu') {
          var currentMousePos = _extends(_extends({}, mousePos), {
            x: e.pageX,
            y: e.pageY,
            left: e.pageX,
            top: e.pageY,
            right: e.pageX,
            bottom: e.pageY
          });
          setMousePos(currentMousePos);
        }
        var showPopper = function showPopper(evType) {
          if (!disabled) {
            !exist && setExist(true);
            setEvType(evType);
            if (onTrigger) {
              var mapTrigger = {
                mouseenter: 'hover',
                click: 'click',
                focus: 'focus',
                contextmenu: 'contextMenu'
              };
              onTrigger(mapTrigger[evType]);
            }
            if (!visible || evType === 'contextmenu') {
              setCanAlign(true);
            }
          }
        };
        if (evType === 'mouseenter') {
          mouseenterTimer = window.setTimeout(function () {
            return showPopper(evType);
          }, mouseEnterDelay * 1000);
        } else {
          showPopper(evType);
        }
      };
      Array.isArray(trigger) ? trigger.forEach(function (action) {
        return addAction(action);
      }) : addAction(trigger);
      return function () {
        Array.isArray(trigger) ? trigger.forEach(function (action) {
          return removeAction(action);
        }) : removeAction(trigger);
      };
    }
  }, [disabled, exist, getTriggerElement, locatorRef, mouseEnterDelay, mousePos, onTrigger, trigger, visible]);
  var Locate = /*#__PURE__*/cloneElement(locatorElement, locatorProps);
  var Popper = /*#__PURE__*/React.createElement("div", _extends({}, popperProps), popperElement);
  return /*#__PURE__*/React.createElement(React.Fragment, null, Locate, exist && container && /*#__PURE__*/ReactDOM.createPortal(Popper, container));
}
export default usePopper;