<script setup lang="ts">
export interface ContextMenuItem {
  key: string
  label: string
  icon?: string
  danger?: boolean
  divider?: boolean
}

const props = defineProps<{
  visible: boolean
  x: number
  y: number
  items: ContextMenuItem[]
}>()

const emit = defineEmits<{
  select: [key: string]
  close: []
}>()

const menuRef = ref<HTMLElement | null>(null)
const adjustedX = ref(0)
const adjustedY = ref(0)

async function adjustPosition() {
  await nextTick()
  if (!menuRef.value) return
  const rect = menuRef.value.getBoundingClientRect()
  const { innerWidth, innerHeight } = window
  adjustedX.value = props.x + rect.width > innerWidth ? innerWidth - rect.width - 8 : props.x
  adjustedY.value = props.y + rect.height > innerHeight ? innerHeight - rect.height - 8 : props.y
}

watch(() => [props.visible, props.x, props.y], () => {
  if (props.visible) adjustPosition()
})

function onItemClick(item: ContextMenuItem) {
  if (item.divider) return
  emit('select', item.key)
  emit('close')
}

function onOutsideClick(event: MouseEvent) {
  if (!menuRef.value) return
  if (!menuRef.value.contains(event.target as Node)) {
    emit('close')
  }
}

function onKeydown(event: KeyboardEvent) {
  if (event.key === 'Escape') emit('close')
}

watch(() => props.visible, (v) => {
  if (v) {
    window.addEventListener('mousedown', onOutsideClick, true)
    window.addEventListener('keydown', onKeydown)
    window.addEventListener('contextmenu', onOutsideClick, true)
  } else {
    window.removeEventListener('mousedown', onOutsideClick, true)
    window.removeEventListener('keydown', onKeydown)
    window.removeEventListener('contextmenu', onOutsideClick, true)
  }
})

onUnmounted(() => {
  window.removeEventListener('mousedown', onOutsideClick, true)
  window.removeEventListener('keydown', onKeydown)
  window.removeEventListener('contextmenu', onOutsideClick, true)
})
</script>

<template>
  <Teleport to="body">
    <Transition name="ctx-menu">
      <div
        v-if="visible"
        ref="menuRef"
        class="context-menu"
        :style="{ left: `${adjustedX}px`, top: `${adjustedY}px` }"
        @contextmenu.prevent
      >
        <template v-for="(item, i) in items" :key="item.key || i">
          <div v-if="item.divider" class="ctx-divider" />
          <button
            v-else
            class="ctx-item"
            :class="{ danger: item.danger }"
            @click="onItemClick(item)"
          >
            <Icon v-if="item.icon" :name="item.icon" class="ctx-icon" />
            <span class="ctx-label">{{ item.label }}</span>
          </button>
        </template>
      </div>
    </Transition>
  </Teleport>
</template>

<style scoped>
.context-menu {
  position: fixed;
  z-index: 1000;
  min-width: 180px;
  background: var(--color-canvas);
  border: 1px solid var(--color-hairline);
  border-radius: 10px;
  padding: 6px;
  box-shadow: 0 12px 36px rgba(20, 20, 19, 0.15), 0 2px 8px rgba(20, 20, 19, 0.08);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.ctx-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 12px;
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  color: var(--color-body);
  background: none;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  text-align: left;
  transition: background 0.12s ease, color 0.12s ease;
}

.ctx-item:hover {
  background: var(--color-surface-card);
  color: var(--color-ink);
}

.ctx-item.danger {
  color: #c64545;
}

.ctx-item.danger:hover {
  background: rgba(198, 69, 69, 0.08);
  color: #c64545;
}

.ctx-icon {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  opacity: 0.8;
}

.ctx-label {
  flex: 1;
}

.ctx-divider {
  height: 1px;
  background: var(--color-hairline-soft);
  margin: 4px 0;
}

.ctx-menu-enter-active,
.ctx-menu-leave-active {
  transition: opacity 0.14s ease, transform 0.14s ease;
  transform-origin: top left;
}

.ctx-menu-enter-from,
.ctx-menu-leave-to {
  opacity: 0;
  transform: scale(0.96);
}
</style>
