import { computed, type ComputedRef, type Ref } from 'vue'

import { buildClipEmbed } from '../../lib/clipEmbeds'
import { useAuthStore } from '../../stores/auth'
import { useAwardsStore } from '../../stores/awards'
import type { HomeDisplayCategory, HomeInteractionModalKind, HomeLandingCategory } from './homeLandingTypes'

type AwardsStore = ReturnType<typeof useAwardsStore>
type AuthStore = ReturnType<typeof useAuthStore>
type HomeTimelineKey = 'nomination' | 'voting' | 'preparation' | 'show'

const CATEGORY_ICONS = ['✦', '★', '✧', '♬', '⚔', '☻', '♡', '✶'] as const

export function useHomeLandingOverviewPresentation(store: AwardsStore, authStore: AuthStore) {
  const role = computed<'guest' | 'user' | 'admin'>(() => {
    if (!authStore.session) return 'guest'
    return authStore.isAdmin ? 'admin' : 'user'
  })
  const isGuest = computed(() => role.value === 'guest')
  const isUser = computed(() => role.value === 'user')
  const isAdmin = computed(() => role.value === 'admin')
  const twitchUser = computed(() => authStore.session?.twitchUserId ?? 'local_user')
  const siteContent = computed(() => store.overview.siteContent)
  const faqItems = computed(() =>
    (store.overview.faq ?? []).filter((item) => item?.question && item.answer),
  )
  const publicStreamUrl = computed(() =>
    store.overview.siteContent.streamBanner.liveButtonUrl
    || 'https://twitch.tv/jayuhime',
  )
  const showDate = computed(() => store.overview.showDate)
  const showStartsAt = computed(() => store.overview.showStartsAt || '20:00:00')
  const currentYear = computed(() => store.overview.year ? String(store.overview.year) : '')
  const displayCategories = computed<HomeDisplayCategory[]>(() =>
    store.categories.categories.map((category, index) => ({
      id: String(category.id),
      groupName: category.groupName,
      name: category.name,
      icon: CATEGORY_ICONS[index % CATEGORY_ICONS.length] ?? '✦',
      maxNomineesPerUser: category.maxNomineesPerUser,
      candidates: category.candidates,
    })),
  )
  const landingCategories = computed<HomeLandingCategory[]>(() => {
    if (store.overview.featuredCategories.length > 0) {
      return store.overview.featuredCategories.map((category, index) => {
        const matchingSubcategories = displayCategories.value.filter((item) => item.groupName === category.groupName)
        const subcategoryNames = matchingSubcategories
          .map((item) => item.name.trim())
          .filter(Boolean)
        return {
          id: String(category.id),
          groupName: category.groupName,
          name: category.groupName,
          icon: CATEGORY_ICONS[index % CATEGORY_ICONS.length] ?? '✦',
          description: category.description,
          maxNomineesPerUser: category.maxNomineesPerUser,
          subcategoryNames,
        }
      })
    }

    const seenGroups = new Set<string>()
    return displayCategories.value.flatMap((category, index) => {
      const groupKey = category.groupName.trim().toLowerCase()
      if (seenGroups.has(groupKey)) {
        return []
      }

      seenGroups.add(groupKey)
      const matchingSubcategories = displayCategories.value.filter((item) => item.groupName.trim().toLowerCase() === groupKey)
      const subcategoryNames = matchingSubcategories
        .map((item) => item.name.trim())
        .filter(Boolean)
      return [{
        id: category.id,
        groupName: category.groupName,
        name: category.groupName,
        icon: CATEGORY_ICONS[index % CATEGORY_ICONS.length] ?? '✦',
        description: '',
        maxNomineesPerUser: category.maxNomineesPerUser,
        subcategoryNames,
      }]
    })
  })
  const candidateCount = computed(() =>
    displayCategories.value.reduce((sum, category) => sum + category.candidates.length, 0),
  )
  const bootstrapArchiveYears = computed<Array<{ year: number }>>(() =>
    (store.overview.archiveYears ?? []).length > 0
      ? (store.overview.archiveYears ?? []).map((entry) => ({ year: entry.year }))
      : [{ year: store.overview.year - 1 }],
  )

  function timelineItem(key: HomeTimelineKey) {
    return store.overview.timeline.find((entry) => entry.key === key)
  }

  function formatRange(key: Exclude<HomeTimelineKey, 'show'>) {
    const item = timelineItem(key)
    if (!item) return ''
    return `${formatDateLabel(item.startsAt)} – ${formatDateLabel(item.endsAt)}`
  }

  function formatTimelineRange(key: HomeTimelineKey) {
    const item = timelineItem(key)
    if (!item) return 'Noch offen'
    return item.startsAt === item.endsAt
      ? formatDateLabel(item.startsAt)
      : `${formatDateLabel(item.startsAt)} – ${formatDateLabel(item.endsAt)}`
  }

  function formatShowDate() {
    return formatDateLabel(store.overview.showDate)
  }

  return {
    role,
    isGuest,
    isUser,
    isAdmin,
    twitchUser,
    siteContent,
    faqItems,
    publicStreamUrl,
    showDate,
    showStartsAt,
    currentYear,
    displayCategories,
    landingCategories,
    candidateCount,
    bootstrapArchiveYears,
    formatRange,
    formatTimelineRange,
    formatShowDate,
    initialsFor,
  }
}

export function useHomeModalCandidatePresentation(params: {
  displayCategories: ComputedRef<HomeDisplayCategory[]>
  activeCat: Ref<number>
  modal: Ref<null | HomeInteractionModalKind>
  votes: Ref<Record<string, number>>
  activeCategory: ComputedRef<HomeDisplayCategory | null>
  setCat: (index: number) => void
  pickNominee: (categoryId: string, index: number) => void
}) {
  const {
    displayCategories,
    activeCat,
    modal,
    votes,
    activeCategory,
    setCat,
    pickNominee,
  } = params

  const catList = computed(() => buildCatList(displayCategories, activeCat, votes, setCat))
  const noms = computed(() => {
    const cat = activeCategory.value
    const list = cat?.candidates ?? []
    const voteMode = modal.value === 'vote'
    return list.map((candidate, idx) => {
      const selected = cat ? votes.value[cat.id] === idx : false
      const clipUrl = candidate.clipUrl?.trim() || null
      const clipTitle = candidate.clipTitle?.trim() || 'Highlight-Clip ansehen'
      const clipPlatform = clipUrl ? candidate.clipPlatform?.trim() || candidate.platform : 'Clip fehlt'
      const clipEmbed = clipUrl && candidate.clipEmbedStatus !== 'link_only' ? buildClipEmbed(clipUrl) : null
      return {
        name: candidate.displayName,
        handle: candidate.channelSlug,
        url: resolveCandidateUrl(candidate.channelUrl, candidate.channelSlug),
        platform: candidate.platform,
        initials: initialsFor(candidate.displayName),
        clipUrl,
        clipTitle,
        clipPlatform,
        clipEmbedUrl: clipEmbed?.src ?? null,
        clipEmbedTitle: clipEmbed?.title ?? clipTitle,
        idx,
        selected,
        hasClip: Boolean(clipUrl),
        showPick: voteMode,
        onPick: () => cat && pickNominee(cat.id, idx),
        cardStyle: `display:flex;align-items:center;justify-content:space-between;gap:12px;padding:13px 15px;border-radius:13px;transition:all .15s;border:1.5px solid ${selected ? '#8b6cdb;background:#f6f1fd;' : '#ece4f6;background:#fff;'}`,
        btnStyle: "flex:none;white-space:nowrap;padding:8px 16px;border-radius:9px;border:none;cursor:pointer;font-family:'Outfit',sans-serif;font-weight:600;font-size:13px;transition:all .15s;" + (selected ? 'background:linear-gradient(135deg,#8b6cdb,#7355c8);color:#fff;' : 'background:#f1ecfb;color:#8b6cdb;'),
        btnLabel: selected ? 'Auswahl entfernen' : 'Für Clip voten',
      }
    })
  })

  return {
    catList,
    noms,
  }
}

function resolveCandidateUrl(channelUrl: string | null | undefined, channelSlug: string) {
  const url = channelUrl?.trim() || channelSlug.trim()
  if (!isHttpUrl(url) || url === '#') return null
  return url
}

function isHttpUrl(value: string) {
  try {
    const url = new URL(value)
    return url.protocol === 'http:' || url.protocol === 'https:'
  } catch {
    return false
  }
}

function formatDateLabel(value: string) {
  if (!value) return 'Noch nicht terminiert'
  const date = new Date(`${value}T00:00:00`)
  return Number.isNaN(date.getTime())
    ? value
    : date.toLocaleDateString('de-DE', { day: '2-digit', month: 'short', year: 'numeric' })
}

function initialsFor(value: string) {
  return value
    .split(/[\s&.-]+/)
    .filter(Boolean)
    .slice(0, 2)
    .map((part) => part[0]?.toUpperCase() ?? '')
    .join('')
}

function buildCatList(
  displayCategories: ComputedRef<HomeDisplayCategory[]>,
  activeCat: Ref<number>,
  votes: Ref<Record<string, number>>,
  setCat: (index: number) => void,
) {
  const baseRow = "display:flex;align-items:center;gap:10px;padding:11px 13px;border-radius:11px;cursor:pointer;font-size:14px;font-weight:600;transition:all .15s;border:1px solid transparent;outline:none;-webkit-tap-highlight-color:transparent;text-align:left;width:100%;background:transparent;font-family:'Outfit',sans-serif;"
  return displayCategories.value.map((category, index) => {
    const active = index === activeCat.value
    const done = votes.value[category.id] != null
    return {
      name: category.name,
      groupName: category.groupName,
      displayName: `${category.groupName} · ${category.name}`,
      icon: category.icon,
      idx: index,
      done,
      candidateCount: category.candidates.length,
      onClick: () => setCat(index),
      rowStyle: baseRow + (active ? 'background:#f1ecfb;border-color:#d8c9f2;color:#5f44ad;' : 'border-color:transparent;color:#6f6685;'),
      iconStyle: "flex:none;display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:8px;font-size:14px;" + (active ? 'background:linear-gradient(135deg,#8b6cdb,#7355c8);color:#fff;' : 'background:#efe7fb;color:#9a7fce;'),
      checkStyle: `flex:none;margin-left:auto;color:#1f9d5a;font-size:14px;font-weight:700;display:${done ? 'inline' : 'none'};`,
    }
  })
}
