<script setup lang="ts">
// Reusable kebab "..." menu. Anchors a teleported popover to the trigger
// button's bottom-right corner — escapes overflow/clip on tables and cards.
// Same pattern as components/enduser/EnduserDeviceActions.vue, but generic.
//
// Pass items via the `items` prop. Each item fires a `select` event with its
// `id` so the parent can route the action (toast, open modal, etc.). Items
// marked `danger: true` render with red text; `disabled: true` are inert;
// `separator: true` renders as a divider (no other fields needed).
//
// Trigger is a small ghost UiButton with a "more" icon. To customize the
// trigger, override the `#trigger` slot — you'll receive a `toggle` fn.

import type { IconName } from '~/components/UiIcon.vue'

export interface KebabItem {
  id: string
  label?: string
  icon?: IconName
  danger?: boolean
  disabled?: boolean
  separator?: boolean
}

withDefaults(
  defineProps<{
    items: KebabItem[]
    size?: number
    iconSize?: number
    align?: 'right' | 'left'
  }>(),
  {
    size: 14,
    iconSize: 14,
    align: 'right',
  },
)

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

const open = ref(false)
const triggerRef = ref<HTMLElement | null>(null)
const menuRef = ref<HTMLElement | null>(null)
const pos = ref({ top: 0, right: 0, left: 0 })

function toggle(e: MouseEvent) {
  e.stopPropagation()
  if (!triggerRef.value) return
  const r = triggerRef.value.getBoundingClientRect()
  pos.value = {
    top: r.bottom + 4,
    right: window.innerWidth - r.right,
    left: r.left,
  }
  open.value = !open.value
}

function pick(item: KebabItem) {
  if (item.disabled || item.separator) return
  open.value = false
  emit('select', item.id)
}

function onDoc(e: MouseEvent) {
  if (!open.value) return
  const t = e.target as Node
  if (menuRef.value?.contains(t) || triggerRef.value?.contains(t)) return
  open.value = false
}
function onKey(e: KeyboardEvent) {
  if (e.key === 'Escape') open.value = false
}
function onScroll() {
  open.value = false
}

onMounted(() => {
  document.addEventListener('mousedown', onDoc)
  document.addEventListener('keydown', onKey)
  window.addEventListener('scroll', onScroll, true)
  window.addEventListener('resize', onScroll)
})
onBeforeUnmount(() => {
  document.removeEventListener('mousedown', onDoc)
  document.removeEventListener('keydown', onKey)
  window.removeEventListener('scroll', onScroll, true)
  window.removeEventListener('resize', onScroll)
})

// Route changes also close.
const route = useRoute()
watch(() => route.fullPath, () => { open.value = false })
</script>

<template>
  <span ref="triggerRef" class="more-wrap">
    <slot name="trigger" :toggle="toggle">
      <UiButton size="sm" variant="ghost" @click="toggle">
        <UiIcon name="more" :size="iconSize" />
      </UiButton>
    </slot>
  </span>
  <Teleport to="body">
    <Transition name="pop">
      <div
        v-if="open"
        ref="menuRef"
        class="menu"
        :style="align === 'right'
          ? { top: pos.top + 'px', right: pos.right + 'px' }
          : { top: pos.top + 'px', left: pos.left + 'px' }"
      >
        <template v-for="(it, i) in items" :key="it.id + '_' + i">
          <span v-if="it.separator" class="sep" />
          <button
            v-else
            :class="{ danger: it.danger }"
            :disabled="it.disabled"
            @click="pick(it)"
          >
            <UiIcon v-if="it.icon" :name="it.icon" :size="14" />
            <span>{{ it.label }}</span>
          </button>
        </template>
      </div>
    </Transition>
  </Teleport>
</template>

<style scoped>
.more-wrap { display: inline-flex; }

.menu {
  position: fixed;
  min-width: 220px;
  padding: 4px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
  z-index: 100;
}
.menu button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border-radius: 5px;
  background: transparent;
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  text-align: left;
  color: var(--text);
}
.menu button:hover { background: var(--row-hover, var(--surface)); }
.menu button:disabled { opacity: 0.5; cursor: not-allowed; }
.menu .danger { color: var(--bad); }
.menu .sep { display: block; height: 1px; background: var(--border); margin: 4px 0; }

.pop-enter-active, .pop-leave-active { transition: opacity 0.12s, transform 0.12s; }
.pop-enter-from, .pop-leave-to { opacity: 0; transform: translateY(-4px); }
</style>
