<script>
import keyBy from "lodash/keyBy"
import CollapseTransition from "../../utils/collapse-transition"
import menuMixin from "./menu-mixin"
import Popper from "../popper"
import Icon from "../icon"

export default {
  name: "mm-submenu",

  components: {
    "ui-collapse-transition": CollapseTransition,
    "ui-popper": Popper,
    "ui-icon": Icon,
  },

  mixins: [menuMixin],
  provide() {
    return {
      "mm-submenu": this,
    }
  },

  inject: {
    prevSubmenu: {
      from: "mm-submenu",
      default: null,
    },
  },

  props: {
    selectAble: Boolean,
    routeable: {
      type: Boolean,
      default: true,
    },
    route: [String, Object],
    index: {
      type: String,
      required: true,
    },
    showTimeout: {
      type: Number,
      default: 300,
    },
    hideTimeout: {
      type: Number,
      default: 300,
    },
    popperClass: String,
    disabled: Boolean,
    popperOptions: {
      type: [Object, Function],
      default: () => ({
        modifiers: {
          flip: {
            boundariesElement: "viewport",
          },
          preventOverflow: {
            boundariesElement: "viewport",
            escapeWithReference: false,
          },
        },
      }),
    },
  },

  data() {
    return {
      timeout: null,
      itemsArr: [],
      submenusArr: [],
      mouseInChild: false,
    }
  },
  computed: {
    items() {
      return keyBy(this.itemsArr, "index")
    },
    submenus() {
      return keyBy(this.submenusArr, "index")
    },
    selfActive() {
      return this.index === this.rootMenu.activeIndex
    },
    menuTransitionName() {
      return this.rootMenu.collapse ? "zoom-in-left" : "zoom-in-top"
    },
    opened() {
      return this.rootMenu.openedMenus.indexOf(this.index) > -1
    },
    active() {
      let isActive = false
      const submenus = this.submenus
      const items = this.items

      Object.keys(items).forEach(index => {
        if (items[index].active) {
          isActive = true
        }
      })

      Object.keys(submenus).forEach(index => {
        if (submenus[index].active) {
          isActive = true
        }
      })

      return isActive
    },
    hoverBackground() {
      return this.rootMenu.hoverBackground
    },
    backgroundColor() {
      return this.rootMenu.backgroundColor || ""
    },
    activeTextColor() {
      return this.rootMenu.activeTextColor || ""
    },
    textColor() {
      return this.rootMenu.textColor || ""
    },
    mode() {
      return this.rootMenu.mode
    },
    isMenuPopup() {
      return this.rootMenu.isMenuPopup
    },
    titleStyle() {
      if (this.mode !== "horizontal") {
        return {
          color: this.textColor,
        }
      }
      return {
        borderBottomColor: this.active
          ? this.rootMenu.activeTextColor
            ? this.activeTextColor
            : ""
          : "transparent",
        color: this.active ? this.activeTextColor : this.textColor,
      }
    },
    isFirstLevel() {
      let isFirstLevel = true
      let parent = this.$parent
      while (parent && parent !== this.rootMenu) {
        if (["mm-submenu", "mm-menu-item-group"].indexOf(parent.$options.name) > -1) {
          isFirstLevel = false
          break
        } else {
          parent = parent.$parent
        }
      }
      return isFirstLevel
    },
    currentPlacement() {
      return this.mode === "horizontal" && this.isFirstLevel ? "bottom-start" : "right-start"
    },
  },
  created() {
    this.parentMenu.addSubmenu(this)
    this.rootMenu.addSubmenu(this)
    this.$on("toggle-collapse", this.handleCollapseToggle)
    this.$on("mouse-enter-child", () => {
      this.mouseInChild = true
      clearTimeout(this.timeout)
    })
    this.$on("mouse-leave-child", () => {
      this.mouseInChild = false
      clearTimeout(this.timeout)
    })
  },

  beforeDestroy() {
    this.parentMenu.removeSubmenu(this)
    this.rootMenu.removeSubmenu(this)
  },
  methods: {
    handleCollapseToggle() {},
    addItem(item) {
      if (!this.itemsArr.includes(item)) {
        this.itemsArr.push(item)
      }
    },
    removeItem(item) {
      const index = this.itemsArr.indexOf(item)
      if (~index) {
        this.itemsArr.splice(index, 1)
      }
    },
    addSubmenu(item) {
      if (!this.submenusArr.includes(item)) {
        this.submenusArr.push(item)
      }
    },
    removeSubmenu(item) {
      const index = this.submenusArr.indexOf(item)
      if (~index) {
        this.submenusArr.splice(index, 1)
      }
    },
    handleClick() {
      const { rootMenu, disabled } = this
      if (
        (rootMenu.menuTrigger === "hover" && rootMenu.mode === "horizontal") ||
        (rootMenu.collapse && rootMenu.mode === "vertical") ||
        disabled
      ) {
        return
      }
      this.rootMenu.$emit("submenu-click", this)
    },
    handleMouseenter() {
      const { rootMenu, disabled } = this
      if (
        (rootMenu.menuTrigger === "click" && rootMenu.mode === "horizontal") ||
        (!rootMenu.collapse && rootMenu.mode === "vertical") ||
        disabled
      ) {
        return
      }

      if (this.prevSubmenu) {
        this.prevSubmenu.$emit("mouse-enter-child")
      }

      clearTimeout(this.timeout)
      this.timeout = setTimeout(() => {
        this.rootMenu.openMenu(this.index, this.indexPath)
      }, this.showTimeout)
    },
    handleMouseleave() {
      const { rootMenu } = this
      if (
        (rootMenu.menuTrigger === "click" && rootMenu.mode === "horizontal") ||
        (!rootMenu.collapse && rootMenu.mode === "vertical")
      ) {
        return
      }

      if (this.prevSubmenu) {
        this.prevSubmenu.$emit("mouse-leave-child")
      }

      clearTimeout(this.timeout)
      this.timeout = setTimeout(() => {
        !this.mouseInChild && this.rootMenu.closeMenu(this.index)
      }, this.hideTimeout)
    },
    handleTitleMouseenter() {
      if (this.mode === "horizontal" && !this.rootMenu.backgroundColor) {
        return
      }
      const title = this.$refs["submenu-title"]
      title && (title.style.backgroundColor = this.rootMenu.hoverBackground)
    },
    handleTitleMouseleave() {
      if (this.mode === "horizontal" && !this.rootMenu.backgroundColor) {
        return
      }
      const title = this.$refs["submenu-title"]
      title && (title.style.backgroundColor = this.rootMenu.backgroundColor || "")
    },
  },
  render(h) {
    const {
      active,
      selfActive,
      opened,
      paddingStyle,
      titleStyle,
      backgroundColor,
      rootMenu,
      menuTransitionName,
      mode,
      disabled,
      popperClass,
      $slots,
      isFirstLevel,
      currentPlacement,
      popperOptions,
    } = this

    const popupMenu = (
      <ui-popper
        trigger={this.rootMenu.menuTrigger}
        transition={menuTransitionName}
        visible={opened}
        placement={currentPlacement}
        target="reference"
        lazy-render={false}
        popperOptions={popperOptions}
        class={["mm-menu-popper", `mm-menu-popper-${currentPlacement}`]}
      >
        <div
          ref="menu"
          class={[`mm-menu--${mode}`, popperClass]}
          on-mouseenter={this.handleMouseenter}
          on-mouseleave={this.handleMouseleave}
          on-focus={this.handleMouseenter}
        >
          <ul
            role="menu"
            class={["mm-menu mm-menu--popup"]}
            style={{ backgroundColor: rootMenu.backgroundColor || "" }}
          >
            {$slots.default}
          </ul>
        </div>
      </ui-popper>
    )

    const inlineMenu = (
      <ui-collapse-transition>
        <ul
          role="menu"
          class="mm-menu mm-menu--inline"
          v-show={opened}
          style={{ backgroundColor: rootMenu.backgroundColor || "" }}
        >
          {$slots.default}
        </ul>
      </ui-collapse-transition>
    )

    const submenuTitleIcon =
      (rootMenu.mode === "horizontal" && isFirstLevel) ||
      (rootMenu.mode === "vertical" && !rootMenu.collapse)
        ? "chevrondown"
        : "chevronright"

    const MenuIcon = rootMenu.collapse ? (
      <span class="mm-menu-tooltip">
        <span class="mm-menu-icon">{$slots.icon}</span>
      </span>
    ) : (
      <span class="mm-menu-icon">{$slots.icon}</span>
    )

    return (
      <li
        ref="reference"
        class={{
          "mm-submenu": true,
          "mm-submenu--active": active,
          "mm-submenu--self-active": selfActive,
          "mm-submenu--opened": opened,
          "mm-submenu--disabled": disabled,
        }}
        role="menuitem"
        aria-haspopup="true"
        aria-expanded={opened}
        on-mouseenter={this.handleMouseenter}
        on-mouseleave={this.handleMouseleave}
        on-focus={this.handleMouseenter}
      >
        <div
          class="mm-submenu-title"
          ref="submenu-title"
          on-click={this.handleClick}
          on-mouseenter={this.handleTitleMouseenter}
          on-mouseleave={this.handleTitleMouseleave}
          style={[paddingStyle, titleStyle, { backgroundColor }]}
        >
          {$slots.icon && MenuIcon}
          {$slots.title && <span class="mm-menu-title">{$slots.title}</span>}

          <ui-icon class="mm-submenu-icon-arrow" name={submenuTitleIcon} size="12px" />
        </div>
        {this.isMenuPopup ? popupMenu : inlineMenu}
      </li>
    )
  },
}
</script>
