<template>
  <span
    class="mm-tooltip">
    <span
      ref="reference"
      class="mm-tooltip-trigger"
      v-on="popperListeners">
      <slot></slot>
    </span>
    <ui-popper
      v-if="!disabled"
      ref="popper"
      :visible.sync="localVisible"
      v-bind="popperProps"
      target="reference"
      class="mm-tooltip-popper"
      @after-enter="$emit('after-enter')"
      @after-leave="$emit('after-leave')">
      <slot name="content">
        {{ content }}
      </slot>
    </ui-popper>
  </span>
</template>

<script>
import omit from "lodash/omit"
import visible from "../../mixins/visible"
import Popper from "../popper"
import pick from "lodash/pick"
import xor from "lodash/xor"
import isString from "lodash/isString"
import isObject from "lodash/isObject"
import config from "../../managers/config"

config.defaults({
  "Tooltip.visibleArrow": true,
  "Tooltip.transition": "fade-in-linear",
  "Tooltip.mouseEnterDelay": 100,
  "Tooltip.trackRefWidth": false,
  "Tooltip.placement": "top",
})

// omit passed props(<popper :visible.sync ...>)
const otherPopperProps = omit(Popper.props, ["target", "visible", "popperStyle", "trigger"])

export default {
  name: "mm-tooltip",
  components: {
    "ui-popper": Popper,
  },
  mixins: [visible],
  props: {
    ...otherPopperProps,
    visibleArrow: {
      type: Boolean,
      default: () => config.get("Tooltip.visibleArrow"),
    },
    transition: {
      type: String,
      default: () => config.get("Tooltip.transition"),
    },
    content: {
      type: String,
      default: "",
    },
    trigger: {
      type: [String, Object],
      default: "hover",
      validator(val) {
        if (isString(val)) {
          return ["none", "hover", "click", "focus", "contextmenu"].includes(val)
        }

        if (isObject(val)) {
          return xor(Object.keys(val), ["target", "popper"]).length === 0
        }
        return false
      },
    },
    removeOnDestroy: {
      type: Boolean,
      default: true,
    },
    popperClass: {
      type: [String, Object, Array],
    },
    popperWidth: {
      type: String,
    },
    mouseEnterDelay: {
      type: Number,
      default: () => config.get("Tooltip.mouseEnterDelay"),
    },
    delay: {
      type: Number,
    },
    trackRefWidth: {
      type: Boolean,
      default: () => config.get("Tooltip.trackRefWidth"),
    },
    placement: {
      type: String,
      default: () => config.get("Tooltip.placement"),
    },
    popperStyle: {
      type: Object,
      default: () => ({}),
    },
  },
  computed: {
    realTrigger() {
      if (isString(this.trigger)) {
        return {
          target: this.trigger,
          popper: this.trigger,
        }
      }
      return this.trigger
    },
    popperListeners() {
      return this.genListeners(this.realTrigger.target)
    },
    popperProps() {
      return {
        ...pick(this.$props, Object.keys(otherPopperProps)),
        popperClass: this.popperClass,
        popperStyle: this.realPopperStyle,
        trigger: this.realTrigger.popper,
      }
    },
    realPopperStyle() {
      const style = {
        ...this.popperStyle,
      }
      if (this.popperWidth) {
        style.width = this.popperWidth
      }
      return style
    },
  },
  methods: {
    genListeners(trigger) {
      const events = {}
      switch (trigger) {
        case "hover":
          events.mouseenter = this.mouseEnterHandler
          events.mouseleave = this.mouseLeaveHandler
          break

        case "focus":
          events.focusin = this.show
          events.focusout = this.hide
          break

        case "contextmenu":
          events.contextmenu = this.show
          break

        case "click":
          events.click = this.toggle
          break
      }

      return events
    },
    mouseEnterHandler() {
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        this.show()
      }, this.mouseEnterDelay)
    },
    mouseLeaveHandler() {
      clearTimeout(this.timer)
      this.timer = null
    },
    update() {
      const popper = this.$refs.popper
      if (popper) {
        popper.update()
      }
    },
  },
}
</script>
