<template>
  <v-card>
    <v-card-title>Pick a fandom</v-card-title>
    <v-card-text>
      <!-- Keyboard flow (operator-specified 2026-06-07):
           1. Focus lands here (driven by the dialog's @after-enter calling the
              exposed focusSearch — `autofocus` is unreliable inside a v-dialog
              because the focus-trap activates after mount and steals it).
           2. Tab moves to the "new fandom" field below.
           3. Selecting a fandom (click, or arrow+Enter to pick from the menu)
              leaves it in the field; a SECOND Enter (menu closed) accepts it.
           We bind v-model:menu so the Enter handler can tell "pick from the open
           menu" (let Vuetify handle) apart from "accept the chosen value". -->
      <v-autocomplete
        ref="fandomRef"
        v-model="selectedId"
        v-model:menu="menuOpen"
        :items="store.fandomCache"
        :item-title="(f) => f.name"
        :item-value="(f) => f.id"
        label="Fandom" clearable density="compact"
        @keydown.enter.capture="onSearchEnter"
        @keydown.tab="onSearchTab"
      />
      <v-divider class="my-3" />
      <p class="text-caption mb-2">Or create a new fandom:</p>
      <div class="d-flex" style="gap: 8px;">
        <!-- Enter creates; on success focus returns to the dropdown (onCreate),
             so the operator can immediately Enter-to-accept the new fandom. -->
        <v-text-field
          ref="newNameRef"
          v-model="newName" placeholder="New fandom name"
          density="compact" hide-details
          @keydown.enter.prevent="onCreate"
        />
        <v-btn :disabled="!newName.trim()" rounded="pill" @click="onCreate">Create</v-btn>
      </div>
    </v-card-text>
    <v-card-actions>
      <!-- Not every character belongs to a fandom (original characters,
           unsorted, etc.). "No fandom" creates the character unassigned;
           a fandom can still be set later from the chip's kebab menu. -->
      <v-btn variant="text" @click="onNoFandom">No fandom</v-btn>
      <v-spacer />
      <v-btn @click="$emit('cancel')">Cancel</v-btn>
      <v-btn :disabled="!selectedId" color="primary" rounded="pill" @click="onConfirm">Use this fandom</v-btn>
    </v-card-actions>
  </v-card>
</template>

<script setup>
import { nextTick, onMounted, ref } from 'vue'
import { useTagStore } from '../../stores/tags.js'

const emit = defineEmits(['confirm', 'cancel'])
const store = useTagStore()

const selectedId = ref(null)
const newName = ref('')
const menuOpen = ref(false)
const fandomRef = ref(null)
const newNameRef = ref(null)

// Always refresh on open so the list reflects fandoms created elsewhere (#712).
onMounted(() => store.loadFandoms())

// Exposed so the parent dialog can focus the search field on @after-enter —
// the reliable point to grab focus (the dialog transition + focus-trap are done).
function focusSearch () {
  nextTick(() => {
    fandomRef.value?.focus?.()
    // Keep the menu closed after a programmatic focus so the very next Enter
    // accepts the value instead of being swallowed as a menu interaction.
    menuOpen.value = false
  })
}
defineExpose({ focusSearch })

async function onCreate () {
  const name = newName.value.trim()
  if (!name) return
  const f = await store.createFandom(name)
  selectedId.value = f.id
  newName.value = ''
  // The created fandom is now the selection; hand focus back to the dropdown
  // so a single Enter accepts it (operator-specified flow 2026-06-07).
  focusSearch()
}

function onConfirm () {
  const f = store.fandomCache.find(x => x.id === selectedId.value)
  if (f) emit('confirm', f)
}

// Enter on the search field — bound in the CAPTURE phase so this runs BEFORE
// Vuetify's own input keydown handler (which opens the menu on Enter). When the
// menu is open, let Vuetify pick the highlighted item (it sets selectedId +
// closes the menu). When it's closed and a fandom is already chosen, accept it
// and stop the event so Vuetify never (re)opens the menu — that re-open was the
// bug: Enter popped the dropdown instead of submitting (operator-flagged
// 2026-06-07).
function onSearchEnter (e) {
  if (menuOpen.value) return
  if (selectedId.value != null) {
    e.preventDefault()
    e.stopPropagation()
    onConfirm()
  }
}

// Tab from the search field goes to the "new fandom" text field (operator-
// specified). Shift+Tab keeps normal reverse traversal.
function onSearchTab (e) {
  if (e.shiftKey) return
  e.preventDefault()
  menuOpen.value = false
  nextTick(() => newNameRef.value?.focus?.())
}

// Create the character with no fandom. Emits null so the caller knows this
// was a deliberate "unassigned", not a cancel.
function onNoFandom () {
  emit('confirm', null)
}
</script>
