import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
import { useRoute } from 'vue-router'

import { SOCIAL_ICON_OPTIONS, socialIconOptionForValue } from '../../lib/socialIcons'
import { useAwardsStore } from '../../stores/awards'
import type { AdminNominationReviewItem } from '../../types/awards'

export function useAdminReviewsManager(options?: {
  categoryIdsFilter?: () => number[] | null | undefined
}) {
  const store = useAwardsStore()
  const route = useRoute()
  const reviewSaving = ref<number | null>(null)
  const blacklistSaving = ref(false)
  const adminMessage = ref('')
  const adminError = ref('')
  const reviewFilter = ref('')
  const categoryFilter = ref<string | null>(null)
  const subcategoryFilter = ref<number | null>(null)
  const selectedNominationId = ref<number | null>(null)
  const isReviewModalOpen = ref(false)
  const reviewForms = reactive<Record<number, {
    displayName: string
    channelSlug: string
    platform: string
    categoryId: number | null
    reviewNote: string
  }>>({})

  const seasonDetail = computed(() => store.adminSeasonDetail)
  const selectedSeasonId = computed(() => store.adminSelectedSeasonId)
  const candidatePlatformOptions = computed(() => SOCIAL_ICON_OPTIONS.filter((option) => option.key !== 'website'))
  const reviewGroups = computed(() => seasonDetail.value.pendingNominationGroups ?? [])
  const pendingNominationById = computed(() =>
    new Map(seasonDetail.value.pendingNominations.map((nomination) => [nomination.id, nomination])),
  )
  const tierCategoryFilterIds = computed(() =>
    (options?.categoryIdsFilter?.() ?? [])
      .filter((value): value is number => Number.isFinite(value) && value > 0),
  )
  const filteredNominations = computed(() => {
    const query = reviewFilter.value.trim().toLowerCase()
    const tierFilter = new Set(tierCategoryFilterIds.value)
    return reviewGroups.value.filter((nomination) =>
      (tierFilter.size === 0 || groupMatchesTierFilter(nomination, tierFilter, pendingNominationById.value)) &&
      (subcategoryFilter.value === null || groupMatchesTierFilter(nomination, new Set([subcategoryFilter.value]), pendingNominationById.value)) &&
      (!categoryFilter.value || nomination.categoryGroupName === categoryFilter.value) &&
      (!query || [
        nomination.categoryGroupName,
        nomination.displayName,
        nomination.resolvedChannel,
        nomination.resolvedPlatform,
        nomination.streamUrl,
        nomination.suggestedCategoryName,
      ].join(' ').toLowerCase().includes(query)),
    )
  })
  const selectedNomination = computed(() =>
    filteredNominations.value.find((nomination) => nomination.id === selectedNominationId.value) ?? filteredNominations.value[0] ?? null,
  )
  const reviewStats = computed(() => [
    { label: 'Hauptkategorien', value: new Set(seasonDetail.value.categories.map((category) => category.groupName)).size },
    { label: 'Unterkategorien', value: seasonDetail.value.categories.length },
    { label: 'Nominierungen', value: seasonDetail.value.pendingNominations.length + seasonDetail.value.reviewedNominations.length },
    { label: 'Noch zu bearbeiten', value: seasonDetail.value.pendingNominationGroups.length },
  ])
  const reviewedNominations = computed(() => seasonDetail.value.reviewedNominations.slice(0, 12))
  const categoryOptions = computed(() =>
    [...new Set(reviewGroups.value.map((nomination) => nomination.categoryGroupName))]
      .filter(Boolean)
      .sort((a, b) => a.localeCompare(b))
      .map((groupName) => ({
        id: groupName,
        label: groupName,
        count: reviewGroups.value.filter((nomination) => nomination.categoryGroupName === groupName).length,
      })),
  )
  const availableSubcategoryOptions = computed(() => {
    const scopedCategories = seasonDetail.value.categories
      .filter((category) =>
        (tierCategoryFilterIds.value.length === 0 || tierCategoryFilterIds.value.includes(category.id))
        && (!categoryFilter.value || category.groupName === categoryFilter.value),
      )
      .sort((left, right) => left.sortOrder - right.sortOrder)

    return [
      {
        id: null,
        label: 'Alle',
        count: reviewGroups.value.filter((nomination) =>
          (tierCategoryFilterIds.value.length === 0 || groupMatchesTierFilter(nomination, new Set(tierCategoryFilterIds.value), pendingNominationById.value))
          && (!categoryFilter.value || nomination.categoryGroupName === categoryFilter.value),
        ).length,
      },
      ...scopedCategories.map((category) => ({
        id: category.id,
        label: category.name,
        count: reviewGroups.value.filter((nomination) =>
          groupMatchesTierFilter(nomination, new Set([category.id]), pendingNominationById.value),
        ).length,
        note: formatTierRangeNote(category.viewerRangeMin, category.viewerRangeMax),
      })),
    ]
  })
  const tierCategoryOptions = computed(() => {
    if (!selectedNomination.value) return []
    return seasonDetail.value.categories
      .filter((category) => category.groupName === selectedNomination.value?.categoryGroupName)
      .map((category) => ({
        id: category.id,
        label: formatTierOptionLabel(category.name, category.viewerRangeMin, category.viewerRangeMax),
      }))
  })
  const selectedCandidateCollision = computed(() => {
    if (!selectedNomination.value) return null
    const form = reviewForms[selectedNomination.value.id]
    if (!form?.categoryId) return null
    const normalizedName = form.displayName.trim().toLowerCase()
    const normalizedSlug = form.channelSlug.trim().toLowerCase()
    return seasonDetail.value.candidates.find((candidate) =>
      candidate.categoryId === form.categoryId &&
      (
        (!!selectedNomination.value?.streamerIdentityId && candidate.streamerIdentityId === selectedNomination.value.streamerIdentityId)
        || candidate.displayName.trim().toLowerCase() === normalizedName
        || (!!normalizedSlug && candidate.channelSlug.trim().toLowerCase() === normalizedSlug)
      ),
    ) ?? null
  })
  const selectedNominationSignalSummary = computed(() => {
    if (!selectedNomination.value) return null
    return {
      submissions: selectedNomination.value.nominationTally,
      uniqueSubmitters: selectedNomination.value.uniqueSubmitterCount,
      platforms: selectedNomination.value.resolvedPlatform ? [selectedNomination.value.resolvedPlatform] : [],
    }
  })
  const trackingReviewNotes = computed(() =>
    seasonDetail.value.showTrackingReviewNotes
      ? (seasonDetail.value.trackingReviewNotes ?? '')
      : '',
  )
  const selectedRelatedPendingNominations = computed<AdminNominationReviewItem[]>(() => {
    if (!selectedNomination.value) return []
    const nominationIds = new Set(selectedNomination.value.nominationIds)
    return seasonDetail.value.pendingNominations
      .filter((nomination) => nominationIds.has(nomination.id))
      .sort((left, right) => left.createdAt.localeCompare(right.createdAt))
  })
  const canApproveSelected = computed(() => {
    if (!selectedNomination.value) return false
    const form = reviewForms[selectedNomination.value.id]
    return Boolean(form?.displayName.trim() && form.channelSlug.trim() && form.platform.trim() && form.categoryId)
  })

  function focusNominationFromRoute() {
    const rawNominationId = Array.isArray(route.query.nominationId) ? route.query.nominationId[0] : route.query.nominationId
    const rawCategoryGroup = Array.isArray(route.query.categoryGroup) ? route.query.categoryGroup[0] : route.query.categoryGroup
    if (typeof rawCategoryGroup === 'string' && rawCategoryGroup.trim()) {
      categoryFilter.value = rawCategoryGroup
    }

    const nominationId = Number(rawNominationId)
    if (!Number.isFinite(nominationId)) {
      return typeof rawCategoryGroup === 'string' && rawCategoryGroup.trim().length > 0
    }

    const nomination = reviewGroups.value.find((item) => item.id === nominationId || item.nominationIds.includes(nominationId))
    if (!nomination) {
      return false
    }

    reviewFilter.value = ''
    categoryFilter.value = nomination.categoryGroupName
    selectedNominationId.value = nomination.id
    return true
  }

  watch(
    seasonDetail,
    (detail) => {
      for (const nomination of detail.pendingNominationGroups ?? []) {
        const streamIdentity = resolveStreamIdentity(nomination.streamUrl ?? '')
        reviewForms[nomination.id] = {
          displayName: nomination.displayName === 'Name im Review festlegen' ? '' : nomination.displayName,
          channelSlug: nomination.resolvedChannel ?? streamIdentity.channelSlug,
          platform: nomination.resolvedPlatform ?? streamIdentity.platform,
          categoryId: nomination.suggestedCategoryId,
          reviewNote: nomination.trackingReviewNote ?? '',
        }
      }

      if (focusNominationFromRoute()) {
        return
      }

      if (!reviewGroups.value.some((nomination) => nomination.id === selectedNominationId.value)) {
        selectedNominationId.value = reviewGroups.value[0]?.id ?? null
      }
    },
    { immediate: true },
  )

  watch(
    () => [route.query.nominationId, route.query.categoryGroup] as const,
    () => {
      focusNominationFromRoute()
    },
    { immediate: true },
  )

  watch(
    availableSubcategoryOptions,
    (tabs) => {
      if (!tabs.some((tab) => tab.id === subcategoryFilter.value)) {
        subcategoryFilter.value = null
      }
    },
    { immediate: true },
  )

  watch(
    filteredNominations,
    (nominations) => {
      if (!nominations.some((nomination) => nomination.id === selectedNominationId.value)) {
        selectedNominationId.value = nominations[0]?.id ?? null
      }
    },
    { immediate: true },
  )

  async function approveNomination(nominationId: number) {
    if (!selectedSeasonId.value) return

    reviewSaving.value = nominationId
    adminMessage.value = ''
    adminError.value = ''

    try {
      await store.approveAdminNomination(nominationId, selectedSeasonId.value, reviewForms[nominationId])
      adminMessage.value = 'Nominierungsgruppe wurde in die Kandidatenliste übernommen.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Nominierung konnte nicht übernommen werden.'
    } finally {
      reviewSaving.value = null
    }
  }

  async function rejectNomination(nominationId: number) {
    if (!selectedSeasonId.value) return

    reviewSaving.value = nominationId
    adminMessage.value = ''
    adminError.value = ''

    try {
      await store.rejectAdminNomination(nominationId, selectedSeasonId.value, {
        reviewNote: reviewForms[nominationId]?.reviewNote || undefined,
      })
      adminMessage.value = 'Nominierungsgruppe wurde aus der Review-Liste entfernt.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Nominierung konnte nicht verworfen werden.'
    } finally {
      reviewSaving.value = null
    }
  }

  async function reopenRejectedNomination(nominationId: number) {
    if (!selectedSeasonId.value) return

    reviewSaving.value = nominationId
    adminMessage.value = ''
    adminError.value = ''

    try {
      await store.reopenRejectedAdminNomination(nominationId, selectedSeasonId.value, {})
      adminMessage.value = 'Verworfene Nominierung wurde wieder in die Review-Queue gelegt.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Nominierung konnte nicht wieder geoeffnet werden.'
    } finally {
      reviewSaving.value = null
    }
  }

  async function updateTrackingReview(nominationId: number, status: 'reviewed' | 'overridden') {
    if (!selectedSeasonId.value) return

    reviewSaving.value = nominationId
    adminMessage.value = ''
    adminError.value = ''

    try {
      await store.updateNominationTrackingReview(nominationId, selectedSeasonId.value, {
        status,
        reviewNote: reviewForms[nominationId]?.reviewNote || undefined,
      })
      adminMessage.value = status === 'overridden'
        ? 'Tracking-Override wurde gespeichert.'
        : 'Tracking-Review wurde als geprüft markiert.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Tracking-Review konnte nicht gespeichert werden.'
    } finally {
      reviewSaving.value = null
    }
  }

  async function addStreamUrlToBlacklist(streamUrl: string) {
    const url = streamUrl.trim()
    if (!url || blacklistSaving.value) return

    blacklistSaving.value = true
    adminMessage.value = ''
    adminError.value = ''

    try {
      await store.addAdminNominationLinkBlacklistEntry({ url })
      adminMessage.value = 'Link wurde zur Blacklist hinzugefügt.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Link konnte nicht zur Blacklist hinzugefügt werden.'
    } finally {
      blacklistSaving.value = false
    }
  }

  function openSelectedNomination() {
    if (!selectedNomination.value) return
    selectedNominationId.value = selectedNomination.value.id
    isReviewModalOpen.value = true
  }

  function openNominationById(nominationId: number) {
    const nomination = filteredNominations.value.find((item) => item.id === nominationId)
    if (!nomination) return
    selectedNominationId.value = nomination.id
    isReviewModalOpen.value = true
  }

  function closeNominationModal() {
    isReviewModalOpen.value = false
  }

  function handleKeydown(event: KeyboardEvent) {
    const target = event.target as Element
    if (
      target.tagName === 'INPUT' ||
      target.tagName === 'TEXTAREA' ||
      target.tagName === 'SELECT' ||
      (target as HTMLElement).isContentEditable
    ) return
    if (event.ctrlKey || event.altKey || event.metaKey) return

    const nominations = filteredNominations.value
    const currentIndex = nominations.findIndex((n) => n.id === selectedNomination.value?.id)

    switch (event.key) {
      case 'ArrowDown':
      case 'j': {
        event.preventDefault()
        const next = nominations[Math.min(currentIndex + 1, nominations.length - 1)]
        if (next) selectedNominationId.value = next.id
        break
      }
      case 'ArrowUp':
      case 'k': {
        event.preventDefault()
        const prev = nominations[Math.max(currentIndex - 1, 0)]
        if (prev) selectedNominationId.value = prev.id
        break
      }
      case 'Enter': {
        if (selectedNomination.value) {
          event.preventDefault()
          openSelectedNomination()
        }
        break
      }
      case 'a': {
        if (selectedNomination.value && canApproveSelected.value && !reviewSaving.value) {
          event.preventDefault()
          void approveNomination(selectedNomination.value.id)
        }
        break
      }
      case 'r': {
        if (selectedNomination.value && !reviewSaving.value) {
          event.preventDefault()
          void rejectNomination(selectedNomination.value.id)
        }
        break
      }
    }
  }

  onMounted(() => window.addEventListener('keydown', handleKeydown))
  onUnmounted(() => window.removeEventListener('keydown', handleKeydown))

  function selectedPlatformValue(platform: string) {
    return socialIconOptionForValue(platform)?.key ?? 'custom'
  }

  function setPlatform(platform: string) {
    if (!selectedNomination.value) return
    const form = reviewForms[selectedNomination.value.id]
    if (!form) return

    if (platform === 'custom') {
      if (socialIconOptionForValue(form.platform)) {
        form.platform = ''
      }
      return
    }

    form.platform = socialIconOptionForValue(platform)?.label ?? platform
  }

  function handlePlatformSelection(value: string) {
    setPlatform(value)
  }

  return {
    reviewSaving,
    blacklistSaving,
    adminMessage,
    adminError,
    reviewForms,
    seasonDetail,
    reviewFilter,
    categoryFilter,
    subcategoryFilter,
    selectedNominationId,
    isReviewModalOpen,
    candidatePlatformOptions,
    filteredNominations,
    selectedNomination,
    reviewStats,
    reviewedNominations,
    categoryOptions,
    availableSubcategoryOptions,
    tierCategoryOptions,
    selectedCandidateCollision,
    selectedRelatedPendingNominations,
    selectedNominationSignalSummary,
    trackingReviewNotes,
    canApproveSelected,
    approveNomination,
    rejectNomination,
    reopenRejectedNomination,
    updateTrackingReview,
    addStreamUrlToBlacklist,
    openSelectedNomination,
    openNominationById,
    closeNominationModal,
    selectedPlatformValue,
    handlePlatformSelection,
    extractNominationStreamUrl,
  }
}

export function getTrackerStatusMeta(status: string) {
  switch (status.trim().toLowerCase()) {
    case 'resolved':
      return {
        label: 'Tracker bestätigt',
        toneClass: 'border-emerald-100 bg-emerald-50 text-emerald-800',
        hint: 'Viewer-Wert wurde gefunden und ein Tier automatisch vorgeschlagen.',
      }
    case 'no_data':
      return {
        label: 'Keine Viewer-Daten',
        toneClass: 'border-amber-100 bg-amber-50 text-amber-800',
        hint: 'Link wurde erkannt, aber TwitchTracker lieferte keinen belastbaren Avg-Viewer-Wert.',
      }
    case 'unsupported_platform':
      return {
        label: 'Manueller Tier-Entscheid',
        toneClass: 'border-sky-100 bg-sky-50 text-sky-800',
        hint: 'Diese Plattform wird nicht automatisch getrackt. Das Tier muss manuell festgelegt werden.',
      }
    case 'unresolved':
      return {
        label: 'Link nicht auflösbar',
        toneClass: 'border-rose-100 bg-rose-50 text-rose-800',
        hint: 'Der eingereichte Link konnte nicht sicher einem Kanal zugeordnet werden.',
      }
    default:
      return {
        label: 'Prüfung ausstehend',
        toneClass: 'border-slate-100 bg-slate-50 text-slate-700',
        hint: 'Für diesen Fall liegt noch kein stabiler Tracker-Status vor.',
      }
  }
}

function extractNominationStreamUrl(nomination: { streamUrl?: string | null }) {
  return nomination.streamUrl?.trim() ?? ''
}

function resolveStreamIdentity(streamUrl: string) {
  const fallback = { platform: 'Twitch', channelSlug: '' }
  if (!streamUrl) return fallback

  try {
    const url = new URL(streamUrl)
    const host = url.hostname.replace(/^www\./, '').toLowerCase()
    const firstPathPart = url.pathname
      .split('/')
      .filter(Boolean)
      .find((part) => !['c', 'channel', 'user', 'live'].includes(part.toLowerCase()))
      ?.replace(/^@/, '')
      .replace(/[^a-zA-Z0-9._-]/g, '') ?? ''

    if (host.includes('twitch.tv')) {
      return { platform: 'Twitch', channelSlug: firstPathPart }
    }

    if (host.includes('kick.com')) {
      return { platform: 'Kick', channelSlug: firstPathPart }
    }

    if (host.includes('youtube.com') || host.includes('youtu.be')) {
      return { platform: 'YouTube', channelSlug: firstPathPart }
    }

    const platform = host.split('.')[0]
    return {
      platform: platform ? `${platform.charAt(0).toUpperCase()}${platform.slice(1)}` : fallback.platform,
      channelSlug: firstPathPart,
    }
  } catch {
    return fallback
  }
}

function formatTierOptionLabel(name: string, min: number | null, max: number | null) {
  if (min === null && max === null) return name
  if (min !== null && max !== null) return `${name} (${min}-${max} Viewer)`
  if (min !== null) return `${name} (ab ${min} Viewer)`
  return `${name} (bis ${max} Viewer)`
}

function formatTierRangeNote(min: number | null, max: number | null) {
  if (min === null && max === null) return 'ohne Range'
  if (min !== null && max !== null) return `${min}-${max} Viewer`
  if (min !== null) return `ab ${min} Viewer`
  return `bis ${max} Viewer`
}

function groupMatchesTierFilter(
  nomination: { nominationIds: number[]; suggestedCategoryId: number | null },
  categoryIds: Set<number>,
  pendingNominationById: Map<number, AdminNominationReviewItem>,
) {
  if (nomination.suggestedCategoryId !== null && categoryIds.has(nomination.suggestedCategoryId)) {
    return true
  }

  for (const nominationId of nomination.nominationIds) {
    const pendingNomination = pendingNominationById.get(nominationId)
    if (pendingNomination?.categoryId !== null && pendingNomination?.categoryId !== undefined && categoryIds.has(pendingNomination.categoryId)) {
      return true
    }
  }

  return false
}
