import { computed } from 'vue'
import {
  BarChart3,
  CheckCircle2,
  Clock3,
  ExternalLink,
  Film,
  Globe2,
  ShieldAlert,
  Sparkles,
  Tags,
  Trophy,
  Users,
  Vote,
} from '@lucide/vue'

import { getRiskMetricValue, getVoteMetricValue } from '../../lib/adminMetrics'
import { useAwardsStore } from '../../stores/awards'
import { useAuthStore } from '../../stores/auth'
import type { AdminSeasonDetailResponse } from '../../types/awards'
import { buildAdminReadinessScope, phaseLabel } from './adminReadinessPhase'
import {
  createSeasonTimelineRows,
  normalizePhaseKey,
  resolveAutoPhase,
  type PhaseKey,
  type SeasonTimelineForm,
} from './adminSeasonTimeline'

type DashboardState = 'ok' | 'warn' | 'danger' | 'info'
type PublicHealthItem = { label: string; state: DashboardState; note: string; to: string; icon: unknown }

const metricToneMap = {
  Nominierungen: {
    icon: Sparkles,
  },
  Stimmen: {
    icon: BarChart3,
  },
  Kategorien: {
    icon: Tags,
  },
  'Reviews offen': {
    icon: Clock3,
  },
  Risikohinweise: {
    icon: ShieldAlert,
  },
} as const

const phaseEndFields: Record<PhaseKey, keyof Pick<
  AdminSeasonDetailResponse,
  'nominationEndsAt' | 'votingEndsAt' | 'reviewEndsAt' | 'showDate'
>> = {
  nomination: 'nominationEndsAt',
  voting: 'votingEndsAt',
  preparation: 'reviewEndsAt',
  show: 'showDate',
  completed: 'showDate',
}

export function useAdminDashboardOverview() {
  const store = useAwardsStore()
  const authStore = useAuthStore()

  const seasonDetail = computed(() => store.adminSeasonDetail)
  const adminSiteSettings = computed(() => store.adminSiteSettings)
  const metrics = computed(() => store.admin.metrics)
  const activities = computed(() => store.admin.activities)
  const topCategories = computed(() => store.admin.topCategories)
  const readinessScope = computed(() => buildAdminReadinessScope(seasonDetail.value))
  const phaseKey = computed(() => readinessScope.value.phaseKey)
  const adminGreeting = computed(() => {
    const displayName = authStore.session?.displayName?.trim()
    return displayName ? `Hi ${displayName}` : 'Admin-Überblick'
  })

  const metricCards = computed(() =>
    metrics.value.map((metric) => ({
      ...metric,
      ...(metricToneMap[metric.label as keyof typeof metricToneMap] ?? {
        icon: BarChart3,
      }),
    })),
  )
  const openReviewCount = computed(() => seasonDetail.value.pendingNominations.length)
  const openRiskCount = computed(() => getRiskMetricValue(metrics.value))
  const pendingClipCount = computed(() => seasonDetail.value.clipSubmissions.filter((clip) => clip.status === 'pending').length)
  const votingSummary = computed(() => seasonDetail.value.votingWorkspace.summary)
  const missingWinnerCount = computed(() =>
    Math.max(votingSummary.value.totalSubcategories - votingSummary.value.winnerSetSubcategories, 0),
  )
  const streamBannerLinkConfigured = computed(() => Boolean(adminSiteSettings.value.streamBannerLiveButtonUrl.trim()))
  const liveSummary = computed(() => {
    const phase = seasonDetail.value.currentPhase || 'nicht gesetzt'
    const yearLabel = seasonDetail.value.year ? `${seasonDetail.value.year}` : 'kein Jahr'
    const voteText = getVoteMetricValue(metrics.value) === 1 ? '1 Stimme' : `${getVoteMetricValue(metrics.value)} Stimmen`
    const nominationText = metrics.value.find((metric) => metric.label === 'Nominierungen')?.value ?? 0

    return `${yearLabel} · ${phase}. ${nominationText.toLocaleString('de-DE')} Nominierungen, ${voteText} und ${openReviewCount.value.toLocaleString('de-DE')} offene Reviews im gewählten Jahr.`
  })
  const liveStatusTone = computed<DashboardState>(() => {
    if (openRiskCount.value > 0) return 'danger'
    if (readinessScope.value.reviewWarningsActive && openReviewCount.value > 0) return 'warn'
    return 'ok'
  })
  const liveStatusBadge = computed(() => {
    if (openRiskCount.value > 0) return `${openRiskCount.value} Risiko offen`
    if (readinessScope.value.reviewWarningsActive && openReviewCount.value > 0) return `${openReviewCount.value} Review offen`
    return `${phaseLabel(phaseKey.value)} im Blick`
  })
  const topCategoryBasis = computed(() =>
    topCategories.value[0]?.basis || (phaseKey.value === 'nomination' ? 'Nominierungen' : 'Stimmen'),
  )
  const maxCategoryValue = computed(() => Math.max(...topCategories.value.map((category) => category.value), 1))
  const totalCategoryValue = computed(() => topCategories.value.reduce((sum, category) => sum + category.value, 0))
  const topCategoryTitle = computed(() =>
    topCategoryBasis.value.toLowerCase().includes('nomin')
      ? 'Top Kategorien nach Nominierungen'
      : 'Top Kategorien nach Stimmen',
  )
  const topCategoryTotalLabel = computed(() =>
    `${totalCategoryValue.value.toLocaleString('de-DE')} ${topCategoryBasis.value.toLowerCase()} in den Top-Kategorien`,
  )

  const timelineForm = computed<SeasonTimelineForm>(() => ({
    year: seasonDetail.value.year,
    currentPhase: seasonDetail.value.currentPhase,
    nominationStartsAt: seasonDetail.value.nominationStartsAt,
    nominationEndsAt: seasonDetail.value.nominationEndsAt,
    votingStartsAt: seasonDetail.value.votingStartsAt,
    votingEndsAt: seasonDetail.value.votingEndsAt,
    reviewStartsAt: seasonDetail.value.reviewStartsAt,
    reviewEndsAt: seasonDetail.value.reviewEndsAt,
    showDate: seasonDetail.value.showDate,
    showStartsAt: seasonDetail.value.showStartsAt,
  }))
  const autoPhase = computed(() => resolveAutoPhase(timelineForm.value))
  const timelinePhases = computed(() =>
    createSeasonTimelineRows(timelineForm.value, normalizePhaseKey(seasonDetail.value.currentPhase), autoPhase.value, null)
      .filter((phase) => phase.key !== 'completed'),
  )
  const activeCountdown = computed(() => buildCountdownLabel(phaseKey.value, seasonDetail.value[phaseEndFields[phaseKey.value]]))
  const phaseMismatch = computed(() => {
    const auto = autoPhase.value
    if (!auto || phaseKey.value === 'completed') return false
    const currentTitle = timelinePhases.value.find((phase) => phase.key === phaseKey.value)?.title
    return Boolean(currentTitle && auto !== currentTitle)
  })
  const phaseMismatchLabel = computed(() =>
    phaseMismatch.value ? `Zeitplan wirkt wie "${autoPhase.value}", gespeichert ist "${phaseLabel(phaseKey.value)}".` : '',
  )

  const yearTotals = computed(() => [
    {
      label: 'Nominierungen',
      value: metrics.value.find((metric) => metric.label === 'Nominierungen')?.value ?? 0,
      note: `im Award-Jahr ${seasonDetail.value.year}`,
      icon: Sparkles,
    },
    {
      label: 'Stimmen',
      value: getVoteMetricValue(metrics.value),
      note: 'alle abgegebenen Votes',
      icon: BarChart3,
    },
    {
      label: 'Kandidaten',
      value: seasonDetail.value.candidates.length,
      note: 'für Voting und Archiv gepflegt',
      icon: Users,
    },
    {
      label: 'Winner-ready',
      value: votingSummary.value.winnerSetSubcategories,
      note: `${votingSummary.value.totalSubcategories} Unterkategorien insgesamt`,
      icon: Trophy,
    },
  ])

  function canOpenAdminPath(path: string) {
    if (path === '/admin' || path.startsWith('/admin/dashboard')) return authStore.hasPermission('dashboard')
    if (path.startsWith('/admin/years')) return authStore.hasPermission('years')
    if (path.startsWith('/admin/nominations')) return authStore.hasPermission('nominations')
    if (path.startsWith('/admin/risk')) return authStore.hasPermission('risk')
    if (path.startsWith('/admin/categories')) return authStore.hasPermission('categories')
    if (path.startsWith('/admin/candidates')) return authStore.hasPermission('candidates')
    if (path.startsWith('/admin/archive')) return authStore.hasPermission('winners')
    if (path.startsWith('/admin/clips')) return authStore.hasPermission('clips')
    if (path.startsWith('/admin/users-logs')) return authStore.hasPermission('audit')
    if (path.startsWith('/admin/winners')) return authStore.hasPermission('winners')
    if (path.startsWith('/admin/voting')) return authStore.hasPermission('voting')
    if (path.startsWith('/admin/analytics')) return authStore.hasPermission('analytics')
    if (path.startsWith('/admin/content')) return authStore.hasPermission('content')
    if (path.startsWith('/admin/settings')) return authStore.hasPermission('settings')
    if (path.startsWith('/admin/tracking-rules')) return authStore.hasPermission('settings')
    if (path.startsWith('/admin/team')) return authStore.hasPermission('team')
    return !path.startsWith('/admin')
  }

  const queueItems = computed(() => [
    {
      label: 'Reviews',
      value: openReviewCount.value,
      to: '/admin/nominations?review=1',
      hint: readinessScope.value.reviewWarningsActive ? 'Freitext-Nominierungen entscheiden' : 'Sammelt sich für die spätere Prüfung',
      icon: Sparkles,
      tone: openReviewCount.value > 0 && readinessScope.value.reviewWarningsActive ? 'amber' : 'violet',
    },
    {
      label: 'Risiko',
      value: openRiskCount.value,
      to: '/admin/risk',
      hint: 'Saisonale und globale offene Hinweise',
      icon: ShieldAlert,
      tone: openRiskCount.value > 0 ? 'rose' : 'emerald',
    },
    {
      label: 'Clips',
      value: pendingClipCount.value,
      to: '/admin/clips?status=pending',
      hint: 'Clip-Einreichungen in der Inbox',
      icon: Film,
      tone: pendingClipCount.value > 0 ? 'amber' : 'emerald',
    },
    {
      label: 'Voting',
      value: votingSummary.value.problemSubcategories,
      to: '/admin/voting',
      hint: readinessScope.value.voteWarningsActive ? 'Problem-Unterkategorien prüfen' : 'Voting-Readiness später relevant',
      icon: Vote,
      tone: votingSummary.value.problemSubcategories > 0 && readinessScope.value.voteWarningsActive ? 'amber' : 'violet',
    },
    {
      label: 'Gewinner',
      value: missingWinnerCount.value,
      to: '/admin/winners',
      hint: readinessScope.value.winnerWarningsActive ? 'Unterkategorien ohne Gewinner' : 'Finalisierung später relevant',
      icon: Trophy,
      tone: missingWinnerCount.value > 0 && readinessScope.value.winnerWarningsActive ? 'amber' : 'emerald',
    },
  ].filter((item) => canOpenAdminPath(item.to)))

  const operationChecks = computed(() => {
    const categoriesWithoutCandidates = seasonDetail.value.categories.filter((category) =>
      !seasonDetail.value.candidates.some((candidate) => candidate.categoryId === category.id),
    )
    const categoriesWithReviews = seasonDetail.value.categories.filter((category) =>
      seasonDetail.value.pendingNominations.some((nomination) => nomination.categoryId === category.id),
    )

    return [
      {
        label: 'Kategorien ohne Kandidaten',
        value: categoriesWithoutCandidates.length,
        to: categoriesWithoutCandidates.length > 0
          ? `/admin/categories?group=${encodeURIComponent(categoriesWithoutCandidates[0]!.groupName)}`
          : '/admin/categories',
        state: categoriesWithoutCandidates.length === 0 || !readinessScope.value.candidateWarningsActive ? 'ok' : 'warn',
        note: categoriesWithoutCandidates.length === 0
          ? 'Alle Kategorien sind besetzt.'
          : readinessScope.value.candidateWarningsActive
            ? 'Vor Voting-Endspurt prüfen.'
            : 'In dieser Phase noch Vorbereitung, kein Blocker.',
      },
      {
        label: 'Review-Backlog verteilt',
        value: categoriesWithReviews.length,
        to: categoriesWithReviews.length > 0
          ? `/admin/nominations?review=1&categoryId=${categoriesWithReviews[0]!.id}&status=heavy`
          : '/admin/nominations?review=1',
        state: categoriesWithReviews.length <= 1 || !readinessScope.value.reviewWarningsActive ? 'ok' : 'warn',
        note: categoriesWithReviews.length <= 1
          ? 'Backlog ist fokussiert.'
          : readinessScope.value.reviewWarningsActive
            ? 'Mehrere Kategorien brauchen Sichtung.'
            : 'Nominierungen werden gesammelt; Review wird später relevant.',
      },
      {
        label: 'Risk Flags offen',
        value: openRiskCount.value,
        to: '/admin/risk',
        state: openRiskCount.value === 0 ? 'ok' : 'danger',
        note: openRiskCount.value === 0 ? 'Keine offenen Hinweise.' : 'Saisonale und globale Hinweise zuerst prüfen.',
      },
    ].filter((item) => canOpenAdminPath(item.to))
  })

  const readinessItems = computed(() => {
    const datesComplete = [
      seasonDetail.value.nominationStartsAt,
      seasonDetail.value.nominationEndsAt,
      seasonDetail.value.votingStartsAt,
      seasonDetail.value.votingEndsAt,
      seasonDetail.value.reviewStartsAt,
      seasonDetail.value.reviewEndsAt,
      seasonDetail.value.showDate,
    ].every((value) => value.trim())
    const hasVotingBase = votingSummary.value.totalSubcategories > 0
    const votesReady = !readinessScope.value.voteWarningsActive ||
      (hasVotingBase && votingSummary.value.votedSubcategories === votingSummary.value.totalSubcategories)
    const winnersReady = !readinessScope.value.winnerWarningsActive ||
      (hasVotingBase && votingSummary.value.winnerSetSubcategories === votingSummary.value.totalSubcategories)

    return [
      {
        label: 'Timeline',
        complete: datesComplete,
        note: datesComplete ? 'Alle Phasen sind terminiert.' : 'Mindestens ein Phasendatum fehlt.',
        to: '/admin/years',
      },
      {
        label: 'Public-Jahr',
        complete: seasonDetail.value.isCurrent,
        note: seasonDetail.value.isCurrent ? 'Dieses Jahr ist öffentlich sichtbar.' : 'Das Jahr ist intern ausgewählt.',
        to: '/admin/years',
      },
      {
        label: 'Finale-Link',
        complete: streamBannerLinkConfigured.value,
        note: streamBannerLinkConfigured.value ? 'Finale-Banner Button-Link ist gepflegt.' : 'Finale-Banner Button-Link fehlt.',
        to: '/admin/content?editor=streamBanner',
      },
      {
        label: 'Reviews',
        complete: !readinessScope.value.reviewWarningsActive || openReviewCount.value === 0,
        note: readinessScope.value.reviewWarningsActive
          ? `${openReviewCount.value} offene Reviews.`
          : 'Review-Backlog ist für diese Phase noch kein Blocker.',
        to: '/admin/nominations?review=1',
      },
      {
        label: 'Voting',
        complete: votesReady,
        note: readinessScope.value.voteWarningsActive
          ? `${votingSummary.value.votedSubcategories}/${votingSummary.value.totalSubcategories} Unterkategorien haben Votes.`
          : 'Voting-Readiness wird ab Aufbereitung kritisch.',
        to: '/admin/voting',
      },
      {
        label: 'Gewinner',
        complete: winnersReady,
        note: readinessScope.value.winnerWarningsActive
          ? `${votingSummary.value.winnerSetSubcategories}/${votingSummary.value.totalSubcategories} Gewinner gesetzt.`
          : 'Gewinner werden später finalisiert.',
        to: '/admin/winners',
      },
    ].filter((item) => canOpenAdminPath(item.to))
  })
  const readinessScore = computed(() => ({
    done: readinessItems.value.filter((item) => item.complete).length,
    total: readinessItems.value.length,
  }))

  const publicHealthItems = computed<PublicHealthItem[]>(() => {
    const siteSettings = store.adminSiteSettings
    const operationalSettings = store.adminOperationalSettings
    const configuredFooterLinks = [
      siteSettings.imprintUrl,
      siteSettings.contactUrl,
      siteSettings.sponsorsUrl,
      siteSettings.showactsUrl,
      siteSettings.newsletterUrl,
    ].filter((url) => url.trim()).length
    const configuredFooterPages = [
      siteSettings.imprintContent,
      siteSettings.contactContent,
      siteSettings.sponsorsContent,
      siteSettings.showactsContent,
    ].filter((content) => content.trim()).length
    const canReadSettings = authStore.hasPermission('settings')
    const contentReady = configuredFooterLinks === 5 &&
      configuredFooterPages === 4 &&
      Boolean(siteSettings.privacyPolicyContent.trim() && siteSettings.privacyEmail.trim())

    return [
      {
        label: 'Saison öffentlich',
        state: seasonDetail.value.isCurrent ? 'ok' as const : 'warn' as const,
        note: seasonDetail.value.isCurrent ? `${seasonDetail.value.year} ist Public-Kontext.` : 'Gewähltes Jahr ist nicht öffentlich.',
        to: '/admin/years',
        icon: Globe2,
      },
      {
        label: 'Wartungsmodus',
        state: canReadSettings ? operationalSettings.maintenanceModeEnabled ? 'warn' as const : 'ok' as const : 'info' as const,
        note: canReadSettings
          ? operationalSettings.maintenanceModeEnabled ? 'Landingpage zeigt Sternenpause.' : 'Public-Seite ist nicht im Wartungsmodus.'
          : 'Nur mit Settings-Berechtigung prüfbar.',
        to: '/admin/settings/access',
        icon: ShieldAlert,
      },
      {
        label: 'Finale-Link',
        state: streamBannerLinkConfigured.value ? 'ok' as const : 'warn' as const,
        note: streamBannerLinkConfigured.value ? 'Finale-Banner zeigt auf einen Live-Link.' : 'Im Finale-Banner fehlt noch der Live-Link.',
        to: '/admin/content?editor=streamBanner',
        icon: ExternalLink,
      },
      {
        label: 'Pflicht-Content',
        state: contentReady ? 'ok' as const : 'warn' as const,
        note: contentReady
          ? 'Footer und Datenschutz sind gepflegt.'
          : `${configuredFooterLinks}/5 Links, ${configuredFooterPages}/4 Seiten plus Datenschutz prüfen.`,
        to: '/admin/content',
        icon: CheckCircle2,
      },
    ].filter((item) => canOpenAdminPath(item.to))
  })
  const canViewAuditLog = computed(() => authStore.hasPermission('audit'))
  const canOpenYears = computed(() => canOpenAdminPath('/admin/years'))

  return {
    store,
    activities,
    topCategories,
    metricCards,
    openReviewCount,
    openRiskCount,
    liveSummary,
    liveStatusBadge,
    liveStatusTone,
    maxCategoryValue,
    totalCategoryValue,
    topCategoryTitle,
    topCategoryTotalLabel,
    yearTotals,
    queueItems,
    operationChecks,
    timelinePhases,
    activeCountdown,
    phaseMismatch,
    phaseMismatchLabel,
    readinessItems,
    readinessScore,
    publicHealthItems,
    adminGreeting,
    canViewAuditLog,
    canOpenYears,
  }
}

function buildCountdownLabel(phaseKey: PhaseKey, endValue: string) {
  if (phaseKey === 'completed') return 'Award-Jahr abgeschlossen'
  const date = parseDate(endValue)
  if (!date) return 'Nächster Termin offen'
  const today = startOfDay(new Date())
  const days = Math.ceil((date.getTime() - today.getTime()) / 86_400_000)
  const target = phaseKey === 'show' ? 'bis zur Show' : 'bis Phasen-Ende'

  if (days < 0) return `${Math.abs(days)} Tage über dem Zeitplan`
  if (days === 0) return `Heute ${target}`
  if (days === 1) return `Noch 1 Tag ${target}`
  return `Noch ${days} Tage ${target}`
}

function parseDate(value: string) {
  if (!value) return null
  const date = new Date(`${value}T00:00:00`)
  return Number.isNaN(date.getTime()) ? null : startOfDay(date)
}

function startOfDay(date: Date) {
  const next = new Date(date)
  next.setHours(0, 0, 0, 0)
  return next
}
