<template>
  <div ref="container" class="relative">
    <!-- Input: shows current value; typing filters the dropdown list -->
    <div class="relative">
      <input
        ref="inputEl"
        v-model="query"
        type="text"
        :placeholder="placeholder"
        class="block w-full rounded-lg px-3 py-2 pr-8 text-sm border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition-colors"
        autocomplete="off"
        @focus="handleFocus"
        @blur="handleBlur"
        @keydown.down.prevent="moveDown"
        @keydown.up.prevent="moveUp"
        @keydown.enter.prevent="selectHighlighted"
        @keydown.escape="close"
        @input="onInput"
      />
      <!-- Chevron toggle button -->
      <button
        type="button"
        tabindex="-1"
        class="absolute inset-y-0 right-0 flex items-center px-2 text-gray-400 hover:text-gray-600"
        @mousedown.prevent="toggleOpen"
      >
        <AppIcon
          name="chevronDown"
          :class="['w-4 h-4 transition-transform', isOpen ? 'rotate-180' : '']"
        />
      </button>
    </div>

    <!-- Dropdown — teleported to body to avoid overflow:hidden clipping in parent sections -->
    <Teleport to="body">
      <ul
        v-if="isOpen"
        ref="listEl"
        :style="dropdownStyle"
        class="fixed z-[9999] bg-white border border-gray-200 rounded-lg shadow-xl overflow-y-auto"
        style="max-height: 240px;"
        @mousedown.prevent
      >
        <!-- Loading state -->
        <li v-if="loading" class="flex items-center gap-2 px-3 py-2 text-sm text-gray-400">
          <span class="animate-spin rounded-full border-2 border-current border-t-transparent w-3 h-3"></span>
          Loading models…
        </li>

        <!-- Error state -->
        <li v-else-if="fetchError && filtered.length === 0" class="px-3 py-2 text-sm text-amber-600">
          Could not fetch models — type a name manually below.
        </li>

        <!-- Model list -->
        <template v-else>
          <li
            v-for="(model, i) in filtered"
            :key="model"
            :class="[
              'px-3 py-2 text-sm cursor-pointer select-none',
              i === highlighted ? 'bg-indigo-50 text-indigo-900' : 'text-gray-800 hover:bg-gray-50'
            ]"
            @mousedown.prevent="selectModel(model)"
          >
            {{ model }}
          </li>

          <!-- No matches hint (only when query typed but nothing matches) -->
          <li
            v-if="filtered.length === 0 && query.trim()"
            class="px-3 py-2 text-xs text-gray-400 italic"
          >
            No matches
          </li>
        </template>

        <!-- Static "manual entry" — always last, always visible regardless of filter -->
        <li
          class="sticky bottom-0 flex items-center gap-2 px-3 py-2 text-sm text-indigo-600 font-medium border-t border-gray-100 bg-white cursor-pointer hover:bg-indigo-50 select-none"
          @mousedown.prevent="selectManual"
        >
          <AppIcon name="pencilEdit" class="w-3.5 h-3.5 shrink-0" />
          <span>{{ query.trim() ? `Use "${query.trim()}"` : 'Enter model name manually' }}</span>
        </li>
      </ul>
    </Teleport>
  </div>
</template>

<script setup>
import { ref, computed, watch, nextTick, onUnmounted } from 'vue'
import { getAiModels } from '../../api/client.js'
import AppIcon from './AppIcon.vue'

const props = defineProps({
  modelValue: { type: String, default: '' },
  providerId: { type: String, required: true },
  placeholder: { type: String, default: '' },
})
const emit = defineEmits(['update:modelValue'])

// ── State ─────────────────────────────────────────────────────────────────────

const container = ref(null)
const inputEl = ref(null)
const listEl = ref(null)
const isOpen = ref(false)
const query = ref(props.modelValue || '')   // displayed value in the input
const filterText = ref('')                  // separate filter — only set when user types
const hasTyped = ref(false)                 // false on open → show all models unfiltered
const models = ref([])
const loading = ref(false)
const fetchError = ref(null)
const highlighted = ref(-1)
const dropdownStyle = ref({})
// Cache fetched models per providerId so we don't re-fetch on each open
const fetchedFor = ref(null)

// ── Sync external modelValue → internal query when parent changes the value ───

watch(() => props.modelValue, (val) => {
  if (val !== query.value) query.value = val || ''
})

// ── Filtered list ─────────────────────────────────────────────────────────────
// Show ALL models when the dropdown first opens (hasTyped=false).
// Only filter once the user starts typing so the pre-filled value
// doesn't hide every model that doesn't match the current selection.

const filtered = computed(() => {
  if (!hasTyped.value) return models.value
  const q = filterText.value.trim().toLowerCase()
  if (!q) return models.value
  return models.value.filter(m => m.toLowerCase().includes(q))
})

// ── Dropdown position (recalculate from input bounding rect) ──────────────────

function updatePosition() {
  if (!inputEl.value) return
  const rect = inputEl.value.getBoundingClientRect()
  const spaceBelow = window.innerHeight - rect.bottom
  const dropH = Math.min(240, 40 + filtered.value.length * 36 + 40)

  // Prefer opening below; flip above if not enough space
  if (spaceBelow >= dropH || spaceBelow > 120) {
    dropdownStyle.value = {
      top: `${rect.bottom + 4}px`,
      left: `${rect.left}px`,
      width: `${rect.width}px`,
    }
  } else {
    dropdownStyle.value = {
      bottom: `${window.innerHeight - rect.top + 4}px`,
      left: `${rect.left}px`,
      width: `${rect.width}px`,
    }
  }
}

// ── Fetch models from backend ─────────────────────────────────────────────────

async function fetchModels() {
  if (fetchedFor.value === props.providerId) return   // already cached for this provider
  loading.value = true
  fetchError.value = null
  try {
    const data = await getAiModels(props.providerId)
    models.value = data.models || []
    fetchedFor.value = props.providerId
    if (data.error) fetchError.value = data.error
  } catch (e) {
    fetchError.value = e.message || 'fetch failed'
    models.value = []
  } finally {
    loading.value = false
  }
}

// ── Open / close ──────────────────────────────────────────────────────────────

async function open() {
  isOpen.value = true
  highlighted.value = -1
  hasTyped.value = false   // reset so all models are shown on open
  filterText.value = ''
  await nextTick()
  updatePosition()
  fetchModels()
}

function close() {
  isOpen.value = false
  highlighted.value = -1
  hasTyped.value = false
  filterText.value = ''
}

function toggleOpen() {
  if (isOpen.value) {
    close()
  } else {
    inputEl.value?.focus()
    open()
  }
}

function handleFocus() {
  open()
}

// Delay close so mousedown on list items fires first
function handleBlur() {
  setTimeout(close, 150)
}

// ── Input handler — emit new value as user types ──────────────────────────────

function onInput() {
  hasTyped.value = true
  filterText.value = query.value
  emit('update:modelValue', query.value)
  highlighted.value = -1
  if (!isOpen.value) open()
}

// ── Selection ─────────────────────────────────────────────────────────────────

function selectModel(model) {
  query.value = model
  emit('update:modelValue', model)
  close()
}

function selectManual() {
  // Commit whatever is currently typed and close
  emit('update:modelValue', query.value)
  close()
}

// ── Keyboard navigation ───────────────────────────────────────────────────────

function moveDown() {
  if (!isOpen.value) { open(); return }
  const max = filtered.value.length  // +1 for manual entry item, but we skip it in keyboard nav
  highlighted.value = highlighted.value < max - 1 ? highlighted.value + 1 : 0
}

function moveUp() {
  if (!isOpen.value) return
  const max = filtered.value.length
  highlighted.value = highlighted.value > 0 ? highlighted.value - 1 : max - 1
}

function selectHighlighted() {
  if (highlighted.value >= 0 && highlighted.value < filtered.value.length) {
    selectModel(filtered.value[highlighted.value])
  } else {
    selectManual()
  }
}

// ── Reposition on scroll/resize so dropdown tracks input ─────────────────────

function onScroll() { if (isOpen.value) updatePosition() }

window.addEventListener('scroll', onScroll, true)
window.addEventListener('resize', onScroll)
onUnmounted(() => {
  window.removeEventListener('scroll', onScroll, true)
  window.removeEventListener('resize', onScroll)
})
</script>
