import { computed, reactive, ref, watch } from 'vue'
import { CheckCircle2, Film, Layers3, PlayCircle } from '@lucide/vue'
import { useRoute } from 'vue-router'

import { buildClipEmbed, type ClipEmbed } from '../../lib/clipEmbeds'
import { useAwardsStore } from '../../stores/awards'
import type { AdminClipSubmissionItem } from '../../types/awards'

type ClipReviewStatus = 'pending' | 'approved' | 'rejected'
type ClipStatusFilter = 'all' | 'pending' | 'reviewed'
type ClipPlatformFilter = 'all' | string

export function useAdminClipManager() {
  const store = useAwardsStore()
  const route = useRoute()
  const query = ref('')
  const statusFilter = ref<ClipStatusFilter>('all')
  const platformFilter = ref<ClipPlatformFilter>('all')
  const categoryFilter = ref('all')
  const deleting = ref(false)
  const statusSaving = ref<number | null>(null)
  const bulkSaving = ref(false)
  const adminMessage = ref('')
  const adminError = ref('')
  const clipToDelete = ref<AdminClipSubmissionItem | null>(null)
  const reviewNotes = reactive<Record<number, string>>({})

  const seasonDetail = computed(() => store.adminSeasonDetail)
  const selectedSeasonId = computed(() => store.adminSelectedSeasonId)
  const optionalFeatures = computed(() => store.adminOptionalFeatureSettings)
  const clipSubmissionsEnabled = computed(() => optionalFeatures.value.clipSubmissionsEnabled)
  const clipReviewEnabled = computed(() => optionalFeatures.value.clipReviewEnabled)
  const clipDisabledMessage = computed(() => optionalFeatures.value.clipSubmissionDisabledMessage)
  const clipWorkflowStatusLabel = computed(() => {
    if (clipSubmissionsEnabled.value && clipReviewEnabled.value) return 'Public-Einreichung und Review aktiv'
    if (clipSubmissionsEnabled.value) return 'Public-Einreichung aktiv, Review ausgeblendet'
    if (clipReviewEnabled.value) return 'Public aus, Review bleibt sichtbar'
    return 'Clip-Workflow deaktiviert'
  })
  const clipWorkflowStatusClass = computed(() =>
    clipSubmissionsEnabled.value
      ? 'border-emerald-200 bg-emerald-50 text-emerald-700'
      : clipReviewEnabled.value || submissions.value.length > 0
        ? 'border-amber-200 bg-amber-50 text-amber-700'
        : 'border-slate-200 bg-slate-50 text-slate-600',
  )
  const submissions = computed(() => seasonDetail.value.clipSubmissions ?? [])
  const categories = computed(() => seasonDetail.value.categories ?? [])
  const categoryName = computed(() =>
    Object.fromEntries(categories.value.map((category) => [category.id, category.name])),
  )
  const clips = computed(() => {
    const search = query.value.trim().toLowerCase()
    return submissions.value.filter((clip) =>
      matchesStatusFilter(clip.status, statusFilter.value) &&
      (platformFilter.value === 'all' || clip.platform === platformFilter.value) &&
      (categoryFilter.value === 'all' || String(clip.categoryId) === categoryFilter.value) &&
      (!search || [clip.title, clip.creator, clip.platform, clip.submittedByTwitchId, clip.clipUrl].join(' ').toLowerCase().includes(search)),
    )
  })

  const PAGE_SIZE = 10
  const page = ref(1)
  const sortedClips = computed(() =>
    [...clips.value].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()),
  )
  const totalPages = computed(() => Math.max(1, Math.ceil(sortedClips.value.length / PAGE_SIZE)))
  const pagedClips = computed(() => sortedClips.value.slice((page.value - 1) * PAGE_SIZE, page.value * PAGE_SIZE))
  const rangeStart = computed(() => sortedClips.value.length === 0 ? 0 : (page.value - 1) * PAGE_SIZE + 1)
  const rangeEnd = computed(() => Math.min(page.value * PAGE_SIZE, sortedClips.value.length))

  watch([query, statusFilter, platformFilter, categoryFilter, () => submissions.value.length], () => {
    page.value = 1
  })
  watch(totalPages, (max) => {
    if (page.value > max) page.value = max
  })
  const clipEmbeds = computed<Record<number, ClipEmbed | null>>(() =>
    Object.fromEntries(submissions.value.map((clip) => [clip.id, buildClipEmbed(clip.clipUrl)])),
  )
  const duplicateUrls = computed(() => {
    const counts = new Map<string, number>()
    for (const clip of submissions.value) {
      const key = normalizeClipUrl(clip.clipUrl)
      if (!key) continue
      counts.set(key, (counts.get(key) ?? 0) + 1)
    }
    return counts
  })
  const creatorClipGroups = computed(() => {
    const counts = new Map<string, number>()
    for (const clip of submissions.value) {
      const key = creatorClipKey(clip)
      if (!key) continue
      counts.set(key, (counts.get(key) ?? 0) + 1)
    }
    return counts
  })
  const stats = computed(() => [
    { label: 'Einreichungen', value: submissions.value.length, icon: Film },
    { label: 'Offen', value: submissions.value.filter((clip) => clip.status === 'pending').length, icon: PlayCircle },
    { label: 'Freigegeben', value: submissions.value.filter((clip) => clip.status === 'approved').length, icon: CheckCircle2 },
    { label: 'Duplikate', value: [...duplicateUrls.value.values()].filter((count) => count > 1).length, icon: Layers3 },
  ])
  const statusFilters = computed(() => [
    { key: 'all' as const, label: 'Alle', count: submissions.value.length },
    { key: 'pending' as const, label: 'Offen', count: submissions.value.filter((clip) => clip.status === 'pending').length },
    { key: 'reviewed' as const, label: 'Geprüft', count: submissions.value.filter((clip) => clip.status !== 'pending').length },
  ])
  const platformFilters = computed(() => [
    { key: 'all', label: 'Alle Plattformen', count: submissions.value.length },
    ...[...new Set(submissions.value.map((clip) => clip.platform).filter(Boolean))]
      .sort()
      .map((platform) => ({
        key: platform,
        label: platform,
        count: submissions.value.filter((clip) => clip.platform === platform).length,
      })),
  ])
  const categoryFilters = computed(() => [
    { id: 'all' as const, label: 'Alle Kategorien', count: submissions.value.length },
    ...categories.value
      .filter((category) => submissions.value.some((clip) => clip.categoryId === category.id))
      .map((category) => ({
        id: String(category.id),
        label: category.name,
        count: submissions.value.filter((clip) => clip.categoryId === category.id).length,
      })),
  ])

  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 rawPlatform = Array.isArray(route.query.platform) ? route.query.platform[0] : route.query.platform
    const rawCategoryId = Array.isArray(route.query.categoryId) ? route.query.categoryId[0] : route.query.categoryId

    query.value = typeof rawQuery === 'string' ? rawQuery : ''
    statusFilter.value = isClipStatusFilter(rawStatus) ? rawStatus : 'all'
    platformFilter.value = typeof rawPlatform === 'string' && rawPlatform.trim() ? rawPlatform : 'all'

    const normalizedCategoryId = typeof rawCategoryId === 'string' && rawCategoryId.trim() ? rawCategoryId : 'all'
    categoryFilter.value = categoryFilters.value.some((filter) => filter.id === normalizedCategoryId) ? normalizedCategoryId : 'all'
  }

  watch(submissions, (items) => {
    for (const clip of items) {
      if (reviewNotes[clip.id] === undefined) {
        reviewNotes[clip.id] = clip.reviewNote ?? ''
      }
    }
  }, { immediate: true })

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

  async function updateClipStatus(clip: AdminClipSubmissionItem, status: ClipReviewStatus) {
    if (!selectedSeasonId.value) return
    statusSaving.value = clip.id
    adminMessage.value = ''
    adminError.value = ''
    try {
      await store.updateAdminClipStatus(clip.id, selectedSeasonId.value, {
        status,
        reviewNote: reviewNotes[clip.id]?.trim() || undefined,
      })
      adminMessage.value = `Clip ${clip.id} wurde auf „${statusLabel(status)}“ gesetzt.`
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Clip-Status konnte nicht gespeichert werden.'
    } finally {
      statusSaving.value = null
    }
  }

  async function confirmDelete() {
    if (!clipToDelete.value || !selectedSeasonId.value) return
    deleting.value = true
    adminError.value = ''
    try {
      await store.deleteAdminClip(clipToDelete.value.id, selectedSeasonId.value)
      adminMessage.value = 'Clip-Einreichung wurde entfernt.'
      clipToDelete.value = null
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Löschen fehlgeschlagen.'
    } finally {
      deleting.value = false
    }
  }

  async function bulkUpdateStatus(status: 'approved' | 'rejected') {
    if (!selectedSeasonId.value || bulkSaving.value) return
    const targets = clips.value
    if (targets.length === 0) return

    bulkSaving.value = true
    adminMessage.value = ''
    adminError.value = ''
    try {
      await store.bulkUpdateAdminClipStatus(targets.map((c) => c.id), selectedSeasonId.value, status)
      const verb = status === 'approved' ? 'freigegeben' : 'abgelehnt'
      adminMessage.value = `${targets.length} Clip${targets.length !== 1 ? 's' : ''} wurden ${verb}.`
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Bulk-Aktion fehlgeschlagen.'
    } finally {
      bulkSaving.value = false
    }
  }

  function duplicateUrlCount(clipUrl: string) {
    return duplicateUrls.value.get(normalizeClipUrl(clipUrl)) ?? 0
  }

  function creatorClipCount(clip: AdminClipSubmissionItem) {
    return creatorClipGroups.value.get(creatorClipKey(clip)) ?? 0
  }

  return {
    query,
    statusFilter,
    platformFilter,
    categoryFilter,
    deleting,
    statusSaving,
    adminMessage,
    adminError,
    clipToDelete,
    reviewNotes,
    clipSubmissionsEnabled,
    clipReviewEnabled,
    clipDisabledMessage,
    clipWorkflowStatusLabel,
    clipWorkflowStatusClass,
    submissions,
    categoryName,
    clips,
    page,
    totalPages,
    pagedClips,
    rangeStart,
    rangeEnd,
    clipEmbeds,
    stats,
    statusFilters,
    platformFilters,
    categoryFilters,
    bulkSaving,
    platformClass,
    statusClass,
    statusLabel,
    duplicateUrlCount,
    creatorClipCount,
    updateClipStatus,
    bulkUpdateStatus,
    confirmDelete,
  }
}

function matchesStatusFilter(status: string, filter: ClipStatusFilter) {
  return filter === 'all' || status === filter || (filter === 'reviewed' && status !== 'pending')
}

function isClipStatusFilter(value: unknown): value is ClipStatusFilter {
  return value === 'all' || value === 'pending' || value === 'reviewed'
}

function normalizeClipUrl(clipUrl: string) {
  return clipUrl.trim().toLowerCase()
}

function creatorClipKey(clip: AdminClipSubmissionItem) {
  if (clip.candidateId) return `candidate:${clip.candidateId}`
  const creator = clip.creator.trim().toLowerCase()
  const categoryId = clip.categoryId ?? 'global'
  return creator ? `creator:${categoryId}:${creator}` : ''
}

function platformClass(platform: string) {
  if (platform === 'Twitch') return 'border-violet-200 bg-violet-50 text-violet-700'
  if (platform === 'YouTube') return 'border-rose-200 bg-rose-50 text-rose-600'
  return 'border-slate-200 bg-slate-50 text-slate-600'
}

function statusClass(status: string) {
  if (status === 'approved') return 'border-emerald-200 bg-emerald-50 text-emerald-700'
  if (status === 'rejected') return 'border-rose-200 bg-rose-50 text-rose-700'
  return 'border-amber-200 bg-amber-50 text-amber-700'
}

function statusLabel(status: string) {
  if (status === 'approved') return 'freigegeben'
  if (status === 'rejected') return 'abgelehnt'
  return 'offen'
}
