<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { ClipboardList, Search, Sparkles, Tags, Users, XCircle } from '@lucide/vue'
import { useRoute, useRouter, type LocationQueryRaw } from 'vue-router'

import AdminNominationReviewModal from '../../components/admin/AdminNominationReviewModal.vue'
import AdminPageHeader from '../../components/admin/AdminPageHeader.vue'
import AdminSeasonToolbar from '../../components/admin/AdminSeasonToolbar.vue'
import Card from '../../components/ui/Card.vue'
import PaginationFooter from '../../components/ui/PaginationFooter.vue'
import { useAwardsStore } from '../../stores/awards'

const store = useAwardsStore()
const route = useRoute()
const router = useRouter()
const query = ref('')
const categoryFilter = ref<number | null>(null)
const statusFilter = ref<'all' | 'selected' | 'empty-category' | 'heavy'>('all')
const reviewModalOpen = ref(false)

const seasonDetail = computed(() => store.adminSeasonDetail)
const categoryMap = computed(() => Object.fromEntries(seasonDetail.value.categories.map((category) => [category.id, category])))
const filteredNominations = computed(() => {
  const search = query.value.trim().toLowerCase()
  const heavyCategoryIds = new Set(categoryStats.value.filter((category) => category.pending >= 3).map((category) => category.id))
  return seasonDetail.value.pendingNominations.filter((nomination) => {
    const matchesCategory = !categoryFilter.value || nomination.categoryId === categoryFilter.value
    const category = categoryMap.value[nomination.categoryId]
    const candidateCount = seasonDetail.value.candidates.filter((candidate) => candidate.categoryId === nomination.categoryId).length
    const matchesStatus =
      statusFilter.value === 'all' ||
      (statusFilter.value === 'selected' && !!categoryFilter.value) ||
      (statusFilter.value === 'empty-category' && candidateCount === 0) ||
      (statusFilter.value === 'heavy' && heavyCategoryIds.has(nomination.categoryId))
    const matchesSearch = !search || [nomination.categoryName, nomination.candidateText, nomination.submittedByTwitchId, nomination.streamUrl]
      .join(' ')
      .toLowerCase()
      .includes(search)
    return matchesCategory && matchesStatus && matchesSearch && !!category
  })
})
const categoryStats = computed(() =>
  seasonDetail.value.categories
    .map((category) => ({
      ...category,
      pending: seasonDetail.value.pendingNominations.filter((nomination) => nomination.categoryId === category.id).length,
      candidates: seasonDetail.value.candidates.filter((candidate) => candidate.categoryId === category.id).length,
    }))
    .sort((a, b) => b.pending - a.pending || a.sortOrder - b.sortOrder),
)
const nominationStats = computed(() => [
  { label: 'Offene Nominierungen', value: seasonDetail.value.pendingNominations.length, icon: Sparkles },
  { label: 'Betroffene Kategorien', value: categoryStats.value.filter((category) => category.pending > 0).length, icon: Tags },
  { label: 'Kandidatenbasis', value: seasonDetail.value.candidates.length, icon: Users },
])
const reviewFocusCategories = computed(() => categoryStats.value.filter((category) => category.pending > 0).slice(0, 3))
const statusFilters = computed(() => [
  { key: 'all' as const, label: 'Alle', count: seasonDetail.value.pendingNominations.length },
  { key: 'empty-category' as const, label: 'Ohne Kandidatenbasis', count: seasonDetail.value.pendingNominations.filter((nomination) => !seasonDetail.value.candidates.some((candidate) => candidate.categoryId === nomination.categoryId)).length },
  { key: 'heavy' as const, label: 'Hoher Druck', count: categoryStats.value.filter((category) => category.pending >= 3).reduce((sum, category) => sum + category.pending, 0) },
])

function openReviewModal(nominationId?: number) {
  const nextQuery: LocationQueryRaw = { ...route.query, review: '1' }

  if (nominationId) {
    nextQuery.nominationId = String(nominationId)
  } else {
    delete nextQuery.nominationId
  }

  reviewModalOpen.value = true
  void router.replace({ name: 'admin-nominations', query: nextQuery })
}

const bulkRejecting = ref<number | null>(null)

async function bulkRejectCategory(categoryId: number) {
  if (!store.adminSelectedSeasonId || bulkRejecting.value !== null) return
  const ids = seasonDetail.value.pendingNominations
    .filter((n) => n.categoryId === categoryId)
    .map((n) => n.id)
  if (ids.length === 0) return
  bulkRejecting.value = categoryId
  try {
    await store.bulkRejectAdminNominations(ids, store.adminSelectedSeasonId)
  } finally {
    bulkRejecting.value = null
    categoryFilter.value = null
  }
}

const NOM_PAGE_SIZE = 20
const page = ref(1)
const totalPages = computed(() => Math.max(1, Math.ceil(filteredNominations.value.length / NOM_PAGE_SIZE)))
const pagedNominations = computed(() =>
  filteredNominations.value.slice((page.value - 1) * NOM_PAGE_SIZE, page.value * NOM_PAGE_SIZE),
)
const rangeStart = computed(() =>
  filteredNominations.value.length === 0 ? 0 : (page.value - 1) * NOM_PAGE_SIZE + 1,
)
const rangeEnd = computed(() => Math.min(page.value * NOM_PAGE_SIZE, filteredNominations.value.length))

watch([query, categoryFilter, statusFilter], () => {
  page.value = 1
})
watch(totalPages, (max) => {
  if (page.value > max) page.value = max
})

function closeReviewModal() {
  const restQuery: LocationQueryRaw = { ...route.query }
  delete restQuery.review
  delete restQuery.nominationId

  reviewModalOpen.value = false
  void router.replace({ name: 'admin-nominations', query: restQuery })
}

watch(
  () => [route.query.review, route.query.nominationId] as const,
  ([review, nominationId]) => {
    reviewModalOpen.value = Boolean(review || nominationId)
  },
  { immediate: true },
)
</script>

<template>
  <div class="space-y-6">
    <AdminPageHeader
      eyebrow="Nominierungen"
      description="Nominierungen sichten, Kategorien priorisieren und Review-Fälle fokussiert entscheiden."
      :icon="ClipboardList"
    />

    <AdminSeasonToolbar />

    <section class="grid gap-4 lg:grid-cols-3">
      <Card v-for="stat in nominationStats" :key="stat.label" class="p-5">
        <div class="flex items-start justify-between gap-4">
          <div>
            <p class="text-xs font-semibold uppercase tracking-[0.2em] text-violet-500">{{ stat.label }}</p>
            <strong class="mt-3 block text-4xl text-violet-900">{{ stat.value.toLocaleString('de-DE') }}</strong>
          </div>
          <div class="grid h-11 w-11 place-items-center rounded-2xl bg-violet-100 text-violet-700">
            <component :is="stat.icon" class="h-5 w-5" />
          </div>
        </div>
      </Card>
    </section>

    <Card class="overflow-hidden border-amber-100 bg-amber-50/55">
      <div class="grid gap-5 p-5 lg:grid-cols-[minmax(0,1fr)_auto] lg:items-center">
        <div>
          <p class="text-xs font-semibold uppercase tracking-[0.22em] text-amber-700">Review-Fokus</p>
          <h2 class="mt-1 text-xl font-bold text-slate-900">
            {{ seasonDetail.pendingNominations.length }} offene Entscheidungen
          </h2>
          <p class="mt-2 max-w-3xl text-sm leading-6 text-slate-600">
            Die Nominierungsseite bleibt eine Übersicht. Der Review-Fokus öffnet die Queue mit Entscheidungspanel, ohne die Liste dauerhaft aufzublähen.
          </p>
          <div v-if="reviewFocusCategories.length" class="mt-3 flex flex-wrap gap-2">
            <span
              v-for="category in reviewFocusCategories"
              :key="category.id"
              class="rounded-full border border-amber-200 bg-white/75 px-3 py-1 text-xs font-semibold text-amber-800"
            >
              {{ category.name }} · {{ category.pending }}
            </span>
          </div>
        </div>
        <button
          type="button"
          class="inline-flex h-12 items-center justify-center rounded-2xl bg-violet-600 px-5 text-sm font-semibold text-white shadow-lg shadow-violet-500/20 transition hover:bg-violet-500"
          @click="openReviewModal()"
        >
          Review-Fokus öffnen
        </button>
      </div>
    </Card>

    <section class="grid gap-6 xl:grid-cols-[0.92fr_1.08fr]">
      <Card class="overflow-hidden">
        <div class="border-b border-violet-100 p-5">
          <p class="text-xs font-semibold uppercase tracking-[0.24em] text-violet-500">Kategorien</p>
          <h2 class="mt-1 text-xl font-bold text-slate-900">Wo staut es sich?</h2>
        </div>
        <div class="divide-y divide-violet-50">
          <div
            v-for="category in categoryStats"
            :key="category.id"
            class="group/cat grid grid-cols-[minmax(0,1fr)_auto] items-center gap-3 px-5 py-3 transition hover:bg-violet-50/50"
            :class="categoryFilter === category.id ? 'bg-violet-50/80' : ''"
          >
            <button
              type="button"
              class="min-w-0 text-left"
              @click="categoryFilter = categoryFilter === category.id ? null : category.id"
            >
              <span class="block truncate font-semibold text-slate-900">{{ category.name }}</span>
              <span class="mt-0.5 block truncate text-sm text-slate-500">{{ category.groupName }} · {{ category.candidates }} Kandidaten</span>
            </button>
            <div class="flex shrink-0 items-center gap-2">
              <button
                v-if="category.pending > 0"
                type="button"
                class="hidden h-7 items-center gap-1 rounded-full border border-rose-200 bg-white px-2.5 text-[11px] font-semibold text-rose-600 transition hover:bg-rose-50 disabled:opacity-50 group-hover/cat:flex"
                :disabled="bulkRejecting === category.id"
                :title="`Alle ${category.pending} Nominierungen ablehnen`"
                @click.stop="bulkRejectCategory(category.id)"
              >
                <XCircle class="h-3 w-3" />
                {{ bulkRejecting === category.id ? '…' : 'Alle ablehnen' }}
              </button>
              <span class="rounded-full border border-violet-100 bg-white px-3 py-1 text-sm font-semibold text-violet-800">{{ category.pending }}</span>
            </div>
          </div>
        </div>
      </Card>

      <Card class="overflow-hidden">
        <div class="border-b border-violet-100 p-5">
          <div class="grid gap-3 md:grid-cols-[minmax(0,1fr)_auto]">
            <label class="relative block">
              <Search class="pointer-events-none absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-violet-400" />
              <input
                v-model="query"
                class="h-12 w-full rounded-2xl border border-violet-200 bg-white pl-11 pr-4 text-sm outline-none transition focus:border-violet-400 focus:ring-4 focus:ring-violet-100"
                placeholder="Nach Link, User oder Kategorie suchen"
              />
            </label>
            <button
              type="button"
              class="inline-flex h-12 items-center justify-center rounded-2xl bg-violet-600 px-5 text-sm font-semibold text-white shadow-lg shadow-violet-500/20 transition hover:bg-violet-500"
              @click="openReviewModal()"
            >
              Review-Fokus
            </button>
          </div>
          <div class="mt-3 flex flex-wrap gap-2">
            <button
              v-for="filter in statusFilters"
              :key="filter.key"
              type="button"
              class="rounded-full border px-3 py-1.5 text-xs font-semibold transition"
              :class="statusFilter === filter.key ? 'border-violet-200 bg-violet-100 text-violet-800' : 'border-violet-100 bg-white text-slate-600 hover:bg-violet-50'"
              @click="statusFilter = filter.key"
            >
              {{ filter.label }} · {{ filter.count }}
            </button>
          </div>
        </div>

        <div class="divide-y divide-violet-50">
          <div v-for="nomination in pagedNominations" :key="nomination.id" class="px-5 py-4">
            <div class="flex flex-wrap items-start justify-between gap-3">
              <div class="min-w-0">
                <p class="text-xs font-semibold uppercase tracking-[0.18em] text-violet-500">{{ nomination.categoryName }}</p>
                <h3 class="mt-1 truncate text-lg font-semibold text-slate-900">{{ nomination.candidateText || nomination.streamUrl || 'Name im Review festlegen' }}</h3>
                <p class="mt-1 text-sm text-slate-500">
                  {{ nomination.submittedByTwitchId }} · {{ new Date(nomination.createdAt).toLocaleString('de-DE') }}
                </p>
              </div>
              <span class="rounded-full border border-slate-100 bg-slate-50 px-3 py-1 text-xs font-semibold text-slate-600">
                Limit {{ categoryMap[nomination.categoryId]?.maxNomineesPerUser ?? '-' }}
              </span>
              <span
                v-if="!seasonDetail.candidates.some((candidate) => candidate.categoryId === nomination.categoryId)"
                class="rounded-full border border-amber-100 bg-amber-50 px-3 py-1 text-xs font-semibold text-amber-700"
              >
                erst Kandidatenbasis klären
              </span>
              <button
                type="button"
                class="inline-flex h-9 items-center justify-center rounded-full bg-violet-600 px-4 text-xs font-semibold text-white shadow-sm shadow-violet-500/20 transition hover:bg-violet-500"
                @click="openReviewModal(nomination.id)"
              >
                Fall entscheiden
              </button>
            </div>
          </div>
          <p v-if="filteredNominations.length === 0" class="px-5 py-10 text-center text-sm text-slate-500">
            Keine Nominierungen passen zum aktuellen Filter.
          </p>
        </div>

        <PaginationFooter
          :page="page"
          :total-pages="totalPages"
          :range-start="rangeStart"
          :range-end="rangeEnd"
          :filtered-count="filteredNominations.length"
          @update:page="page = $event"
        />
      </Card>
    </section>

    <AdminNominationReviewModal :open="reviewModalOpen" @close="closeReviewModal" />
  </div>
</template>
