<script setup lang="ts">
import { watch, ref, computed, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { invoke } from '@tauri-apps/api/core'
import { useFocusTrap } from '../utils/focusTrap'
import { useProjectsStore } from '../stores/projects'
import { useInvoicesStore } from '../stores/invoices'
import { Search, FolderKanban, Users, Clock, FileText } from 'lucide-vue-next'

const props = defineProps<{ show: boolean }>()
const emit = defineEmits<{ close: [] }>()

const router = useRouter()
const projectsStore = useProjectsStore()
const invoicesStore = useInvoicesStore()
const { activate, deactivate } = useFocusTrap()
const dialogRef = ref<HTMLElement | null>(null)
const inputRef = ref<HTMLInputElement | null>(null)

const query = ref('')
const activeIndex = ref(0)
let debounceTimer: ReturnType<typeof setTimeout> | null = null

interface SearchResult {
  type: 'project' | 'client' | 'entry' | 'invoice'
  id: number
  label: string
  sublabel: string
  color?: string
  route: string
}

const entryResults = ref<SearchResult[]>([])
const searching = ref(false)

const localResults = computed((): SearchResult[] => {
  const q = query.value.toLowerCase().trim()
  if (!q) return []
  const results: SearchResult[] = []

  for (const p of projectsStore.projects) {
    if (results.length >= 5) break
    if (p.name.toLowerCase().includes(q)) {
      results.push({ type: 'project', id: p.id!, label: p.name, sublabel: p.archived ? 'Archived' : 'Active', color: p.color, route: '/projects' })
    }
  }

  for (const inv of invoicesStore.invoices) {
    if (results.length >= 10) break
    if (inv.invoice_number.toLowerCase().includes(q)) {
      results.push({ type: 'invoice', id: inv.id!, label: inv.invoice_number, sublabel: inv.status, route: '/invoices' })
    }
  }

  return results
})

const allResults = computed(() => [...localResults.value, ...entryResults.value])

async function searchEntries(q: string) {
  if (!q.trim()) {
    entryResults.value = []
    return
  }
  searching.value = true
  try {
    const rows = await invoke<any[]>('search_entries', { query: q, limit: 5 })
    entryResults.value = rows.map(r => ({
      type: 'entry' as const,
      id: r.id,
      label: r.description || '(no description)',
      sublabel: r.project_name || 'Unknown project',
      color: r.project_color,
      route: '/entries',
    }))
  } catch {
    entryResults.value = []
  } finally {
    searching.value = false
  }
}

function onInput() {
  activeIndex.value = 0
  if (debounceTimer) clearTimeout(debounceTimer)
  debounceTimer = setTimeout(() => searchEntries(query.value), 200)
}

function navigate(result: SearchResult) {
  router.push(result.route)
  emit('close')
}

function onKeydown(e: KeyboardEvent) {
  const total = allResults.value.length
  if (e.key === 'ArrowDown') {
    e.preventDefault()
    activeIndex.value = (activeIndex.value + 1) % Math.max(total, 1)
  } else if (e.key === 'ArrowUp') {
    e.preventDefault()
    activeIndex.value = (activeIndex.value - 1 + Math.max(total, 1)) % Math.max(total, 1)
  } else if (e.key === 'Enter' && allResults.value[activeIndex.value]) {
    e.preventDefault()
    navigate(allResults.value[activeIndex.value])
  } else if (e.key === 'Escape') {
    emit('close')
  }
}

const typeIcon: Record<string, any> = {
  project: FolderKanban,
  client: Users,
  entry: Clock,
  invoice: FileText,
}

watch(() => props.show, (val) => {
  if (val) {
    query.value = ''
    entryResults.value = []
    activeIndex.value = 0
    nextTick(() => {
      if (dialogRef.value) activate(dialogRef.value, { onDeactivate: () => emit('close') })
      inputRef.value?.focus()
    })
  } else {
    deactivate()
  }
})
</script>

<template>
  <Transition name="modal">
  <div
    v-if="show"
    class="fixed inset-0 bg-black/70 backdrop-blur-[4px] flex items-start justify-center pt-[15vh] p-4 z-50"
    @click.self="$emit('close')"
  >
    <div
      ref="dialogRef"
      role="dialog"
      aria-modal="true"
      aria-label="Search"
      class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-md overflow-hidden"
      @keydown="onKeydown"
    >
      <div class="flex items-center gap-3 px-4 py-3 border-b border-border-subtle">
        <Search class="w-4 h-4 text-text-tertiary shrink-0" :stroke-width="1.5" aria-hidden="true" />
        <input
          ref="inputRef"
          v-model="query"
          @input="onInput"
          type="text"
          class="flex-1 bg-transparent text-[0.875rem] text-text-primary placeholder-text-tertiary outline-none"
          placeholder="Search projects, entries, invoices..."
          aria-label="Search"
        />
        <kbd class="text-[0.625rem] text-text-tertiary border border-border-subtle rounded px-1.5 py-0.5">Esc</kbd>
      </div>

      <div v-if="!query.trim()" class="px-4 py-8 text-center text-[0.75rem] text-text-tertiary">
        Type to search...
      </div>

      <div v-else-if="allResults.length === 0 && !searching" class="px-4 py-8 text-center text-[0.75rem] text-text-tertiary">
        No results for "{{ query }}"
      </div>

      <ul v-else class="max-h-80 overflow-y-auto py-2" role="listbox">
        <li
          v-for="(result, idx) in allResults"
          :key="result.type + '-' + result.id"
          role="option"
          :aria-selected="idx === activeIndex"
          class="flex items-center gap-3 px-4 py-2.5 cursor-pointer transition-colors duration-100"
          :class="idx === activeIndex ? 'bg-accent/10' : 'hover:bg-bg-elevated'"
          @click="navigate(result)"
          @mouseenter="activeIndex = idx"
        >
          <component :is="typeIcon[result.type]" class="w-4 h-4 text-text-tertiary shrink-0" :stroke-width="1.5" aria-hidden="true" />
          <span v-if="result.color" class="w-2 h-2 rounded-full shrink-0" :style="{ backgroundColor: result.color }" aria-hidden="true" />
          <div class="flex-1 min-w-0">
            <p class="text-[0.8125rem] text-text-primary truncate">{{ result.label }}</p>
            <p class="text-[0.6875rem] text-text-tertiary truncate">{{ result.sublabel }}</p>
          </div>
          <span class="text-[0.5625rem] text-text-tertiary uppercase tracking-wider shrink-0">{{ result.type }}</span>
        </li>
      </ul>
    </div>
  </div>
  </Transition>
</template>
