import { computed, reactive, ref, watch } from 'vue'
import { CheckCircle2, Clock3, ListChecks, Trophy } from '@lucide/vue'
import { useRoute } from 'vue-router'

import { buildClipEmbed } from '../../lib/clipEmbeds'
import { useAwardsStore } from '../../stores/awards'
import type { AdminAwardResultItem, AdminCandidateItem, AdminCategoryItem, AdminVotingCandidateRank, AdminWorkflowRule } from '../../types/awards'
import { buildAdminReadinessScope, phaseLabel } from './adminReadinessPhase'

const allFilter = 'all'
const maxWinnerPlacementsRuleKey = 'max_winner_placements'
const winnerRequiresClipRuleKey = 'winner_requires_clip'

export type WinnerRuleNotice = {
  mode: 'warn' | 'block'
  message: string
}

export type WinnerIdentitySummary = {
  appearances: number
  acceptedAppearances: number
  winnerPlacements: number
  nominationTally: number
  hasClip: boolean
}

export type WinnerClipPreview = {
  clipUrl: string | null
  clipTitle: string
  clipPlatform: string
  clipEmbedUrl: string | null
  clipEmbedTitle: string
  clipEmbedStatus: string
}

export type WinnerVotingRank = Pick<AdminVotingCandidateRank, 'candidateId' | 'votes' | 'voteSharePercent' | 'isTopTie'> & {
  rank: number
}

export interface AdminWinnerResultRow {
  category: AdminCategoryItem
  candidates: AdminCandidateItem[]
  topVotingRanks: WinnerVotingRank[]
  existing: AdminAwardResultItem | null
  openReviews: number
  approvedClips: number
  hasPendingReviews: boolean
  isEmptyWarning: boolean
  isEmpty: boolean
  isComplete: boolean
}

export interface AdminWinnerGroupSummary {
  name: string
  sortOrder: number
  totalCategories: number
  completedCount: number
  missingCount: number
  pendingReviewCount: number
  emptyCount: number
  approvedClips: number
  categories: AdminWinnerResultRow[]
}

export interface WinnerWorkflowRuleSummary {
  maxWinnerPlacements: AdminWorkflowRule | null
  winnerRequiresClip: AdminWorkflowRule | null
}

export interface WinnerPublicationIssue {
  key: string
  label: string
  note: string
  isWarning: boolean
}

export interface WinnerPublicationState {
  isPublished: boolean
  publishedAtLabel: string
  publishedByLabel: string
  statusLabel: string
  statusTone: string
  phaseLabel: string
  canPublish: boolean
  issues: WinnerPublicationIssue[]
}

export function useAdminWinnersManager() {
  const store = useAwardsStore()
  const route = useRoute()
  const savingResultForCategory = ref<number | null>(null)
  const deletingResultId = ref<number | null>(null)
  const publishingWinners = ref(false)
  const unpublishingWinners = ref(false)
  const adminMessage = ref('')
  const adminError = ref('')
  const query = ref('')
  const statusFilter = ref(allFilter)
  const selectedGroupName = ref<string | null>(null)
  const focusedCategoryId = ref<number | null>(null)
  const winnerSelections = reactive<Record<number, string>>({})

  const seasonDetail = computed(() => store.adminSeasonDetail)
  const workflowRules = computed(() => store.adminWorkflowRules.rules)
  const readinessScope = computed(() => buildAdminReadinessScope(seasonDetail.value))
  const resultMap = computed(() => new Map(seasonDetail.value.results.map((result) => [result.categoryId, result])))
  const selectedCandidateMap = computed(() => new Map(seasonDetail.value.candidates.map((candidate) => [candidate.id, candidate])))
  const workflowRuleSummary = computed<WinnerWorkflowRuleSummary>(() => {
    const maxWinnerRule = findWorkflowRule(maxWinnerPlacementsRuleKey)
    const clipRule = findWorkflowRule(winnerRequiresClipRuleKey)
    return {
      maxWinnerPlacements: maxWinnerRule,
      winnerRequiresClip: clipRule,
    }
  })

  function findWorkflowRule(ruleKey: string): AdminWorkflowRule | null {
    return workflowRules.value.find((rule) => rule.key === ruleKey) ?? null
  }

  function candidateIdentityKey(candidate: Pick<AdminCandidateItem, 'displayName' | 'channelSlug'> & { streamerIdentityId?: number | null }) {
    if ('streamerIdentityId' in candidate && typeof candidate.streamerIdentityId === 'number') {
      return `identity:${candidate.streamerIdentityId}`
    }
    const channel = candidate.channelSlug.trim().replace(/^@+/, '').toLowerCase()
    return channel ? `slug:${channel}` : `name:${candidate.displayName.trim().toLowerCase()}`
  }

  function formatDateTime(value?: string | null) {
    if (!value) return 'Noch nicht veröffentlicht'
    const parsed = new Date(value)
    if (Number.isNaN(parsed.getTime())) return value
    return parsed.toLocaleString('de-DE', {
      day: '2-digit',
      month: '2-digit',
      year: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
    })
  }

  function selectedWinnerIdentitySummary(categoryId: number): WinnerIdentitySummary | null {
    const candidateId = Number(winnerSelections[categoryId])
    const selectedCandidate = selectedCandidateMap.value.get(candidateId)
    if (!selectedCandidate) {
      return null
    }

    const sameIdentityCandidates = seasonDetail.value.candidates.filter((candidate) =>
      candidateIdentityKey(candidate) === candidateIdentityKey(selectedCandidate),
    )
    const winnerCandidateIds = new Set(seasonDetail.value.results.map((result) => result.candidateId))

    return {
      appearances: sameIdentityCandidates.filter((candidate) => candidate.acceptanceStatus !== 'declined').length,
      acceptedAppearances: sameIdentityCandidates.filter((candidate) => candidate.acceptanceStatus === 'accepted').length,
      winnerPlacements: sameIdentityCandidates.filter((candidate) => winnerCandidateIds.has(candidate.id)).length,
      nominationTally: Math.max(...sameIdentityCandidates.map((candidate) => candidate.nominationTally ?? 0), 0),
      hasClip: Boolean(selectedCandidate.clipCompilationUrl?.trim()),
    }
  }

  function winnerRuleNoticeFor(categoryId: number): WinnerRuleNotice | null {
    const candidateId = Number(winnerSelections[categoryId])
    const selectedCandidate = selectedCandidateMap.value.get(candidateId)
    if (!selectedCandidate) return null

    const clipRule = findWorkflowRule(winnerRequiresClipRuleKey)
    if (clipRule?.enabled && !selectedCandidate.clipCompilationUrl?.trim()) {
      const mode = clipRule.mode === 'warn' ? 'warn' : 'block'
      return {
        mode,
        message: 'Dieser Kandidat hat noch keinen Clip-Link. Bitte in der Kandidatenvorbereitung eine YouTube-/Twitch-Compilation pflegen.',
      }
    }

    const rule = findWorkflowRule(maxWinnerPlacementsRuleKey)
    if (!rule?.enabled) return null

    const identityKey = candidateIdentityKey(selectedCandidate)
    const existingWinnerCount = seasonDetail.value.results.filter((result) => {
      if (result.categoryId === categoryId) return false
      return candidateIdentityKey({
        streamerIdentityId: result.streamerIdentityId,
        displayName: result.candidateDisplayName,
        channelSlug: result.candidateChannelSlug,
      }) === identityKey
    }).length

    if (existingWinnerCount < rule.limit) return null

    const mode = rule.mode === 'warn' ? 'warn' : 'block'
    return {
      mode,
      message: `Diese Person hat bereits ${existingWinnerCount} Gewinnerplatz(e). Limit: ${rule.limit}.`,
    }
  }

  function selectedWinnerClipPreview(categoryId: number): WinnerClipPreview | null {
    const candidateId = Number(winnerSelections[categoryId])
    const selectedCandidate = selectedCandidateMap.value.get(candidateId)
    if (!selectedCandidate) {
      return null
    }

    const clipUrl = selectedCandidate.clipCompilationUrl?.trim() || null
    const clipTitle = selectedCandidate.clipCompilationTitle?.trim() || 'Clip-Link ansehen'
    const clipPlatform = selectedCandidate.clipCompilationPlatform?.trim() || selectedCandidate.platform
    const clipEmbed = clipUrl && selectedCandidate.clipEmbedStatus !== 'link_only' && selectedCandidate.clipEmbedStatus !== 'blocked'
      ? buildClipEmbed(clipUrl)
      : null

    return {
      clipUrl,
      clipTitle,
      clipPlatform,
      clipEmbedUrl: clipEmbed?.src ?? null,
      clipEmbedTitle: clipEmbed?.title ?? clipTitle,
      clipEmbedStatus: selectedCandidate.clipEmbedStatus || 'unchecked',
    }
  }

  const resultRows = computed<AdminWinnerResultRow[]>(() =>
    seasonDetail.value.categories
      .map((category) => {
        const candidates = seasonDetail.value.candidates
          .filter((candidate) => candidate.categoryId === category.id)
          .sort((a, b) => a.displayName.localeCompare(b.displayName))
        const existing = resultMap.value.get(category.id) ?? null
        const openReviews = seasonDetail.value.pendingNominations.filter((nomination) =>
          nomination.categoryId === category.id
          || nomination.suggestedCategoryId === category.id,
        ).length
        const approvedClips = seasonDetail.value.clipSubmissions.filter((clip) => clip.categoryId === category.id && clip.status === 'approved').length
        const topVotingRanks = seasonDetail.value.votingWorkspace.categories
          .find((item) => item.categoryId === category.id)
          ?.leaderboard
          .slice(0, 5)
          .map((candidate, index) => ({
            candidateId: candidate.candidateId,
            votes: candidate.votes,
            voteSharePercent: candidate.voteSharePercent,
            isTopTie: candidate.isTopTie,
            rank: index + 1,
          })) ?? []

        return {
          category,
          candidates,
          topVotingRanks,
          existing,
          openReviews,
          approvedClips,
          hasPendingReviews: openReviews > 0 && readinessScope.value.reviewWarningsActive,
          isEmptyWarning: candidates.length === 0 && readinessScope.value.candidateWarningsActive,
          isEmpty: candidates.length === 0,
          isComplete: Boolean(existing),
        }
      })
      .sort((a, b) => a.category.sortOrder - b.category.sortOrder),
  )

  function rowMatchesFilters(row: AdminWinnerResultRow) {
    const matchesStatus = statusFilter.value === allFilter
      || (statusFilter.value === 'open' && !row.isComplete)
      || (statusFilter.value === 'set' && row.isComplete)
      || (statusFilter.value === 'review' && row.hasPendingReviews)
      || (statusFilter.value === 'empty' && row.isEmpty)

    if (!matchesStatus) return false

    const normalizedQuery = query.value.trim().toLowerCase()
    if (!normalizedQuery) return true

    return [
      row.category.name,
      row.category.groupName,
      row.existing?.candidateDisplayName ?? '',
      ...row.candidates.map((candidate) => `${candidate.displayName} ${candidate.channelSlug} ${candidate.platform}`),
    ].some((value) => value.toLowerCase().includes(normalizedQuery))
  }

  const winnerGroups = computed<AdminWinnerGroupSummary[]>(() => {
    const grouped = new Map<string, AdminWinnerResultRow[]>()
    for (const row of resultRows.value) {
      const key = row.category.groupName.trim() || 'Ohne Gruppe'
      const current = grouped.get(key)
      if (current) {
        current.push(row)
      } else {
        grouped.set(key, [row])
      }
    }

    return [...grouped.entries()]
      .map(([name, rows]) => {
        const categories = rows
          .filter((row) => rowMatchesFilters(row))
          .sort((left, right) => left.category.sortOrder - right.category.sortOrder || left.category.name.localeCompare(right.category.name, 'de'))

        if (categories.length === 0) {
          return null
        }

        return {
          name,
          sortOrder: Math.min(...rows.map((row) => row.category.sortOrder)),
          totalCategories: categories.length,
          completedCount: categories.filter((row) => row.isComplete).length,
          missingCount: categories.filter((row) => !row.isComplete).length,
          pendingReviewCount: categories.filter((row) => row.hasPendingReviews).length,
          emptyCount: categories.filter((row) => row.isEmptyWarning).length,
          approvedClips: categories.reduce((sum, row) => sum + row.approvedClips, 0),
          categories,
        } satisfies AdminWinnerGroupSummary
      })
      .filter((group): group is AdminWinnerGroupSummary => group !== null)
      .sort((left, right) => left.sortOrder - right.sortOrder || left.name.localeCompare(right.name, 'de'))
  })

  const selectedGroup = computed(() =>
    winnerGroups.value.find((group) => group.name === selectedGroupName.value)
    ?? winnerGroups.value[0]
    ?? null,
  )

  const selectedGroupRows = computed(() => selectedGroup.value?.categories ?? [])

  const completedCount = computed(() => resultRows.value.filter((row) => row.isComplete).length)
  const missingCount = computed(() => Math.max(0, resultRows.value.length - completedCount.value))
  const reviewWarningCount = computed(() => resultRows.value.filter((row) => row.hasPendingReviews).length)
  const totalOpenReviewCount = computed(() => resultRows.value.reduce((sum, row) => sum + row.openReviews, 0))
  const emptyCount = computed(() => resultRows.value.filter((row) => row.isEmpty).length)
  const completionPct = computed(() => resultRows.value.length === 0 ? 0 : Math.round((completedCount.value / resultRows.value.length) * 100))

  const publicationIssues = computed<WinnerPublicationIssue[]>(() => {
    const issues: WinnerPublicationIssue[] = []
    if (missingCount.value > 0) {
      const isWarning = readinessScope.value.winnerWarningsActive || readinessScope.value.publicationWarningsActive
      issues.push({
        key: 'missing-winners',
        label: isWarning ? `${missingCount.value} Gewinner fehlen` : `${missingCount.value} Gewinner später nötig`,
        note: isWarning
          ? 'Jede Unterkategorie braucht einen gesetzten Gewinner.'
          : 'Für diese Phase ist das neutral; vor der Freigabe braucht jede Unterkategorie einen Gewinner.',
        isWarning,
      })
    }

    if (totalOpenReviewCount.value > 0) {
      const isWarning = readinessScope.value.reviewWarningsActive || readinessScope.value.publicationWarningsActive
      issues.push({
        key: 'open-reviews',
        label: isWarning ? `${totalOpenReviewCount.value} Reviews offen` : `${totalOpenReviewCount.value} Reviews gesammelt`,
        note: isWarning
          ? 'Offene Nominierungs-Reviews müssen vor der Veröffentlichung geklärt sein.'
          : 'In der Nominierung ist das Sammelstand; vor Voting/Freigabe wird es handlungsrelevant.',
        isWarning,
      })
    }

    const clipRule = workflowRuleSummary.value.winnerRequiresClip
    if (clipRule?.enabled && clipRule.mode === 'block') {
      const missingClipCount = seasonDetail.value.results.filter((result) => {
        const candidate = selectedCandidateMap.value.get(result.candidateId)
        return !candidate?.clipCompilationUrl?.trim()
      }).length
      if (missingClipCount > 0) {
        const isWarning = readinessScope.value.phaseKey !== 'nomination' || readinessScope.value.publicationWarningsActive
        issues.push({
          key: 'missing-clips',
          label: isWarning ? `${missingClipCount} Gewinner ohne Clip` : `${missingClipCount} Clips später nötig`,
          note: isWarning
            ? 'Die Workflow-Regel verlangt gepflegte YouTube-/Twitch-Compilation-Links.'
            : 'Clip-Readiness ist für Voting/Freigabe relevant, aber noch kein Nominierungsproblem.',
          isWarning,
        })
      }
    }

    const winnerRule = workflowRuleSummary.value.maxWinnerPlacements
    if (winnerRule?.enabled && winnerRule.mode === 'block') {
      const winnerIdentityCounts = seasonDetail.value.results
        .reduce((map, result) => {
          const key = candidateIdentityKey({
            streamerIdentityId: result.streamerIdentityId,
            displayName: result.candidateDisplayName,
            channelSlug: result.candidateChannelSlug,
          })
          const current = map.get(key)
          if (current) {
            current.count += 1
          } else {
            map.set(key, { count: 1, displayName: result.candidateDisplayName })
          }
          return map
        }, new Map<string, { count: number; displayName: string }>())
      const duplicateWinner = [...winnerIdentityCounts.values()].find((item) => item.count > winnerRule.limit)

      if (duplicateWinner) {
        const isWarning = readinessScope.value.winnerWarningsActive || readinessScope.value.publicationWarningsActive
        issues.push({
          key: 'winner-identity',
          label: isWarning
            ? `${duplicateWinner.displayName} gewinnt ${duplicateWinner.count}x`
            : `${duplicateWinner.displayName} Limit später prüfen`,
          note: isWarning
            ? `Limit laut Workflow-Regel: ${winnerRule.limit}.`
            : `Das Limit wird vor der Gewinnerfreigabe relevant: ${winnerRule.limit}.`,
          isWarning,
        })
      }
    }

    return issues
  })

  const publicationState = computed<WinnerPublicationState>(() => {
    const isPublished = Boolean(seasonDetail.value.winnersPublishedAt)
    return {
      isPublished,
      publishedAtLabel: formatDateTime(seasonDetail.value.winnersPublishedAt),
      publishedByLabel: seasonDetail.value.winnersPublishedByTwitchId ? `von ${seasonDetail.value.winnersPublishedByTwitchId}` : 'ohne Admin-ID',
      statusLabel: isPublished ? 'Öffentlich sichtbar' : 'Intern gespeichert',
      statusTone: isPublished
        ? 'border-emerald-100 bg-emerald-50 text-emerald-800'
        : readinessScope.value.publicationWarningsActive && publicationIssues.value.length === 0
          ? 'border-sky-100 bg-sky-50 text-sky-800'
          : readinessScope.value.publicationWarningsActive
            ? 'border-amber-100 bg-amber-50 text-amber-800'
            : 'border-violet-100 bg-violet-50 text-violet-800',
      phaseLabel: phaseLabel(readinessScope.value.phaseKey),
      canPublish: publicationIssues.value.length === 0 && resultRows.value.length > 0,
      issues: publicationIssues.value,
    }
  })

  const statusFilters = computed(() => [
    { value: allFilter, label: 'Alle', count: resultRows.value.length },
    { value: 'open', label: 'Offen', count: missingCount.value },
    { value: 'set', label: 'Gesetzt', count: completedCount.value },
    { value: 'review', label: 'Reviews offen', count: reviewWarningCount.value },
    { value: 'empty', label: 'Ohne Kandidaten', count: emptyCount.value },
  ])

  const summaryCards = computed(() => [
    {
      label: 'Fortschritt',
      value: `${completionPct.value}%`,
      note: `${completedCount.value} von ${resultRows.value.length} Kategorien final.`,
      icon: Trophy,
      tone: 'border-violet-100 bg-violet-50 text-violet-800',
      progress: completionPct.value,
    },
    {
      label: 'Offen',
      value: String(missingCount.value),
      note: missingCount.value === 0
        ? 'Keine Gewinner fehlen.'
        : readinessScope.value.winnerWarningsActive
          ? 'Diese Kategorien brauchen eine Auswahl.'
          : 'Für diese Phase noch kein Blocker.',
      icon: ListChecks,
      tone: missingCount.value > 0 && readinessScope.value.winnerWarningsActive
        ? 'border-sky-100 bg-sky-50 text-sky-800'
        : missingCount.value > 0
          ? 'border-violet-100 bg-violet-50 text-violet-800'
          : 'border-emerald-100 bg-emerald-50 text-emerald-800',
      progress: null,
    },
    {
      label: 'Reviews',
      value: String(reviewWarningCount.value),
      note: reviewWarningCount.value === 0 ? 'Keine Review-Warnungen.' : 'Vor finaler Freigabe prüfen.',
      icon: Clock3,
      tone: reviewWarningCount.value > 0 ? 'border-amber-100 bg-amber-50 text-amber-800' : 'border-emerald-100 bg-emerald-50 text-emerald-800',
      progress: null,
    },
    {
      label: 'Gesetzt',
      value: String(completedCount.value),
      note: publicationState.value.isPublished ? 'Auf der Landingpage sichtbar.' : 'Intern gespeichert bis zur Veröffentlichung.',
      icon: CheckCircle2,
      tone: 'border-emerald-100 bg-emerald-50 text-emerald-800',
      progress: null,
    },
  ])

  function applyRouteFilters() {
    const rawQuery = Array.isArray(route.query.q) ? route.query.q[0] : route.query.q
    const rawStatus = Array.isArray(route.query.status) ? route.query.status[0] : route.query.status
    const rawCategoryId = Array.isArray(route.query.categoryId) ? route.query.categoryId[0] : route.query.categoryId
    const rawGroup = Array.isArray(route.query.group) ? route.query.group[0] : route.query.group

    query.value = typeof rawQuery === 'string' ? rawQuery : ''
    const nextStatus = typeof rawStatus === 'string' ? rawStatus : allFilter
    statusFilter.value = statusFilters.value.some((option) => option.value === nextStatus) ? nextStatus : allFilter
    const parsedCategoryId = Number(rawCategoryId)
    focusedCategoryId.value = Number.isFinite(parsedCategoryId) && parsedCategoryId > 0 ? parsedCategoryId : null
    if (typeof rawGroup === 'string' && rawGroup.trim()) {
      selectedGroupName.value = rawGroup
      return
    }

    if (focusedCategoryId.value) {
      selectedGroupName.value = resultRows.value.find((row) => row.category.id === focusedCategoryId.value)?.category.groupName ?? null
      return
    }

    selectedGroupName.value = null
  }

  watch(resultRows, (rows) => {
    const knownCategoryIds = new Set(rows.map((row) => row.category.id))
    for (const key of Object.keys(winnerSelections)) {
      if (!knownCategoryIds.has(Number(key))) {
        delete winnerSelections[Number(key)]
      }
    }

    for (const row of rows) {
      winnerSelections[row.category.id] = row.existing?.candidateId ? String(row.existing.candidateId) : ''
    }
  }, { immediate: true })

  watch(winnerGroups, (groups) => {
    if (!groups.some((group) => group.name === selectedGroupName.value)) {
      selectedGroupName.value = groups[0]?.name ?? null
    }
  }, { immediate: true })

  watch(selectedGroupRows, (rows) => {
    if (!rows.some((row) => row.category.id === focusedCategoryId.value)) {
      focusedCategoryId.value = rows[0]?.category.id ?? null
    }
  }, { immediate: true })

  watch(
    () => [route.query.q, route.query.status, route.query.categoryId, route.query.group] as const,
    () => {
      applyRouteFilters()
    },
    { immediate: true },
  )

  function clearFilters() {
    query.value = ''
    statusFilter.value = allFilter
  }

  function selectGroup(groupName: string) {
    selectedGroupName.value = groupName
    focusedCategoryId.value = winnerGroups.value.find((group) => group.name === groupName)?.categories[0]?.category.id ?? null
  }

  function focusCategory(categoryId: number) {
    focusedCategoryId.value = categoryId
    const matchingRow = resultRows.value.find((row) => row.category.id === categoryId)
    if (matchingRow) {
      selectedGroupName.value = matchingRow.category.groupName
    }
  }

  async function saveWinner(categoryId: number) {
    const candidateId = Number(winnerSelections[categoryId])
    if (!candidateId || !seasonDetail.value.id) return
    const ruleNotice = winnerRuleNoticeFor(categoryId)
    if (ruleNotice?.mode === 'block') {
      adminMessage.value = ''
      adminError.value = `Workflow-Regel blockiert: ${ruleNotice.message}`
      return
    }

    savingResultForCategory.value = categoryId
    adminMessage.value = ''
    adminError.value = ''
    try {
      await store.setAdminResult(seasonDetail.value.id, { categoryId, candidateId })
      adminMessage.value = 'Gewinner wurde gespeichert.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Gewinner konnte nicht gespeichert werden.'
    } finally {
      savingResultForCategory.value = null
    }
  }

  async function clearWinner(resultId: number) {
    if (!seasonDetail.value.id) return
    deletingResultId.value = resultId
    adminMessage.value = ''
    adminError.value = ''
    try {
      await store.deleteAdminResult(resultId, seasonDetail.value.id)
      adminMessage.value = 'Gewinner wurde entfernt.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Gewinner konnte nicht entfernt werden.'
    } finally {
      deletingResultId.value = null
    }
  }

  async function publishWinners() {
    if (!seasonDetail.value.id || !publicationState.value.canPublish) return
    publishingWinners.value = true
    adminMessage.value = ''
    adminError.value = ''
    try {
      await store.publishAdminWinners(seasonDetail.value.id)
      adminMessage.value = 'Gewinner wurden auf der Landingpage veröffentlicht.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Gewinner konnten nicht veröffentlicht werden.'
    } finally {
      publishingWinners.value = false
    }
  }

  async function unpublishWinners() {
    if (!seasonDetail.value.id) return
    unpublishingWinners.value = true
    adminMessage.value = ''
    adminError.value = ''
    try {
      await store.unpublishAdminWinners(seasonDetail.value.id)
      adminMessage.value = 'Gewinner wurden von der Landingpage zurückgenommen.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Veröffentlichung konnte nicht zurückgenommen werden.'
    } finally {
      unpublishingWinners.value = false
    }
  }

  return {
    adminError,
    adminMessage,
    completionPct,
    clearFilters,
    deletingResultId,
    focusedCategoryId,
    query,
    publishingWinners,
    savingResultForCategory,
    unpublishingWinners,
    selectedGroup,
    selectedGroupName,
    selectedGroupRows,
    selectGroup,
    focusCategory,
    statusFilter,
    statusFilters,
    summaryCards,
    winnerGroups,
    winnerSelections,
    clearWinner,
    saveWinner,
    workflowRuleSummary,
    publicationState,
    publishWinners,
    unpublishWinners,
    selectedWinnerIdentitySummary,
    selectedWinnerClipPreview,
    winnerRuleNoticeFor,
  }
}
