<template>
  <Teleport to="body">
    <div
      v-if="show"
      class="lightbox-backdrop"
      @click.self="close"
      @keydown="onKeydown"
      tabindex="0"
      ref="backdropEl"
    >
      <!-- Close button -->
      <button class="lightbox-close" @click="close">
        <svg class="w-6 h-6" 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>

      <!-- Counter -->
      <div v-if="mediaItems.length > 1" class="lightbox-counter">
        {{ currentIndex + 1 }} / {{ mediaItems.length }}
      </div>

      <!-- Previous button -->
      <button
        v-if="mediaItems.length > 1"
        class="lightbox-nav lightbox-nav-prev"
        @click.stop="prev"
      >
        <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
        </svg>
      </button>

      <!-- Next button -->
      <button
        v-if="mediaItems.length > 1"
        class="lightbox-nav lightbox-nav-next"
        @click.stop="next"
      >
        <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
        </svg>
      </button>

      <!-- Media content -->
      <div class="lightbox-content" @click.stop>
        <!-- Loading -->
        <div v-if="loading" class="lightbox-loading">
          <div class="w-10 h-10 border-3 border-white/20 border-t-white/80 rounded-full animate-spin"></div>
        </div>

        <!-- Image -->
        <img
          v-else-if="currentItem && currentUrl && isImageFile(currentItem)"
          :src="currentUrl"
          :alt="currentItem.name"
          class="lightbox-media"
          @error="onMediaError"
        />

        <!-- Video -->
        <video
          v-else-if="currentItem && currentUrl && isVideoFile(currentItem)"
          :src="currentUrl"
          :key="currentUrl"
          class="lightbox-media"
          controls
          autoplay
          @error="onMediaError"
        />

        <!-- Audio -->
        <div
          v-else-if="currentItem && currentUrl && isAudioFile(currentItem)"
          class="flex flex-col items-center justify-center gap-6 p-8"
        >
          <div class="w-32 h-32 rounded-2xl bg-gradient-to-br from-orange-500/20 to-orange-600/10 flex items-center justify-center">
            <svg class="w-16 h-16 text-orange-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3" />
            </svg>
          </div>
          <audio
            :src="currentUrl"
            :key="currentUrl"
            controls
            autoplay
            class="w-full max-w-md"
            @error="onMediaError"
          />
        </div>

        <!-- Error -->
        <div v-else-if="mediaError" class="lightbox-error">
          <p class="text-white/60">Failed to load media</p>
        </div>
      </div>

      <!-- Filename -->
      <div class="lightbox-filename">
        <p class="text-sm text-white/70 truncate max-w-md">{{ currentItem?.name }}</p>
      </div>
    </div>
  </Teleport>
</template>

<script setup lang="ts">
import { ref, computed, watch, onUnmounted, nextTick } from 'vue'
import type { FileBrowserItem } from '@/api/filebrowser-client'
import { getFileCategory } from '@/composables/useFileType'

const props = defineProps<{
  items: FileBrowserItem[]
  startIndex: number
  show: boolean
  fetchBlobUrl: (path: string) => Promise<string>
}>()

const emit = defineEmits<{
  close: []
}>()

const currentIndex = ref(0)
const loading = ref(false)
const mediaError = ref(false)
const currentUrl = ref<string | null>(null)
const backdropEl = ref<HTMLElement | null>(null)

// Cache blob URLs to avoid re-fetching
const urlCache = new Map<string, string>()

const mediaItems = computed(() =>
  props.items.filter(item => {
    const ext = item.name.includes('.') ? item.name.split('.').pop()!.toLowerCase() : ''
    const cat = getFileCategory(ext, item.isDir)
    return cat === 'image' || cat === 'video' || cat === 'audio'
  })
)

const currentItem = computed(() => mediaItems.value[currentIndex.value] ?? null)

function isImageFile(item: FileBrowserItem): boolean {
  const ext = item.name.includes('.') ? item.name.split('.').pop()!.toLowerCase() : ''
  return getFileCategory(ext, false) === 'image'
}

function isVideoFile(item: FileBrowserItem): boolean {
  const ext = item.name.includes('.') ? item.name.split('.').pop()!.toLowerCase() : ''
  return getFileCategory(ext, false) === 'video'
}

function isAudioFile(item: FileBrowserItem): boolean {
  const ext = item.name.includes('.') ? item.name.split('.').pop()!.toLowerCase() : ''
  return getFileCategory(ext, false) === 'audio'
}

async function loadMedia(item: FileBrowserItem) {
  loading.value = true
  mediaError.value = false
  currentUrl.value = null

  try {
    const cached = urlCache.get(item.path)
    if (cached) {
      currentUrl.value = cached
    } else {
      const url = await props.fetchBlobUrl(item.path)
      urlCache.set(item.path, url)
      currentUrl.value = url
    }
  } catch {
    mediaError.value = true
  } finally {
    loading.value = false
  }
}

function preloadAdjacent() {
  const items = mediaItems.value
  if (items.length <= 1) return
  const prevIdx = (currentIndex.value - 1 + items.length) % items.length
  const nextIdx = (currentIndex.value + 1) % items.length

  for (const idx of [prevIdx, nextIdx]) {
    const item = items[idx]
    if (item && !urlCache.has(item.path) && isImageFile(item)) {
      props.fetchBlobUrl(item.path).then(url => {
        urlCache.set(item.path, url)
      }).catch(() => {})
    }
  }
}

function prev() {
  const len = mediaItems.value.length
  if (len <= 1) return
  currentIndex.value = (currentIndex.value - 1 + len) % len
}

function next() {
  const len = mediaItems.value.length
  if (len <= 1) return
  currentIndex.value = (currentIndex.value + 1) % len
}

function close() {
  emit('close')
}

function onMediaError() {
  mediaError.value = true
  loading.value = false
}

function onKeydown(e: KeyboardEvent) {
  if (e.key === 'Escape') {
    e.preventDefault()
    close()
  } else if (e.key === 'ArrowLeft') {
    e.preventDefault()
    prev()
  } else if (e.key === 'ArrowRight') {
    e.preventDefault()
    next()
  }
}

// Load media when current item changes
watch(currentItem, (item) => {
  if (item) {
    loadMedia(item)
    preloadAdjacent()
  }
})

// Initialize when shown
watch(() => props.show, async (visible) => {
  if (visible) {
    currentIndex.value = props.startIndex
    const item = mediaItems.value[props.startIndex]
    if (item) {
      await loadMedia(item)
      preloadAdjacent()
    }
    await nextTick()
    backdropEl.value?.focus()
  }
}, { immediate: true })

// Clean up blob URLs on unmount
onUnmounted(() => {
  for (const url of urlCache.values()) {
    URL.revokeObjectURL(url)
  }
  urlCache.clear()
})
</script>
