<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue'
import KsDialog from '../ui/components/KsDialog.vue'
import type { NavigationEntry } from './navigationCatalog'

const props = defineProps<{ open: boolean; entries: NavigationEntry[] }>()
const emit = defineEmits<{ close: []; select: [entry: NavigationEntry] }>()

const query = ref('')
const activeIndex = ref(0)
const inputRef = ref<HTMLInputElement | null>(null)
const resultId = (index: number) => `ks-menu-search-result-${index}`

const results = computed<NavigationEntry[]>(() => {
  const q = query.value.trim().toLowerCase()
  const source = q
    ? props.entries.filter(entry => entry.title.toLowerCase().includes(q) || entry.screenId.toLowerCase().includes(q) || entry.module.toLowerCase().includes(q))
    : props.entries
  return source.slice(0, 20)
})

watch(() => props.open, async value => {
  if (!value) return
  query.value = ''
  activeIndex.value = 0
  await nextTick()
  inputRef.value?.focus()
})
watch(results, () => { activeIndex.value = 0 })

function move(delta: number) {
  if (!results.value.length) return
  activeIndex.value = (activeIndex.value + delta + results.value.length) % results.value.length
}
function selectActive() {
  const entry = results.value[activeIndex.value]
  if (entry) emit('select', entry)
}
</script>

<template>
  <KsDialog :visible="props.open" title="메뉴 검색" modal closable @update:visible="value => { if (!value) emit('close') }">
    <div class="ks-menu-search" role="presentation" @keydown.down.prevent="move(1)" @keydown.up.prevent="move(-1)" @keydown.enter.prevent="selectActive" @keydown.esc="emit('close')">
      <input ref="inputRef" v-model="query" type="text" placeholder="메뉴명 · 화면코드 · 업무명 검색" aria-label="메뉴 검색" :aria-activedescendant="results.length ? resultId(activeIndex) : undefined" aria-controls="ks-menu-search-results" />
      <ul id="ks-menu-search-results" role="listbox" aria-label="검색 결과">
        <li
          v-for="(entry, index) in results"
          :key="entry.screenId"
          :id="resultId(index)"
          role="option"
          :aria-selected="index === activeIndex"
          :class="{ active: index === activeIndex }"
          @mouseenter="activeIndex = index"
          @click="emit('select', entry)"
        >
          <span>{{ entry.title }}</span><small>{{ entry.module }} · {{ entry.screenId }}</small>
        </li>
        <li v-if="!results.length" class="empty">검색 결과가 없습니다.</li>
      </ul>
    </div>
  </KsDialog>
</template>

<style scoped>
.ks-menu-search { display: grid; gap: var(--ks-space-2); min-width: 24rem; }
.ks-menu-search input { height: var(--ks-control-height); padding: 0 var(--ks-space-3); border: 1px solid var(--ks-color-border-strong); border-radius: var(--ks-radius-sm); font-size: var(--ks-font-body); }
.ks-menu-search ul { list-style: none; margin: 0; padding: 0; max-height: 20rem; overflow-y: auto; display: grid; gap: 1px; }
.ks-menu-search li { display: flex; justify-content: space-between; gap: var(--ks-space-2); padding: var(--ks-space-2) var(--ks-space-3); border-radius: var(--ks-radius-sm); cursor: pointer; }
.ks-menu-search li.active { background: var(--ks-color-neutral-100); }
.ks-menu-search li small { color: var(--ks-color-text-muted); font-size: var(--ks-font-caption); white-space: nowrap; }
.ks-menu-search li.empty { color: var(--ks-color-text-muted); cursor: default; }
</style>
