import { createVNode as _createVNode, isVNode as _isVNode } from "vue";
// @ts-nocheck
import { defineComponent, Teleport, reactive, ref, watch, getCurrentInstance, inject, onMounted, onUpdated, onUnmounted, cloneVNode, computed, mergeProps } from "vue";
import { getComponent, filterEmpty, getSlot, findDOMNode, isValidElement, noop } from '../_util/props-util';
import addEventListener from '../_util/Dom/addEventListener';
import { requestAnimationTimeout, cancelAnimationTimeout } from '../_util/requestAnimationTimeout';
import Popup from './Popup';
import placements from "../tooltip/placements";

function _isSlot(s) {
  return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !_isVNode(s);
}

export default defineComponent({
  name: 'Trigger',
  inheritAttrs: false,
  props: {
    prefixCls: String,
    action: {
      type: String,
      default: ''
    },
    disabled: Boolean,
    // mask
    mask: Boolean,
    maskClosable: {
      type: Boolean,
      default: true
    },
    maskTransitionName: String,
    // popup
    popup: [String, Number, Object, Array],
    popupVisible: Boolean,
    popupTransitionName: {
      default: 'zoom-ani'
    },
    popupStyle: [Array, Object, String],
    popupClass: [Array, Object, String],
    popupAlign: Object,
    popupPlacement: {
      type: String
    },
    builtinPlacements: {
      type: Object,
      default: placements
    },
    popupAnimation: Object,
    onPopupVisibleChange: Function,
    afterPopupVisibleChange: Function,
    getPopupContainer: Function,
    getDocument: {
      type: Function,
      default: () => window.document
    },
    zIndex: String || Number,
    // target
    mouseEnterDelay: {
      default: 0
    },
    mouseLeaveDelay: {
      default: 150
    },
    focusDelay: {
      default: 0
    },
    blurDelay: {
      default: 0
    },
    // align
    alignPoint: Boolean
  },

  setup(props, {
    emit,
    attrs,
    slots
  }) {
    const savePopupRef = inject('savePopupRef', () => {});
    const popupRef = ref(),
          triggerRef = ref();
    const {
      proxy: vm
    } = getCurrentInstance();
    const alignRef = computed(() => {
      var _props$builtinPlaceme;

      return { ...((_props$builtinPlaceme = props.builtinPlacements) === null || _props$builtinPlaceme === void 0 ? void 0 : _props$builtinPlaceme[props.popupPlacement]),
        ...props.popupAlign
      };
    });
    const state = reactive({
      popupVisible: props.popupVisible,
      point: null
    });
    watch(() => props.popupVisible, v => {
      state.popupVisible = v;
    });
    onMounted(() => {
      addOutsideHandler();
    });
    onUpdated(() => {
      addOutsideHandler();
    });
    onUnmounted(() => {
      clearDelayTimer();
      clearOutsideHandler();
    });

    function setPopupVisible(v, event) {
      if (props.disabled) return;

      if (state.popupVisible != v) {
        state.popupVisible = v;
        emit('popupVisibleChange', v);
      }

      setPoint(event);
    }

    function setPoint(point) {
      if (!props.alignPoint || !point) return;
      state.point = {
        pageX: point.pageX,
        pageY: point.pageY
      };
    }

    let delayTimer;

    function delaySetPopupVisible(visible, delay, event) {
      clearDelayTimer();

      if (delay) {
        delayTimer = requestAnimationTimeout(() => {
          setPopupVisible(visible, event);
          clearDelayTimer();
        }, delay);
      } else {
        setPopupVisible(visible, event);
      }
    }

    function clearDelayTimer() {
      if (delayTimer) {
        cancelAnimationTimeout(delayTimer);
        delayTimer = null;
      }
    }

    function close() {
      setPopupVisible(false);
    }

    let clickOutsideHandler, ctxmOutsideHandler;

    function addOutsideHandler() {
      if (state.popupVisible) {
        const document = props.getDocument();

        if (!clickOutsideHandler && props.action.includes('click')) {
          clickOutsideHandler = addEventListener(document, 'mousedown', onDocumentClick);
        }

        if (!ctxmOutsideHandler && props.action.includes('contextmenu')) {
          clickOutsideHandler = addEventListener(document, 'mousedown', onDocumentClick);
        }
      } else {
        clearOutsideHandler();
      }
    }

    function clearOutsideHandler() {
      var _clickOutsideHandler, _ctxmOutsideHandler;

      (_clickOutsideHandler = clickOutsideHandler) === null || _clickOutsideHandler === void 0 ? void 0 : _clickOutsideHandler.remove();
      clickOutsideHandler = null;
      (_ctxmOutsideHandler = ctxmOutsideHandler) === null || _ctxmOutsideHandler === void 0 ? void 0 : _ctxmOutsideHandler.remove();
      ctxmOutsideHandler = null;
    } // click popup outside


    function onDocumentClick(event) {
      if (popupMousedowned) return;
      if (props.mask && !props.maskClosable) return;
      const root = findDOMNode(vm);

      if (!root.contains(event.target)) {
        close();
      }
    }

    let popupMousedowned = false;

    function savePopup(v) {
      popupRef.value = v;
      savePopupRef(v);
    }

    function getPopupComponent() {
      let _slot;

      const mouseProps = {};

      if (props.action.includes('hover')) {
        mouseProps.onMouseenter = clearDelayTimer;
        mouseProps.onMouseleave = onPopupMouseleave;
      }

      mouseProps.onMousedown = onPopupMousedown;
      mouseProps.onMouseup = onPopupMouseup;
      const {
        prefixCls,
        popupPlacement
      } = props;
      let placementCls = popupPlacement ? `${prefixCls}-placement-${popupPlacement}` : '';
      const popupPorps = {
        prefixCls,
        visible: state.popupVisible && !props.disabled,
        point: props.alignPoint ? state.point : null,
        action: props.action,
        align: alignRef.value,
        getRootDomNode,
        mask: props.mask,
        maskTransitionName: props.maskTransitionName,
        // getContainer,
        popupStyle: props.popupStyle,
        popupClass: [props.popupClass, placementCls],
        transitionName: props.popupTransitionName,
        animation: props.popupAnimation,
        onAlign: attrs.onPopupAlign || noop,
        zIndex: props.zIndex,
        ref: savePopup,
        ...mouseProps
      };
      return _createVNode(Popup, popupPorps, _isSlot(_slot = getComponent(vm, 'popup')) ? _slot : {
        default: () => [_slot]
      });
    }

    function getPopupContainer() {
      const mountDom = props.getPopupContainer ? props.getPopupContainer(findDOMNode(vm)) : props.getDocument().body;
      return mountDom;
    } // ========================== Event ==========================


    let focused = false;

    function onClick(e) {
      setPopupVisible(!state.popupVisible, e);
    }

    function onClickHide() {
      setPopupVisible(false);
    }

    function onContextmenu(e) {
      e.preventDefault();
      setPopupVisible(true, e);
    }

    function onMouseenter(e) {
      delaySetPopupVisible(true, props.mouseEnterDelay, e);
    }

    function onFocus(e) {
      focused = true;
      delaySetPopupVisible(true, props.focusDelay, e);
    }

    function onBlur(e) {
      focused = false;
      delaySetPopupVisible(false, props.blurDelay, e);
    } // ===================== Popup Event ==========================


    function onPopupMouseleave(e) {
      if (props.action.includes('focus') && focused) return;
      delaySetPopupVisible(false, props.mouseLeaveDelay, e);
    }

    function onPopupMousedown() {
      popupMousedowned = true;
    }

    function onPopupMouseup() {
      popupMousedowned = false;
    }

    function getRootDomNode() {
      return findDOMNode(triggerRef.value);
    }

    return vm => {
      let _slot2;

      let child = filterEmpty(getSlot(vm))[0];
      child = isValidElement(child) ? child : _createVNode("span", null, [child]);
      const newProps = {
        ref: triggerRef
      };

      if (props.action.includes('click')) {
        newProps.onClick = onClick;
      }

      if (props.action.includes('contextmenu')) {
        newProps.onContextmenu = onContextmenu;
        newProps.onClick = onClickHide;
      }

      if (props.action.includes('hover')) {
        newProps.onMouseenter = onMouseenter;
        newProps.onMouseleave = onPopupMouseleave;
      }

      if (props.action.includes('focus')) {
        newProps.onFocus = onFocus;
        newProps.onBlur = onBlur;
      }

      const trigger = cloneVNode(child, mergeProps(newProps, attrs), true);
      const teleport = triggerRef.value ? _createVNode(Teleport, {
        "to": getPopupContainer()
      }, _isSlot(_slot2 = getPopupComponent()) ? _slot2 : {
        default: () => [_slot2]
      }) : undefined;
      return [teleport, trigger];
    };
  }

});