<script setup>
import { ref, nextTick, onMounted, watch, computed } from 'vue'
import { useTranslation } from 'i18next-vue'
import { useRouter } from 'vue-router'
import { useExercises } from '../composables/useExercises.js'
import { useJsonExport } from '../composables/useJsonExport.js'
import { useJsonImport } from '../composables/useJsonImport.js'
import { useSettings } from '../composables/useSettings.js'
import { useKeyboardShortcut } from '../composables/useKeyboardShortcut.js'
import { useListNavigation } from '../composables/useListNavigation.js'
import ImportDialog from '../components/ImportDialog.vue'

const { t } = useTranslation()
const router = useRouter()
const { exercises, loading, fetchAll, search } = useExercises()
const { exportAllExercises } = useJsonExport()
const { loadFile } = useJsonImport()
const { settings, fetchAll: fetchSettings } = useSettings()

const searchQuery = ref('')
const searching = ref(false)
const searchInput = ref(null)

// Import dialog state
const showImportDialog = ref(false)
const importEnvelope = ref(null)
const importAsMine = ref(false)
const localUuid = ref('')

onMounted(async () => {
  fetchAll()
  await fetchSettings()
  localUuid.value = settings.value.user_uuid || ''
})

let searchTimeout = null
watch(searchQuery, (query) => {
  clearTimeout(searchTimeout)
  const trimmed = query.trim()
  if (!trimmed) {
    fetchAll()
    return
  }
  searchTimeout = setTimeout(() => {
    search(trimmed)
  }, 250)
})

function goToNew() {
  router.push({ name: 'exercise-new' })
}

useKeyboardShortcut('n', goToNew)

const exerciseCount = computed(() => exercises.value.length)
const { focusedIndex: focusedExerciseIndex } = useListNavigation(exerciseCount, (index) => {
  goToDetail(exercises.value[index].id)
})

function goToDetail(id) {
  router.push({ name: 'exercise-detail', params: { id } })
}

function toggleSearch() {
  searching.value = !searching.value
  if (searching.value) {
    nextTick(() => {
      searchInput.value?.focus()
    })
  } else {
    searchQuery.value = ''
    fetchAll()
  }
}

function onSearchBlur() {
  if (!searchQuery.value.trim()) {
    searching.value = false
  }
}

function clearSearch() {
  searchQuery.value = ''
  searchInput.value?.focus()
}

async function onExport() {
  await exportAllExercises(searchQuery.value.trim())
}

async function onImport(asMine = false) {
  const result = await loadFile()
  if (result.cancelled) return
  if (result.error) {
    window.alert(t(result.error))
    return
  }
  importEnvelope.value = result.envelope
  importAsMine.value = asMine
  showImportDialog.value = true
}

function onImportDone() {
  showImportDialog.value = false
  importEnvelope.value = null
  importAsMine.value = false
  fetchAll()
}

function onImportClose() {
  showImportDialog.value = false
  importEnvelope.value = null
  importAsMine.value = false
}
</script>

<template>
  <Teleport to="#actionbar-actions" defer>
    <button
      data-testid="exercise-search-toggle"
      :title="$t('exercises.searchPlaceholder')"
      :aria-label="$t('exercises.searchPlaceholder')"
      @click="toggleSearch"
    >
      <i class="bi bi-search"></i>
    </button>
    <button
      data-testid="exercise-export-btn"
      :title="$t('export.exercises')"
      :aria-label="$t('export.exercises')"
      @click="onExport"
    >
      <i class="bi bi-download"></i>
    </button>
    <button
      data-testid="exercise-import-btn"
      :title="$t('import.exercises')"
      :aria-label="$t('import.exercises')"
      @click="onImport(false)"
    >
      <i class="bi bi-upload"></i>
    </button>
    <button
      data-testid="exercise-import-as-mine-btn"
      :title="$t('import.importAsMine')"
      :aria-label="$t('import.importAsMine')"
      @click="onImport(true)"
    >
      <i class="bi bi-person-check"></i>
    </button>
    <button
      data-testid="exercise-new-btn"
      :title="$t('exercises.new') + ' ' + $t('shortcuts.new')"
      :aria-label="$t('exercises.new')"
      @click="goToNew"
    >
      <i class="bi bi-plus-lg"></i>
    </button>
  </Teleport>

  <div class="exercise-list-view">
    <!-- Search bar -->
    <div v-if="searching" class="search-bar" data-testid="exercise-search-bar">
      <input
        ref="searchInput"
        v-model="searchQuery"
        type="text"
        :placeholder="$t('exercises.searchPlaceholder')"
        data-testid="exercise-search-input"
        @blur="onSearchBlur"
      />
      <button
        v-if="searchQuery"
        type="button"
        class="search-clear-btn"
        data-testid="exercise-search-clear"
        :title="$t('common.clearSearch')"
        :aria-label="$t('common.clearSearch')"
        @mousedown.prevent="clearSearch"
      >
        <i class="bi bi-x-lg"></i>
      </button>
    </div>

    <!-- Loading state -->
    <p v-if="loading" class="text-muted">{{ $t('app.loading') }}</p>

    <!-- Empty state -->
    <p
      v-else-if="exercises.length === 0 && !searchQuery.trim()"
      class="text-muted"
      data-testid="exercise-empty"
    >
      {{ $t('exercises.empty') }}
    </p>

    <!-- No search results -->
    <p
      v-else-if="exercises.length === 0 && searchQuery.trim()"
      class="text-muted"
      data-testid="exercise-no-results"
    >
      {{ $t('exercises.noResults') }}
    </p>

    <!-- Exercise cards -->
    <div
      v-for="(exercise, index) in exercises"
      :key="exercise.id"
      class="card exercise-card"
      :class="{ 'card-focused': focusedExerciseIndex === index }"
      :data-testid="'exercise-card-' + exercise.id"
      :data-list-index="index"
      tabindex="0"
      @click="goToDetail(exercise.id)"
    >
      <div class="exercise-card-header">
        <h3 data-testid="exercise-card-title">{{ exercise.title }}</h3>
        <div class="exercise-card-badges">
          <span v-if="exercise.default_reps" class="badge" data-testid="exercise-card-reps">
            {{ exercise.default_reps }} {{ $t('exercises.reps') }}
          </span>
          <span v-if="exercise.default_weight" class="badge" data-testid="exercise-card-weight">
            {{ exercise.default_weight }} {{ $t('exercises.weight') }}
          </span>
          <span
            v-if="exercise.asymmetric"
            class="badge badge-info"
            data-testid="exercise-card-asymmetric"
          >
            <i class="bi bi-arrow-left-right"></i>
          </span>
        </div>
      </div>
    </div>

    <!-- Import dialog -->
    <ImportDialog
      v-if="showImportDialog && importEnvelope"
      :envelope="importEnvelope"
      :local-uuid="localUuid"
      :as-mine="importAsMine"
      @done="onImportDone"
      @close="onImportClose"
    />
  </div>
</template>

<style scoped>
.exercise-list-view {
  max-width: 800px;
}

.search-bar {
  position: relative;
  margin-bottom: 16px;
}

.search-bar input {
  padding-right: 36px;
}

.search-clear-btn {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  background: none;
  border: none;
  padding: 4px;
  line-height: 1;
  color: var(--front-color2);
  cursor: pointer;
}

.exercise-card {
  cursor: pointer;
  transition: border-color 0.15s;
}

.exercise-card:hover {
  border-color: var(--btn-primary-bg);
}

.exercise-card:focus-visible {
  border-color: var(--btn-primary-bg);
  box-shadow: 0 0 0 2px var(--btn-primary-bg);
  outline: none;
}

.exercise-card.card-focused {
  border-color: var(--btn-primary-bg);
  box-shadow: 0 0 0 2px var(--btn-primary-bg);
}

.exercise-card-header {
  display: flex;
  align-items: center;
  gap: 8px;
}

.exercise-card-header h3 {
  flex: 1;
  font-size: 16px;
  font-weight: 600;
}

.exercise-card-badges {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 12px;
  font-size: 12px;
  background-color: var(--btn-primary-bg);
  color: var(--btn-primary-color);
  white-space: nowrap;
}

.badge-info {
  background-color: var(--front-color2);
}
</style>
