<script lang="ts" setup>
import { nextTick } from 'vue';

import type { ContextMenuItem } from './types';
import MIcon from '#/components/icon/icon.vue';
import {
  contextMenuState,
  getSubmenuPosition,
  hideContextMenu,
  MENU_WIDTH,
  showSubmenu,
  submenuState,
} from './use-context-menu';

defineOptions({ name: 'GlobalContextMenu' });

function onItemEnter(item: ContextMenuItem, e: MouseEvent) {
  if (item.type === 'divider') {
    showSubmenu('', [], 0, 0);
    return;
  }
  if (!item.children?.length || item.disabled) {
    showSubmenu('', [], 0, 0);
    return;
  }

  const target = e.currentTarget as HTMLElement;
  const rect = target.getBoundingClientRect();
  const pos = getSubmenuPosition(rect, item.children.length);
  showSubmenu(item.key, item.children, pos.left, pos.top);
}

function handleClick(item: ContextMenuItem) {
  if (item.disabled || item.children?.length) {
    return;
  }
  const payload = contextMenuState.payload;
  hideContextMenu();
  void nextTick(() => {
    item.handler?.(payload);
  });
}

function handleSubmenuClick(item: ContextMenuItem) {
  if (item.disabled) {
    return;
  }
  const payload = contextMenuState.payload;
  hideContextMenu();
  void nextTick(() => {
    item.handler?.(payload);
  });
}
</script>

<template>
  <Teleport to="body">
    <div
      v-if="contextMenuState.visible"
      class="global-context-menu"
      :style="{ left: `${contextMenuState.x}px`, top: `${contextMenuState.y}px`, width: `${MENU_WIDTH}px` }"
      @contextmenu.prevent
    >
      <template v-for="item in contextMenuState.items" :key="item.key">
        <div v-if="item.type === 'divider'" class="context-menu-divider" />
        <div
          v-else
          class="context-menu-item"
          :class="{ disabled: item.disabled, 'has-children': !!item.children?.length }"
          @click.stop="handleClick(item)"
          @mouseenter="onItemEnter(item, $event)"
        >
          <span class="item-icon">
            <component :is="item.icon" v-if="item.icon" />
            <MIcon v-else-if="item.iconName" :icon="item.iconName" size="14" />
          </span>
          <span class="item-label">{{ item.label }}</span>
          <span v-if="item.children?.length" class="item-arrow">›</span>
        </div>
      </template>
    </div>

    <div
      v-if="contextMenuState.visible && submenuState.activeKey && submenuState.items.length"
      class="global-context-menu submenu"
      :style="{ left: `${submenuState.left}px`, top: `${submenuState.top}px`, width: `${MENU_WIDTH}px` }"
      @contextmenu.prevent
    >
      <div
        v-for="child in submenuState.items"
        :key="child.key"
        class="context-menu-item"
        :class="{ disabled: child.disabled }"
        @click.stop="handleSubmenuClick(child)"
      >
        <span class="item-icon">
          <component :is="child.icon" v-if="child.icon" />
          <MIcon v-else-if="child.iconName" :icon="child.iconName" size="14" />
        </span>
        <span class="item-label">{{ child.label }}</span>
      </div>
    </div>
  </Teleport>
</template>

<style scoped lang="scss">
.global-context-menu {
  position: fixed;
  z-index: 9999;
  padding: 4px 0;
  background: #fff;
  border: 1px solid #e5e6eb;
  border-radius: 8px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
}

.context-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 36px;
  padding: 0 12px;
  font-size: 13px;
  color: #1d2129;
  cursor: pointer;
  user-select: none;

  &:hover:not(.disabled) {
    background: #f2f7ff;
    color: #165dff;
  }

  &.disabled {
    color: #c9cdd4;
    cursor: not-allowed;
  }

  &.has-children {
    padding-right: 8px;
  }
}

.item-icon {
  display: inline-flex;
  width: 16px;
  height: 16px;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.item-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.item-arrow {
  color: #86909c;
  font-size: 14px;
}

.context-menu-divider {
  height: 1px;
  margin: 4px 8px;
  background: #e5e6eb;
}

.dark {
  .global-context-menu {
    background: #1f2937;
    border-color: #374151;
  }

  .context-menu-item {
    color: #e5e7eb;

    &:hover:not(.disabled) {
      background: #374151;
      color: #93c5fd;
    }
  }

  .context-menu-divider {
    background: #374151;
  }
}
</style>
