<template>
  <div class="relative">
    <label v-if="label" class="block text-sm font-medium text-slate-300 mb-1">{{ label }}</label>
    <div class="relative">
      <input
        ref="inputRef"
        :value="displayText"
        @input="onInput"
        @focus="onFocus"
        @blur="onBlur"
        @keydown.down.prevent="highlightNext"
        @keydown.up.prevent="highlightPrev"
        @keydown.enter.prevent="selectHighlighted"
        @keydown.escape="closeDropdown"
        :placeholder="placeholder"
        class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm"
      />
      <!-- Loading spinner -->
      <svg
        v-if="searching"
        class="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 animate-spin text-slate-400"
        fill="none" stroke="currentColor" viewBox="0 0 24 24"
      >
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
      </svg>
      <!-- Clear button -->
      <button
        v-if="selectedItem && !searching"
        @click="clearSelection"
        class="absolute right-3 top-1/2 -translate-y-1/2 text-slate-500 hover:text-white transition"
        type="button"
      >
        <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
        </svg>
      </button>
    </div>

    <!-- Dropdown -->
    <div
      v-if="showDropdown && filteredItems.length > 0"
      class="absolute z-50 mt-1 w-full bg-slate-800 border border-slate-600 rounded-lg shadow-xl max-h-60 overflow-y-auto"
    >
      <button
        v-for="(item, index) in filteredItems"
        :key="item.id"
        @mousedown.prevent="selectItem(item)"
        class="w-full text-left px-3 py-2 text-sm transition flex items-center gap-2"
        :class="index === highlightedIndex
          ? 'bg-indigo-500/20 text-white'
          : 'text-slate-300 hover:bg-slate-700'"
      >
        <span class="font-mono text-indigo-400">{{ item.zip_code }}</span>
        <span>{{ item.city }}</span>
        <span class="text-xs text-slate-500 ml-auto">{{ item.country_code }}</span>
      </button>
    </div>

    <!-- No results -->
    <div
      v-if="showDropdown && query.length >= minChars && filteredItems.length === 0 && !searching"
      class="absolute z-50 mt-1 w-full bg-slate-800 border border-slate-600 rounded-lg shadow-xl p-3 text-sm text-slate-400"
    >
      Nincs találat
    </div>
  </div>
</template>

<script setup lang="ts">
/**
 * SmartLocationInput.vue
 * ======================
 * 
 * Autocomplete/combobox component for selecting a city/zip code pair.
 * Calls the backend GET /api/v1/locations/autocomplete endpoint.
 * 
 * Usage:
 *   <SmartLocationInput v-model="selected" />
 * 
 * The v-model emits the selected GeoPostalCode object:
 *   { id: number, zip_code: string, city: string, country_code: string }
 * 
 * Props:
 *   modelValue: The currently selected location (null or the object)
 *   label: Optional label text above the input
 *   placeholder: Placeholder text
 *   minChars: Minimum characters before triggering search (default: 2)
 *   countryCode: Filter by country code (default: 'HU')
 *   debounceMs: Debounce delay in ms (default: 300)
 */

import { ref, computed, watch, nextTick } from 'vue'

interface LocationItem {
  id: number
  zip_code: string
  city: string
  country_code: string
}

const props = withDefaults(defineProps<{
  modelValue?: LocationItem | null
  label?: string
  placeholder?: string
  minChars?: number
  countryCode?: string
  debounceMs?: number
}>(), {
  modelValue: null,
  label: '',
  placeholder: 'Kezdj el gépelni (irányítószám vagy város)...',
  minChars: 2,
  countryCode: 'HU',
  debounceMs: 300,
})

const emit = defineEmits<{
  'update:modelValue': [value: LocationItem | null]
  'select': [value: LocationItem]
}>()

// ── State ──────────────────────────────────────────────
const inputRef = ref<HTMLInputElement | null>(null)
const query = ref('')
const selectedItem = ref<LocationItem | null>(props.modelValue)
const items = ref<LocationItem[]>([])
const searching = ref(false)
const showDropdown = ref(false)
const highlightedIndex = ref(0)
let debounceTimer: ReturnType<typeof setTimeout> | null = null

// ── Computed ───────────────────────────────────────────

/**
 * The display text shown in the input.
 * If a location is selected, shows "zip_code city".
 * Otherwise shows the raw query text.
 */
const displayText = computed(() => {
  if (selectedItem.value) {
    return `${selectedItem.value.zip_code} ${selectedItem.value.city}`
  }
  return query.value
})

/**
 * Filtered items based on the current query.
 * The backend already filters, but we keep client-side filtering
 * for instant feedback when the user types more after results load.
 */
const filteredItems = computed(() => {
  if (!query.value || query.value.length < props.minChars) return []
  const q = query.value.toLowerCase()
  return items.value.filter(
    (item) =>
      item.zip_code.toLowerCase().includes(q) ||
      item.city.toLowerCase().includes(q)
  )
})

// ── Watch modelValue from parent ───────────────────────
watch(
  () => props.modelValue,
  (val) => {
    selectedItem.value = val
  }
)

// ── Methods ────────────────────────────────────────────

/**
 * Handle input events from the text field.
 * Starts debounced search when the user types.
 */
function onInput(event: Event) {
  const target = event.target as HTMLInputElement
  query.value = target.value

  // If the user is typing, clear the selected item
  if (selectedItem.value) {
    selectedItem.value = null
    emit('update:modelValue', null)
  }

  // Debounced search
  if (debounceTimer) clearTimeout(debounceTimer)
  if (query.value.length >= props.minChars) {
    debounceTimer = setTimeout(() => {
      searchLocations(query.value)
    }, props.debounceMs)
  } else {
    items.value = []
    showDropdown.value = false
  }
}

/**
 * Call the backend autocomplete API.
 */
async function searchLocations(searchQuery: string) {
  if (!searchQuery || searchQuery.length < props.minChars) return
  searching.value = true
  try {
    const res = await $fetch('/api/v1/locations/autocomplete', {
      params: {
        q: searchQuery,
        country_code: props.countryCode,
        limit: 15,
      },
      headers: getHeaders(),
    })
    items.value = (res as LocationItem[]) || []
    highlightedIndex.value = 0
    showDropdown.value = items.value.length > 0
  } catch (err: any) {
    console.error('Location autocomplete error:', err)
    items.value = []
  } finally {
    searching.value = false
  }
}

/**
 * Get auth headers for API calls.
 */
function getHeaders(): Record<string, string> {
  const token = useCookie('access_token').value
  const headers: Record<string, string> = { 'Content-Type': 'application/json' }
  if (token) headers['Authorization'] = `Bearer ${token}`
  return headers
}

/**
 * Select an item from the dropdown.
 */
function selectItem(item: LocationItem) {
  selectedItem.value = item
  query.value = ''
  showDropdown.value = false
  emit('update:modelValue', item)
  emit('select', item)
}

/**
 * Clear the current selection.
 */
function clearSelection() {
  selectedItem.value = null
  query.value = ''
  items.value = []
  showDropdown.value = false
  emit('update:modelValue', null)
  nextTick(() => {
    inputRef.value?.focus()
  })
}

/**
 * Close the dropdown.
 */
function closeDropdown() {
  showDropdown.value = false
}

/**
 * Handle focus - show dropdown if there are results.
 */
function onFocus() {
  if (filteredItems.value.length > 0) {
    showDropdown.value = true
  }
}

/**
 * Handle blur - close dropdown with a delay to allow click.
 */
function onBlur() {
  // Delay to allow mousedown on dropdown items
  setTimeout(() => {
    showDropdown.value = false
  }, 200)
}

/**
 * Highlight the next item in the dropdown.
 */
function highlightNext() {
  if (filteredItems.value.length > 0) {
    highlightedIndex.value = (highlightedIndex.value + 1) % filteredItems.value.length
  }
}

/**
 * Highlight the previous item in the dropdown.
 */
function highlightPrev() {
  if (filteredItems.value.length > 0) {
    highlightedIndex.value = (highlightedIndex.value - 1 + filteredItems.value.length) % filteredItems.value.length
  }
}

/**
 * Select the currently highlighted item.
 */
function selectHighlighted() {
  if (filteredItems.value.length > 0 && highlightedIndex.value >= 0) {
    selectItem(filteredItems.value[highlightedIndex.value])
  }
}
</script>

<style scoped>
.overflow-y-auto::-webkit-scrollbar {
  width: 6px;
}
.overflow-y-auto::-webkit-scrollbar-track {
  background: transparent;
}
.overflow-y-auto::-webkit-scrollbar-thumb {
  background-color: rgba(100, 116, 139, 0.5);
  border-radius: 3px;
}
</style>
