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'

export function useAdminReviewsManager() {
  const store = useAwardsStore()
  const route = useRoute()
  const reviewSaving = ref<number | null>(null)
  const adminMessage = ref('')
  const adminError = ref('')
  const reviewFilter = ref('')
  const categoryFilter = ref<number | null>(null)
  const selectedNominationId = ref<number | null>(null)
  const reviewForms = reactive<Record<number, {
    displayName: string
    channelSlug: string
    platform: string
    reviewNote: string
  }>>({})

  const seasonDetail = computed(() => store.adminSeasonDetail)
  const selectedSeasonId = computed(() => store.adminSelectedSeasonId)
  const candidatePlatformOptions = computed(() => SOCIAL_ICON_OPTIONS.filter((option) => option.key !== 'website'))
  const filteredNominations = computed(() => {
    const query = reviewFilter.value.trim().toLowerCase()
    return seasonDetail.value.pendingNominations.filter((nomination) =>
      (!categoryFilter.value || nomination.categoryId === categoryFilter.value) &&
      (!query || [nomination.categoryName, nomination.candidateText, nomination.submittedByTwitchId, extractNominationStreamUrl(nomination)]
        .join(' ')
        .toLowerCase()
        .includes(query)),
    )
  })
  const selectedNomination = computed(() =>
    filteredNominations.value.find((nomination) => nomination.id === selectedNominationId.value) ?? filteredNominations.value[0] ?? null,
  )
  const reviewStats = computed(() => [
    { label: 'Offen', value: seasonDetail.value.pendingNominations.length },
    { label: 'Entschieden', value: seasonDetail.value.reviewedNominations.length },
    { label: 'Sichtbar', value: filteredNominations.value.length },
    { label: 'Kategorien', value: new Set(seasonDetail.value.pendingNominations.map((nomination) => nomination.categoryName)).size },
  ])
  const reviewedNominations = computed(() => seasonDetail.value.reviewedNominations.slice(0, 12))
  const categoryOptions = computed(() =>
    seasonDetail.value.categories
      .filter((category) => seasonDetail.value.pendingNominations.some((nomination) => nomination.categoryId === category.id))
      .map((category) => ({
        id: category.id,
        label: category.name,
        count: seasonDetail.value.pendingNominations.filter((nomination) => nomination.categoryId === category.id).length,
      })),
  )
  const selectedCandidateCollision = computed(() => {
    if (!selectedNomination.value) return null
    const form = reviewForms[selectedNomination.value.id]
    if (!form) return null
    const normalizedName = form.displayName.trim().toLowerCase()
    const normalizedSlug = form.channelSlug.trim().toLowerCase()
    return seasonDetail.value.candidates.find((candidate) =>
      candidate.categoryId === selectedNomination.value?.categoryId &&
      (candidate.displayName.trim().toLowerCase() === normalizedName || (!!normalizedSlug && candidate.channelSlug.trim().toLowerCase() === normalizedSlug)),
    ) ?? null
  })
  const selectedRelatedPendingNominations = computed(() => {
    if (!selectedNomination.value) return []
    const selectedName = selectedNomination.value.candidateText.trim().toLowerCase()
    const selectedStreamUrl = extractNominationStreamUrl(selectedNomination.value).toLowerCase()

    return seasonDetail.value.pendingNominations
      .filter((nomination) => {
        if (nomination.id === selectedNomination.value?.id || nomination.categoryId !== selectedNomination.value?.categoryId) {
          return false
        }

        const sameName = Boolean(selectedName) && nomination.candidateText.trim().toLowerCase() === selectedName
        const sameStreamUrl = selectedStreamUrl && extractNominationStreamUrl(nomination).toLowerCase() === selectedStreamUrl
        return sameName || sameStreamUrl
      })
      .slice(0, 5)
  })
  const selectedNominationSignalSummary = computed(() => {
    if (!selectedNomination.value) return null

    const selectedName = selectedNomination.value.candidateText.trim().toLowerCase()
    const selectedStreamUrl = extractNominationStreamUrl(selectedNomination.value).toLowerCase()
    const relatedNominations = seasonDetail.value.pendingNominations.filter((nomination) =>
      nomination.categoryId === selectedNomination.value?.categoryId &&
      (
        (Boolean(selectedName) && nomination.candidateText.trim().toLowerCase() === selectedName) ||
        (Boolean(selectedStreamUrl) && extractNominationStreamUrl(nomination).toLowerCase() === selectedStreamUrl)
      ),
    )
    const submitters = new Set(relatedNominations.map((nomination) => nomination.submittedByTwitchId.trim().toLowerCase()).filter(Boolean))
    const platforms = new Set(
      relatedNominations
        .map((nomination) => resolveStreamIdentity(extractNominationStreamUrl(nomination)).platform)
        .filter(Boolean),
    )

    return {
      submissions: relatedNominations.length,
      uniqueSubmitters: submitters.size,
      platforms: [...platforms].sort(),
    }
  })
  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())
  })

  function focusNominationFromRoute() {
    const rawNominationId = Array.isArray(route.query.nominationId) ? route.query.nominationId[0] : route.query.nominationId
    const nominationId = Number(rawNominationId)
    if (!Number.isFinite(nominationId)) {
      return false
    }

    const nomination = seasonDetail.value.pendingNominations.find((item) => item.id === nominationId)
    if (!nomination) {
      return false
    }

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

  watch(
    seasonDetail,
    (detail) => {
      for (const nomination of detail.pendingNominations) {
        const streamIdentity = resolveStreamIdentity(extractNominationStreamUrl(nomination))
        reviewForms[nomination.id] = {
          displayName: nomination.candidateText,
          channelSlug: streamIdentity.channelSlug,
          platform: streamIdentity.platform,
          reviewNote: nomination.reviewNote ?? '',
        }
      }

      if (focusNominationFromRoute()) {
        return
      }

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

  watch(
    () => route.query.nominationId,
    () => {
      focusNominationFromRoute()
    },
    { 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 = 'Nominierung 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 = 'Nominierung wurde aus der Review-Liste entfernt.'
    } catch (error) {
      adminError.value = error instanceof Error ? error.message : 'Nominierung konnte nicht verworfen werden.'
    } finally {
      reviewSaving.value = null
    }
  }

  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 '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,
    adminMessage,
    adminError,
    reviewForms,
    seasonDetail,
    reviewFilter,
    categoryFilter,
    selectedNominationId,
    candidatePlatformOptions,
    filteredNominations,
    selectedNomination,
    reviewStats,
    reviewedNominations,
    categoryOptions,
    selectedCandidateCollision,
    selectedRelatedPendingNominations,
    selectedNominationSignalSummary,
    canApproveSelected,
    approveNomination,
    rejectNomination,
    selectedPlatformValue,
    handlePlatformSelection,
    extractNominationStreamUrl,
  }
}

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

  const noteMatch = nomination.reviewNote?.match(/Stream-Link:\s*(https?:\/\/\S+)/i)
  return noteMatch?.[1]?.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
  }
}
