<template>
  <transition name="fade">
    <div v-if="ui.showSearch" class="fixed inset-0 z-50 flex items-center justify-center transition-all">
      <div class="absolute inset-0 bg-black/60 backdrop-blur-md" @click="close"></div>
      <div
        class="relative w-full max-w-2xl rounded-xl bg-white shadow-xl ring-1 ring-slate-200 dark:bg-slate-900 dark:ring-slate-700"
        role="dialog" aria-modal="true" @keydown.esc.prevent.stop="close">
        <div class="flex items-center gap-2 dark:border-slate-700">
          <svg class="ml-4 h-7 w-7 text-slate-500" viewBox="0 0 24 24" fill="none" stroke="currentColor"
            stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <circle cx="11" cy="11" r="8" />
            <path d="m21 21-4.3-4.3" />
          </svg>
          <input ref="inputRef" v-model="ui.searchQuery" type="text" placeholder="Rechercher boxes, artistes, tracks..."
            class="flex-1 bg-transparent px-2 py-2 text-slate-900 text-3xl placeholder-slate-400 outline-none dark:text-slate-100"
            @keydown.down.prevent="move(1)" @keydown.up.prevent="move(-1)" @keydown.enter.prevent="confirm" />
        </div>

        <div class="max-h-72 overflow-auto results-scroll">
          <template v-if="results.length">
            <ul class="divide-y divide-slate-100 dark:divide-slate-800">
              <li v-for="(resultItem, idx) in results" :key="resultItem.key" :class="[
                'flex cursor-pointer items-center justify-between gap-3 px-2 py-3 hover:bg-slate-50 dark:hover:bg-slate-800',
                idx === activeIndex ? 'bg-slate-100 dark:bg-slate-800' : ''
              ]" @mouseenter="activeIndex = idx" @click="selectResult(resultItem)">
                <div class="flex items-center gap-3">
                  <img v-if="coverUrlFor(resultItem)" :src="coverUrlFor(resultItem)" alt="" loading="lazy"
                    class="h-10 w-10 rounded object-cover ring-1 ring-slate-200 dark:ring-slate-700" />
                  <span
                    class="inline-flex min-w-[68px] items-center justify-center rounded-md border px-2 py-0.5 text-xs font-semibold uppercase text-slate-600 dark:text-slate-300 dark:border-slate-600">{{
                      resultItem.type }}</span>
                  <span class="text-slate-900 dark:text-slate-100">{{ resultItem.label }}</span>
                </div>
                <div class="flex items-center gap-2">
                  <span v-if="resultItem.sublabel" class="text-sm text-slate-500 dark:text-slate-400">{{
                    resultItem.sublabel }}</span>
                </div>
              </li>
            </ul>
          </template>
          <div v-else-if="ui.searchQuery" class="px-2 py-6 text-center text-slate-500 dark:text-slate-400">
            Aucun résultat
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { useUiStore } from '~/store/ui'
import { useDataStore } from '~/store/data'
import { usePlayerStore } from '~/store/player'

const ui = useUiStore()
const data = useDataStore()
const player = usePlayerStore()
const inputRef = ref<HTMLInputElement | null>(null)
const activeIndex = ref(0)

const close = () => ui.closeSearch()

const normalized = (s: string) =>
  s
    .normalize('NFD')
    .replace(/\p{Diacritic}/gu, '')
    .toLowerCase()

type ResultItem = {
  key: string
  type: 'BOX' | 'ARTIST' | 'TRACK'
  label: string
  sublabel?: string
  payload: any
}

const results = computed<ResultItem[]>(() => {
  const q = normalized(ui.searchQuery || '')
  if (!q) return []

  const out: ResultItem[] = []

  for (const b of data.boxes) {
    const label = `${b.id}`
    if (normalized(label).includes(q)) {
      out.push({ key: `box:${b.id}`, type: 'BOX', label, payload: b })
    }
  }
  for (const a of data.artists) {
    if (normalized(a.name).includes(q)) {
      out.push({
        key: `artist:${a.id}`,
        type: 'ARTIST',
        label: a.name,
        payload: a
      })
    }
  }
  for (const track of data.tracks) {
    const artistName =
      typeof track.artist === 'object' && track.artist
        ? ((track.artist as any).name ?? '')
        : String(track.artist)
    const label = track.title
    const sub = artistName
    if (normalized(label).includes(q) || normalized(sub).includes(q)) {
      out.push({ key: `track:${track.id}`, type: 'TRACK', label, sublabel: sub, payload: track })
    }
  }

  return out.slice(0, 100)
})

const move = (delta: number) => {
  if (!results.value.length) return
  activeIndex.value = (activeIndex.value + delta + results.value.length) % results.value.length
}

const coverUrlFor = (ResultItem: ResultItem): string | undefined => {
  if (ResultItem.type === 'BOX') {
    return `/${ResultItem.payload.id}/cover.jpg`
  }
  if (ResultItem.type === 'TRACK') {
    const track = ResultItem.payload
    if (track && track.type === 'playlist' && track.coverId) return track.coverId as string
    if (track && track.coverId) return track.coverId as string
    return `/${track.boxId}/cover.jpg`
  }
  if (ResultItem.type === 'ARTIST') {
    const tracks = data.getTracksByArtistId(ResultItem.payload.id)
    if (tracks && tracks.length) {
      const track = tracks[0]!
      if (track.type === 'playlist' && track.coverId) return track.coverId as string
      if (track.coverId) return track.coverId as string
      return `/${track.boxId}/cover.jpg`
    }
  }
  return undefined
}

const selectResult = (ResultItem: ResultItem) => {
  if (ResultItem.type === 'BOX') {
    ui.selectBox(ResultItem.payload.id)
    nextTick(() => ui.scrollToBox(ResultItem.payload))
  } else if (ResultItem.type === 'ARTIST') {
    const tracks = data.getTracksByArtistId(ResultItem.payload.id)
    if (tracks && tracks.length) {
      const track = tracks[0]!
      const box = data.getBoxById(track.boxId)
      if (box) {
        ui.selectBox(box.id)
      }
    }
  } else if (ResultItem.type === 'TRACK') {
    const track = ResultItem.payload
    const box = data.getBoxById(track.boxId)
    if (box) {
      ui.selectBox(box.id)
      player.playTrack(track)
    }
  }
  close()
}

const confirm = () => {
  const ResultItem = results.value[activeIndex.value]
  if (ResultItem) selectResult(ResultItem)
}

watch(
  () => ui.showSearch,
  async (open) => {
    if (open) {
      activeIndex.value = 0
      await nextTick()
      inputRef.value?.focus()
    }
  }
)
</script>

<style scoped>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.15s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

.results-scroll {
  scrollbar-width: thin;
  scrollbar-color: rgba(100, 116, 139, 0.6) transparent;
}

.results-scroll::-webkit-scrollbar {
  width: 8px;
}

.results-scroll::-webkit-scrollbar-track {
  background: transparent;
}

.results-scroll::-webkit-scrollbar-thumb {
  background-color: rgba(100, 116, 139, 0.6);
  border-radius: 9999px;
  border: 2px solid transparent;
  background-clip: content-box;
}

.dark .results-scroll {
  scrollbar-color: rgba(148, 163, 184, 0.5) transparent;
}

.dark .results-scroll::-webkit-scrollbar-thumb {
  background-color: rgba(148, 163, 184, 0.5);
}
</style>
