<script setup lang="ts">
/**
 * Collection page component for viewing and filtering owned cards.
 *
 * Displays the user's card collection in a responsive grid with:
 * - Filter bar with search, type, category, and rarity filters
 * - Card count display showing filtered vs total cards
 * - Responsive card grid (2-6 columns based on screen size)
 * - Click-to-view card detail modal
 * - Loading skeleton grid while fetching
 * - Empty state when collection is empty or no matches
 * - Error state with retry capability
 *
 * Filters persist in URL query params for bookmarking/sharing.
 * Search input is debounced for performance.
 */
import { computed, onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useDebounceFn } from '@vueuse/core'

import { useCollection } from '@/composables/useCollection'
import type { CardType, CardCategory, CardDefinition, CollectionCard } from '@/types'

import CardDisplay from '@/components/cards/CardDisplay.vue'
import CardDetailModal from '@/components/cards/CardDetailModal.vue'
import EmptyState from '@/components/ui/EmptyState.vue'
import FilterBar from '@/components/ui/FilterBar.vue'
import SkeletonCard from '@/components/ui/SkeletonCard.vue'

const route = useRoute()
const router = useRouter()

const {
  cards,
  totalCards,
  uniqueCards,
  isLoading,
  error,
  fetchCollection,
  clearError,
  getQuantity,
} = useCollection()

// Filter state - initialized from URL query params
const searchQuery = ref(typeof route.query.q === 'string' ? route.query.q : '')
const selectedType = ref<CardType | null>(
  typeof route.query.type === 'string' ? (route.query.type as CardType) : null
)
const selectedCategory = ref<CardCategory | null>(
  typeof route.query.category === 'string' ? (route.query.category as CardCategory) : null
)
const selectedRarity = ref<CardDefinition['rarity'] | null>(
  typeof route.query.rarity === 'string' ? (route.query.rarity as CardDefinition['rarity']) : null
)

// Internal search state for debouncing
const internalSearch = ref(searchQuery.value)

// Modal state
const selectedCard = ref<CardDefinition | null>(null)
const isModalOpen = ref(false)

/** Number of skeleton cards to show in loading grid */
const SKELETON_COUNT = 12

/**
 * Debounced search update - waits 300ms after typing stops.
 */
const debouncedSearchUpdate = useDebounceFn((value: string) => {
  searchQuery.value = value
}, 300)

/**
 * Handle search input changes - immediately update internal state,
 * debounce the actual filter update.
 */
function onSearchInput(value: string) {
  internalSearch.value = value
  debouncedSearchUpdate(value)
}

/**
 * Filtered cards based on current filter state.
 */
const filteredCards = computed<CollectionCard[]>(() => {
  let result = cards.value

  // Filter by search query (case-insensitive partial match)
  if (searchQuery.value) {
    const query = searchQuery.value.toLowerCase()
    result = result.filter(c =>
      c.card.name.toLowerCase().includes(query)
    )
  }

  // Filter by type
  if (selectedType.value) {
    result = result.filter(c => c.card.type === selectedType.value)
  }

  // Filter by category
  if (selectedCategory.value) {
    result = result.filter(c => c.card.category === selectedCategory.value)
  }

  // Filter by rarity
  if (selectedRarity.value) {
    result = result.filter(c => c.card.rarity === selectedRarity.value)
  }

  return result
})

/**
 * Count display text showing filtered vs total.
 */
const cardCountText = computed(() => {
  const filtered = filteredCards.value.length
  const total = uniqueCards.value

  if (filtered === total) {
    return `${total} unique cards (${totalCards.value} total)`
  }
  return `Showing ${filtered} of ${total} unique cards`
})

/**
 * Update URL query params when filters change.
 */
watch(
  [searchQuery, selectedType, selectedCategory, selectedRarity],
  ([q, type, category, rarity]) => {
    const query: Record<string, string> = {}
    if (q) query.q = q
    if (type) query.type = type
    if (category) query.category = category
    if (rarity) query.rarity = rarity

    router.replace({ query })
  },
  { deep: true }
)

/**
 * Open the card detail modal.
 */
function openCardModal(cardId: string) {
  const collectionCard = cards.value.find(c => c.card.id === cardId)
  if (collectionCard) {
    selectedCard.value = collectionCard.card
    isModalOpen.value = true
  }
}

/**
 * Close the card detail modal.
 */
function closeCardModal() {
  isModalOpen.value = false
  // Delay clearing card to allow exit animation
  setTimeout(() => {
    selectedCard.value = null
  }, 200)
}

/**
 * Retry fetching collection after error.
 */
async function retryFetch() {
  clearError()
  await fetchCollection()
}

// Fetch collection on mount
onMounted(async () => {
  await fetchCollection()
})
</script>

<template>
  <div class="container mx-auto px-4 py-8">
    <!-- Page header -->
    <div class="mb-6">
      <h1 class="text-2xl font-bold text-text mb-2">
        Collection
      </h1>
      <p
        v-if="!isLoading && !error"
        class="text-text-muted"
      >
        {{ cardCountText }}
      </p>
    </div>

    <!-- Filter bar -->
    <FilterBar
      :search="internalSearch"
      :type="selectedType"
      :category="selectedCategory"
      :rarity="selectedRarity"
      search-placeholder="Search cards..."
      @update:search="onSearchInput"
      @update:type="selectedType = $event"
      @update:category="selectedCategory = $event"
      @update:rarity="selectedRarity = $event"
    />

    <!-- Loading state: skeleton grid -->
    <div
      v-if="isLoading"
      class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-3 md:gap-4"
    >
      <SkeletonCard
        v-for="i in SKELETON_COUNT"
        :key="i"
        size="md"
      />
    </div>

    <!-- Error state -->
    <div
      v-else-if="error"
      class="flex items-start gap-3 p-4 bg-error/10 border border-error/20 rounded-xl"
    >
      <svg
        class="w-5 h-5 text-error flex-shrink-0 mt-0.5"
        fill="none"
        stroke="currentColor"
        viewBox="0 0 24 24"
        aria-hidden="true"
      >
        <path
          stroke-linecap="round"
          stroke-linejoin="round"
          stroke-width="2"
          d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
        />
      </svg>
      <div class="flex-1">
        <p class="text-error font-medium">
          Failed to load collection
        </p>
        <p class="text-error/80 text-sm mt-1">
          {{ error }}
        </p>
      </div>
      <button
        class="px-4 py-2 rounded-lg font-medium bg-error text-white hover:bg-error/90 active:scale-95 transition-all duration-150"
        @click="retryFetch"
      >
        Retry
      </button>
    </div>

    <!-- Empty state: no cards in collection -->
    <EmptyState
      v-else-if="cards.length === 0"
      title="Your collection is empty"
      description="Win matches to earn booster packs and grow your collection."
    >
      <template #icon>
        <svg
          class="w-full h-full"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
          aria-hidden="true"
        >
          <path
            stroke-linecap="round"
            stroke-linejoin="round"
            stroke-width="1.5"
            d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"
          />
        </svg>
      </template>
      <template #action>
        <router-link
          to="/play"
          class="px-4 py-2 rounded-lg font-medium bg-primary text-white hover:bg-primary-dark active:scale-95 transition-all duration-150"
        >
          Find a Match
        </router-link>
      </template>
    </EmptyState>

    <!-- Empty state: no cards match filters -->
    <EmptyState
      v-else-if="filteredCards.length === 0"
      title="No cards found"
      description="Try adjusting your filters or search query."
    >
      <template #icon>
        <svg
          class="w-full h-full"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
          aria-hidden="true"
        >
          <path
            stroke-linecap="round"
            stroke-linejoin="round"
            stroke-width="1.5"
            d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
          />
        </svg>
      </template>
    </EmptyState>

    <!-- Card grid -->
    <Transition
      enter-active-class="duration-200 ease-out"
      enter-from-class="opacity-0"
      enter-to-class="opacity-100"
    >
      <div
        v-if="!isLoading && !error && filteredCards.length > 0"
        class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-3 md:gap-4"
      >
        <CardDisplay
          v-for="collectionCard in filteredCards"
          :key="collectionCard.cardDefinitionId"
          :card="collectionCard.card"
          :quantity="collectionCard.quantity"
          size="md"
          @click="openCardModal"
        />
      </div>
    </Transition>

    <!-- Card detail modal -->
    <CardDetailModal
      :card="selectedCard"
      :is-open="isModalOpen"
      :owned-quantity="selectedCard ? getQuantity(selectedCard.id) : 0"
      @close="closeCardModal"
    />
  </div>
</template>
