<template>
  <Modal :open="open" size="xl" :title="title" :subtitle="subtitle" @close="$emit('close')">
    <div class="grid gap-4 md:grid-cols-4">
      <div class="rounded-2xl border border-violet-100 bg-violet-50/60 px-4 py-3">
        <p class="text-[10px] font-semibold uppercase tracking-[0.14em] text-violet-500">Unterkategorien</p>
        <strong class="mt-2 block text-2xl text-violet-900">{{ categories.length }}</strong>
      </div>
      <div class="rounded-2xl border border-emerald-100 bg-emerald-50/70 px-4 py-3">
        <p class="text-[10px] font-semibold uppercase tracking-[0.14em] text-emerald-600">Kandidaten</p>
        <strong class="mt-2 block text-2xl text-emerald-800">{{ candidates.length }}</strong>
      </div>
      <div class="rounded-2xl border border-amber-100 bg-amber-50/70 px-4 py-3">
        <p class="text-[10px] font-semibold uppercase tracking-[0.14em] text-amber-600">Nominierungen</p>
        <strong class="mt-2 block text-2xl text-amber-800">{{ nominations.length }}</strong>
      </div>
      <div class="rounded-2xl border border-sky-100 bg-sky-50/70 px-4 py-3">
        <p class="text-[10px] font-semibold uppercase tracking-[0.14em] text-sky-600">Nominierer</p>
        <strong class="mt-2 block text-2xl text-sky-800">{{ totalNominatorCount }}</strong>
      </div>
    </div>

    <div v-if="readinessItems.length > 0" class="mt-4 grid gap-2">
      <article
        v-for="item in readinessItems"
        :key="item.category.id"
        class="flex flex-wrap items-center justify-between gap-3 rounded-2xl border px-4 py-3"
        :class="item.isReady ? 'border-emerald-100 bg-emerald-50/70' : 'border-sky-100 bg-sky-50/70'"
      >
        <div class="min-w-0">
          <p class="truncate text-sm font-semibold" :class="item.isReady ? 'text-emerald-900' : 'text-sky-900'">
            {{ item.category.groupName }} · {{ item.category.name }}
          </p>
          <p class="mt-1 text-xs" :class="item.isReady ? 'text-emerald-700' : 'text-sky-700'">
            {{ item.nominatorCount }} von {{ readinessTargetLabel }} Nominierern erreicht. Hinweis, kein Blocker.
          </p>
        </div>
        <span class="rounded-full px-3 py-1 text-xs font-semibold" :class="item.isReady ? 'bg-emerald-100 text-emerald-700' : 'bg-white/80 text-sky-700'">
          {{ item.isReady ? 'Bereit' : 'Aufbau' }}
        </span>
      </article>
    </div>

    <div class="mt-5 grid gap-5 lg:grid-cols-[0.82fr_1.18fr]">
      <section class="space-y-3">
        <div>
          <p class="text-xs font-semibold uppercase tracking-[0.18em] text-violet-500">Tree-Ausschnitt</p>
          <p class="mt-1 text-sm text-slate-500">Aktuelle Struktur und Belegung.</p>
        </div>
        <article
          v-for="category in categories"
          :key="category.id"
          class="rounded-2xl border border-violet-100 bg-white px-4 py-4"
        >
          <div class="flex items-start justify-between gap-3">
            <div class="min-w-0">
              <p class="truncate font-semibold text-slate-900">{{ category.name }}</p>
              <p class="mt-1 font-mono text-xs text-slate-400">/{{ category.slug }}</p>
            </div>
            <span class="shrink-0 rounded-full bg-violet-50 px-2.5 py-1 text-[11px] font-semibold text-violet-700">
              {{ formatViewerRange(category.viewerRangeMin, category.viewerRangeMax) }}
            </span>
          </div>
          <div class="mt-3 flex flex-wrap gap-2">
            <span class="rounded-full bg-emerald-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-emerald-700">
              {{ category.candidateCount }} Kandidaten
            </span>
            <span class="rounded-full bg-amber-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-amber-700">
              {{ category.pendingCount }} Reviews
            </span>
            <span class="rounded-full bg-sky-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-sky-700">
              {{ category.nominatorCount }}/{{ readinessTargetLabel }} Nominierer
            </span>
          </div>
        </article>
      </section>

      <section class="space-y-5">
        <div>
          <div class="flex flex-wrap items-end justify-between gap-3">
            <div>
              <p class="text-xs font-semibold uppercase tracking-[0.18em] text-violet-500">Nominierungs-Leaderboard</p>
              <p class="mt-1 text-sm text-slate-500">Standard: viele Nominierungen vor wenigen Nominierungen.</p>
            </div>
            <span class="rounded-full bg-violet-50 px-3 py-1 text-xs font-semibold text-violet-700">
              {{ filteredLeaderboardRows.length }} Einträge
            </span>
          </div>

          <div class="mt-3 grid gap-2 md:grid-cols-[minmax(0,1fr)_auto_auto]">
            <label class="block">
              <span class="sr-only">Leaderboard filtern</span>
              <input
                v-model="leaderboardQuery"
                class="h-10 w-full rounded-2xl border border-violet-200 bg-white px-3 text-sm outline-none transition focus:border-violet-400 focus:ring-4 focus:ring-violet-100"
                placeholder="Streamer, Link oder Plattform filtern"
              />
            </label>
            <select
              v-model="leaderboardStatusFilter"
              class="h-10 rounded-2xl border border-violet-200 bg-white px-3 text-sm font-semibold text-slate-600 outline-none transition focus:border-violet-400 focus:ring-4 focus:ring-violet-100"
            >
              <option value="all">Alle Status</option>
              <option value="pending">Offen</option>
              <option value="approved">Übernommen</option>
              <option value="rejected">Verworfen</option>
              <option value="candidate">Kandidaten</option>
            </select>
            <select
              v-model="leaderboardSort"
              class="h-10 rounded-2xl border border-violet-200 bg-white px-3 text-sm font-semibold text-slate-600 outline-none transition focus:border-violet-400 focus:ring-4 focus:ring-violet-100"
            >
              <option value="votes-desc">Viele Votes</option>
              <option value="votes-asc">Wenige Votes</option>
              <option value="name-asc">Name A-Z</option>
              <option value="recent-desc">Neueste</option>
            </select>
          </div>
        </div>

        <div v-if="filteredLeaderboardRows.length > 0" class="grid gap-2">
          <article
            v-for="(row, index) in filteredLeaderboardRows"
            :key="row.key"
            class="rounded-2xl border border-violet-100 bg-white px-4 py-3"
          >
            <div class="grid gap-3 sm:grid-cols-[auto_minmax(0,1fr)_auto] sm:items-center">
              <span class="grid h-9 w-9 place-items-center rounded-xl bg-violet-50 text-sm font-black text-violet-700">
                #{{ index + 1 }}
              </span>
              <div class="min-w-0">
                <p class="truncate font-semibold text-slate-900">{{ row.label }}</p>
                <p class="mt-1 truncate text-xs text-slate-500">
                  {{ row.platform || 'Plattform offen' }} · {{ row.url || 'kein Link' }}
                </p>
                <div class="mt-2 flex flex-wrap gap-2">
                  <span
                    v-for="status in row.statuses"
                    :key="`${row.key}-${status}`"
                    class="rounded-full px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em]"
                    :class="statusBadgeClass(status)"
                  >
                    {{ statusLabel(status) }}
                  </span>
                </div>
              </div>
              <div class="sm:text-right">
                <strong class="block text-2xl text-violet-900">{{ row.voteCount }}</strong>
                <span class="text-[11px] font-semibold uppercase tracking-[0.14em] text-violet-500">Nominierer</span>
                <p class="mt-1 text-xs text-slate-500">{{ row.nominationCount }} Einreichungen</p>
              </div>
            </div>
          </article>
        </div>
        <p v-else class="rounded-2xl border border-dashed border-violet-200 bg-violet-50/40 px-4 py-5 text-sm text-slate-500">
          Keine Leaderboard-Einträge passen zum Filter.
        </p>

        <div>
          <p class="text-xs font-semibold uppercase tracking-[0.18em] text-violet-500">Kandidaten</p>
          <p class="mt-1 text-sm text-slate-500">Finale und vorbereitete Kandidaten in diesem Ausschnitt.</p>
        </div>
        <div v-if="candidates.length > 0" class="grid gap-2">
          <article
            v-for="candidate in candidates"
            :key="candidate.id"
            class="rounded-2xl border border-violet-100 bg-white px-4 py-3"
          >
            <div class="flex items-start justify-between gap-3">
              <div class="min-w-0">
                <p class="truncate font-semibold text-slate-900">{{ candidate.displayName }}</p>
                <p class="mt-1 truncate text-xs text-slate-500">{{ candidate.platform }} · {{ candidate.channelSlug }}</p>
              </div>
              <span class="rounded-full bg-violet-50 px-2.5 py-1 text-[11px] font-semibold text-violet-700">
                {{ candidate.nominationTally }}x
              </span>
            </div>
          </article>
        </div>
        <p v-else class="rounded-2xl border border-dashed border-violet-200 bg-violet-50/40 px-4 py-5 text-sm text-slate-500">
          Noch keine Kandidaten in diesem Ausschnitt.
        </p>

        <div>
          <p class="text-xs font-semibold uppercase tracking-[0.18em] text-violet-500">Roh-Nominierungen</p>
          <p class="mt-1 text-sm text-slate-500">Offene und bereits gepruefte Einreichungen zur Kontrolle.</p>
        </div>
        <div v-if="nominations.length > 0" class="grid gap-2">
          <article
            v-for="nomination in nominations"
            :key="nomination.id"
            class="rounded-2xl border border-violet-100 bg-white px-4 py-3"
          >
            <div class="flex items-start justify-between gap-3">
              <div class="min-w-0">
                <p class="truncate font-semibold text-slate-900">{{ nomination.resolvedChannel || nomination.candidateText || 'Ohne Namen' }}</p>
                <p class="mt-1 truncate text-xs text-slate-500">{{ nomination.streamUrl || nomination.categoryGroupName }}</p>
              </div>
              <span class="rounded-full px-2.5 py-1 text-[11px] font-semibold" :class="nomination.status === 'pending' ? 'bg-amber-50 text-amber-700' : 'bg-slate-100 text-slate-600'">
                {{ nomination.status }}
              </span>
            </div>
          </article>
        </div>
        <p v-else class="rounded-2xl border border-dashed border-violet-200 bg-violet-50/40 px-4 py-5 text-sm text-slate-500">
          Keine Nominierungen in diesem Ausschnitt.
        </p>
      </section>
    </div>

    <template #footer>
      <Button variant="ghost" @click="$emit('close')">Schliessen</Button>
    </template>
  </Modal>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import type { AdminCandidateItem, AdminNominationReviewItem } from '../../types/awards'
import Button from '../ui/Button.vue'
import Modal from '../ui/Modal.vue'
import type { AdminCategoryGroupSummary } from './useAdminCategoryManager'
import { formatViewerRange } from './useAdminCategoryManager'

const props = defineProps<{
  open: boolean
  title: string
  subtitle: string
  categories: AdminCategoryGroupSummary['categories']
  candidates: AdminCandidateItem[]
  nominations: AdminNominationReviewItem[]
  recommendedNominatorTarget: number | null
}>()

defineEmits<{
  close: []
}>()

type LeaderboardStatus = 'pending' | 'approved' | 'rejected' | 'candidate' | string
type LeaderboardStatusFilter = 'all' | 'pending' | 'approved' | 'rejected' | 'candidate'
type LeaderboardSort = 'votes-desc' | 'votes-asc' | 'name-asc' | 'recent-desc'

interface LeaderboardRow {
  key: string
  label: string
  platform: string
  url: string
  voteCount: number
  nominationCount: number
  latestCreatedAt: string
  statuses: LeaderboardStatus[]
  nominatorKeys: string[]
  searchText: string
}

const leaderboardQuery = ref('')
const leaderboardStatusFilter = ref<LeaderboardStatusFilter>('all')
const leaderboardSort = ref<LeaderboardSort>('votes-desc')

const totalNominatorCount = computed(() => uniqueNominatorCount(props.nominations))
const readinessTargetLabel = computed(() => props.recommendedNominatorTarget === null ? '' : String(props.recommendedNominatorTarget))

const readinessItems = computed(() =>
  props.recommendedNominatorTarget === null
    ? []
    : props.categories.map((category) => {
      const target = props.recommendedNominatorTarget ?? 0
      const nominations = props.nominations.filter((nomination) =>
        (nomination.categoryId !== null && nomination.categoryId === category.id)
        || (nomination.suggestedCategoryId !== null && nomination.suggestedCategoryId === category.id),
      )
      const nominatorCount = uniqueNominatorCount(nominations)
      return {
        category,
        nominatorCount,
        isReady: nominatorCount >= target,
      }
    }),
)

const leaderboardRows = computed<LeaderboardRow[]>(() => {
  const rows = new Map<string, LeaderboardRow>()

  for (const nomination of props.nominations) {
    const key = nominationKey(nomination)
    const existing = rows.get(key)
    const label = nomination.resolvedChannel || nomination.candidateDisplayName || nomination.candidateText || nomination.streamUrl || 'Ohne Namen'
    const platform = nomination.resolvedPlatform || ''
    const url = nomination.streamUrl || ''
    const status = nomination.status || 'pending'
    const createdAt = nomination.createdAt || ''
    const row = existing ?? {
      key,
      label,
      platform,
      url,
      voteCount: 0,
      nominationCount: 0,
      latestCreatedAt: createdAt,
      statuses: [],
      nominatorKeys: [],
      searchText: '',
    }

    row.nominationCount += 1
    const nominatorKey = nomination.submittedByTwitchId.trim().toLowerCase()
    if (nominatorKey && !row.nominatorKeys.includes(nominatorKey)) {
      row.nominatorKeys.push(nominatorKey)
    }
    row.voteCount = Math.max(row.voteCount, row.nominatorKeys.length)
    if (!row.statuses.includes(status)) row.statuses.push(status)
    if (createdAt && (!row.latestCreatedAt || createdAt > row.latestCreatedAt)) row.latestCreatedAt = createdAt
    row.searchText = [row.label, row.platform, row.url, row.statuses.join(' ')].join(' ').toLowerCase()
    rows.set(key, row)
  }

  for (const candidate of props.candidates) {
    const key = candidateKey(candidate)
    const existing = rows.get(key)
    const row = existing ?? {
      key,
      label: candidate.displayName,
      platform: candidate.platform,
      url: candidate.channelSlug,
      voteCount: 0,
      nominationCount: 0,
      latestCreatedAt: '',
      statuses: [],
      nominatorKeys: [],
      searchText: '',
    }

    row.label = row.label || candidate.displayName
    row.platform = row.platform || candidate.platform
    row.url = row.url || candidate.channelSlug
    row.voteCount = Math.max(row.voteCount, candidate.nominationTally)
    if (!row.statuses.includes('candidate')) row.statuses.push('candidate')
    row.searchText = [row.label, row.platform, row.url, row.statuses.join(' ')].join(' ').toLowerCase()
    rows.set(key, row)
  }

  return [...rows.values()]
})

const filteredLeaderboardRows = computed(() => {
  const search = leaderboardQuery.value.trim().toLowerCase()
  const statusFilter = leaderboardStatusFilter.value
  const filtered = leaderboardRows.value.filter((row) =>
    (!search || row.searchText.includes(search))
    && (statusFilter === 'all' || row.statuses.includes(statusFilter)),
  )

  return filtered.sort((left, right) => {
    if (leaderboardSort.value === 'votes-asc') return left.voteCount - right.voteCount || left.nominationCount - right.nominationCount || left.label.localeCompare(right.label, 'de')
    if (leaderboardSort.value === 'name-asc') return left.label.localeCompare(right.label, 'de')
    if (leaderboardSort.value === 'recent-desc') return right.latestCreatedAt.localeCompare(left.latestCreatedAt) || right.voteCount - left.voteCount || right.nominationCount - left.nominationCount
    return right.voteCount - left.voteCount || right.nominationCount - left.nominationCount || left.label.localeCompare(right.label, 'de')
  })
})

function nominationKey(nomination: AdminNominationReviewItem) {
  if (nomination.streamerIdentityId !== null) return `identity:${nomination.streamerIdentityId}`
  const channel = (nomination.resolvedChannel || nomination.candidateText || '').trim().toLowerCase()
  if (channel) return `channel:${channel}`
  const url = (nomination.streamUrl || '').trim().toLowerCase()
  if (url) return `url:${url}`
  return `nomination:${nomination.id}`
}

function candidateKey(candidate: AdminCandidateItem) {
  if (candidate.streamerIdentityId !== null) return `identity:${candidate.streamerIdentityId}`
  const channel = candidate.channelSlug.trim().replace(/^@+/, '').toLowerCase()
  if (channel) return `channel:${channel}`
  return `candidate:${candidate.id}`
}

function uniqueNominatorCount(nominations: AdminNominationReviewItem[]) {
  return new Set(nominations.map((nomination) => nomination.submittedByTwitchId.trim().toLowerCase()).filter(Boolean)).size
}

function statusLabel(status: LeaderboardStatus) {
  if (status === 'pending') return 'offen'
  if (status === 'approved') return 'übernommen'
  if (status === 'rejected') return 'verworfen'
  if (status === 'candidate') return 'Kandidat'
  return status
}

function statusBadgeClass(status: LeaderboardStatus) {
  if (status === 'pending') return 'bg-amber-50 text-amber-700'
  if (status === 'approved' || status === 'candidate') return 'bg-emerald-50 text-emerald-700'
  if (status === 'rejected') return 'bg-rose-50 text-rose-700'
  return 'bg-slate-100 text-slate-600'
}
</script>
