<script setup>
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'

import { useSearchEngine } from '@/composables/useSearchEngine'
import { useLinksStore } from '@/stores/links'

import SearchResultItem from './SearchResultItem.vue'
import styles from './GlobalSearchModal.module.scss'

const props = defineProps({
  modelValue: {
    type: Boolean,
    default: false,
  },
  searchShortcut: {
    type: String,
    default: 'Ctrl + K',
  },
})

const emit = defineEmits(['update:modelValue', 'select', 'create'])

const linksStore = useLinksStore()
const { results, hasResults, isSearching, search, clear, isIndexReady } = useSearchEngine()

const localQuery = ref('')
const activeIndex = ref(-1)
const inputRef = ref(null)

const visible = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value),
})

onMounted(() => {
  linksStore.ensureLoaded()
})

watch(
  () => props.modelValue,
  (next) => {
    if (next) {
      nextTick(() => {
        inputRef.value?.focus()
      })
    } else {
      localQuery.value = ''
      clear()
      activeIndex.value = -1
    }
  }
)

watch(localQuery, (value) => {
  if (!props.modelValue) return
  search(value)
})

watch(
  results,
  (items) => {
    if (items.length) {
      activeIndex.value = 0
    } else {
      activeIndex.value = -1
    }
  },
  { immediate: true }
)

function close() {
  visible.value = false
}

function selectAt(index) {
  const result = results.value[index]
  if (!result) return
  emit('select', result.link)
  close()
}

function handleInputKeydown(event) {
  if (event.key === 'ArrowDown') {
    event.preventDefault()
    if (!results.value.length) return
    activeIndex.value = (activeIndex.value + 1) % results.value.length
    return
  }
  if (event.key === 'ArrowUp') {
    event.preventDefault()
    if (!results.value.length) return
    activeIndex.value = (activeIndex.value - 1 + results.value.length) % results.value.length
    return
  }
  if (event.key === 'Enter') {
    event.preventDefault()
    if (activeIndex.value >= 0) {
      selectAt(activeIndex.value)
    }
    return
  }
  if (event.key === 'Escape') {
    event.preventDefault()
    close()
  }
}

function handleResultSelect(link) {
  emit('select', link)
  close()
}

function handleOverlayClick(event) {
  if (event.target === event.currentTarget) {
    close()
  }
}

function handleCreateBookmark() {
  emit('create')
  close()
}

const emptyMessage = computed(() => {
  if (!localQuery.value.trim()) {
    return '输入关键词即可根据标题、标签、描述或链接进行搜索。'
  }
  if (!isIndexReady.value) {
    return '正在准备搜索索引...'
  }
  return '暂无匹配结果，尝试其他关键字或创建一个新链接。'
})

onBeforeUnmount(() => {
  clear()
})
</script>

<template>
  <teleport to="body">
    <transition name="fade">
      <div v-if="visible" :class="styles.overlay" @click="handleOverlayClick">
        <div :class="styles.panel" role="dialog" aria-modal="true" aria-label="全局书签搜索">
          <header :class="styles.header">
            <div :class="styles.inputWrapper">
              <el-input
                ref="inputRef"
                v-model="localQuery"
                placeholder="搜索书签或输入 @标签"
                size="large"
                clearable
                autofocus
                @keydown="handleInputKeydown"
              />
              <span :class="styles.shortcutBadge">{{ searchShortcut }}</span>
            </div>
            <div :class="styles.meta">
              <span v-if="isSearching" :class="styles.loading">
                正在搜索...
              </span>
              <span v-else-if="localQuery">共找到 {{ results.length }} 条结果</span>
              <span v-else>搜索范围覆盖标题、描述、标签与链接。</span>
              <span :class="styles.closeHint">按 Esc 关闭</span>
            </div>
          </header>

          <section :class="styles.results">
            <ul v-if="hasResults" :class="styles.resultsList" role="listbox">
              <SearchResultItem
                v-for="(result, index) in results"
                :key="result.link.id"
                :result="result"
                :active="index === activeIndex"
                @select="handleResultSelect"
              />
            </ul>
            <div v-else :class="styles.emptyState">
              <p>{{ emptyMessage }}</p>
              <el-button type="primary" size="small" @click="handleCreateBookmark">新增书签</el-button>
            </div>
          </section>

          <footer :class="styles.footer">
            <span>使用 ↑ ↓ 导航，Enter 打开链接</span>
            <span>结果优先展示标题、标签及常访问的书签。</span>
          </footer>
        </div>
      </div>
    </transition>
  </teleport>
</template>

<style lang="scss" scoped>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>

