import { useAsyncData } from '#imports'
import { computed, unref } from 'vue'
import { EMPTY_NEWS_EXPORT, loadNewsLocaleExport } from '~/content/news-export'
import {
  buildContentRouteSeo,
  resolveContentLocalizedEntry,
  resolveContentRouteGroup,
  resolveContentRoutePath,
} from '~/content/site-route-groups'
import { formatContentDate, toPublicIntlLocale } from '~/content/utils'
import { useResolvedPage } from '~/content/pages'
import { usePublicLocale } from '~/composables/usePublicLocale'
import { resolvePublicUiValue } from '~/i18n/public-ui'
import { DEFAULT_PUBLIC_LOCALE, normalizePublicLocale, toPublicLocaleCode } from '~/utils/public-locales'

function uniqueValues(values = []) {
  return [...new Set(values.map((value) => String(value || '').trim()).filter(Boolean))]
}

function newsLookupCandidates(identifier, locale = DEFAULT_PUBLIC_LOCALE) {
  if (typeof identifier === 'string') {
    const normalized = String(identifier || '').trim()
    const pathSlug = normalized.split('/').filter(Boolean).at(-1) || ''

    return uniqueValues([
      normalized,
      pathSlug,
      `${pathSlug}__${normalizePublicLocale(locale)}`,
    ])
  }

  const path = String(identifier?.path || '').trim()
  const pathSlug = path.split('/').filter(Boolean).at(-1) || ''
  const requestedLocale = normalizePublicLocale(identifier?.locale || locale)

  return uniqueValues([
    identifier?.contentKey,
    identifier?.content_key,
    identifier?.slug,
    identifier?.publicSlug,
    identifier?.id,
    path,
    pathSlug,
    identifier?.slug ? `${identifier.slug}__${requestedLocale}` : '',
    identifier?.publicSlug ? `${identifier.publicSlug}__${requestedLocale}` : '',
    pathSlug ? `${pathSlug}__${requestedLocale}` : '',
  ])
}

function lookupNewsValue(lookup = {}, candidates = []) {
  for (const candidate of candidates) {
    if (lookup?.[candidate]) {
      return lookup[candidate]
    }
  }

  return null
}

function resolveNewsPayloadEntry(payload = EMPTY_NEWS_EXPORT, identifier, locale = DEFAULT_PUBLIC_LOCALE) {
  const candidates = newsLookupCandidates(identifier, locale)
  const directMatch = lookupNewsValue(payload.newsBySlug || {}, candidates)

  if (directMatch) {
    return directMatch
  }

  const routeGroup = resolveContentRouteGroup('news', identifier)

  if (!routeGroup?.contentKey) {
    return null
  }

  return (payload.newsArticles || []).find((item) => String(item?.contentKey || '') === routeGroup.contentKey) || null
}

function localizeNewsCategory(value, locale = DEFAULT_PUBLIC_LOCALE) {
  const resolvedValue = String(value || '').trim()
  const path = {
    article: 'news.categoryArticles',
    articles: 'news.categoryArticles',
    news: 'news.categoryNews',
  }[resolvedValue.toLowerCase()]

  if (!path) {
    return resolvedValue
  }

  return resolvePublicUiValue(locale, path, resolvedValue)
}

function formatNewsDate(value, locale = DEFAULT_PUBLIC_LOCALE) {
  return formatContentDate(value, toPublicIntlLocale(locale)) || String(value || '').trim()
}

function formatNewsReadTime(article, locale = DEFAULT_PUBLIC_LOCALE) {
  const numericMinutes = Number(article?.readTimeMinutes || parseInt(String(article?.readTime || ''), 10))

  if (!Number.isFinite(numericMinutes) || numericMinutes <= 0) {
    return String(article?.readTime || '').trim()
  }

  return resolvePublicUiValue(locale, 'news.readTimeMinutesTemplate', '{count} min read')
    .replace('{count}', String(numericMinutes))
}

function decorateNewsArticleBody(body, currentLocale = DEFAULT_PUBLIC_LOCALE) {
  if (!body) {
    return null
  }

  return {
    ...body,
    badge: localizeNewsCategory(body?.badge || body?.category || '', currentLocale),
    category: localizeNewsCategory(body?.category || body?.badge || '', currentLocale),
    date: formatNewsDate(body?.publishedAt || body?.seo?.lastModified || body?.date, currentLocale),
    readTime: formatNewsReadTime(body, currentLocale),
  }
}

function decorateNewsArticle(article, currentLocale = DEFAULT_PUBLIC_LOCALE) {
  if (!article) {
    return null
  }

  const requestedLocale = normalizePublicLocale(currentLocale)
  const sourceLocale = normalizePublicLocale(article?.locale || requestedLocale)
  const routeGroup = resolveContentRouteGroup('news', article)
  const localizedRouteEntry = resolveContentLocalizedEntry(routeGroup, requestedLocale)
  const resolvedPath = resolveContentRoutePath(routeGroup, requestedLocale, article?.path || '')
  const seo = buildContentRouteSeo(routeGroup, requestedLocale, article?.seo || {})

  return {
    ...article,
    availableLocales: routeGroup?.availableLocales || [sourceLocale],
    available_locales: routeGroup?.available_locales || [sourceLocale],
    localized: routeGroup?.localized || [],
    redirectFrom: routeGroup?.redirectFrom || [],
    redirect_from: routeGroup?.redirect_from || [],
    path: resolvedPath || article?.path || '',
    resolvedPath: resolvedPath || article?.path || '',
    seo,
    canonical: localizedRouteEntry?.canonical || seo?.canonical || '',
    category: localizeNewsCategory(article?.category || '', requestedLocale),
    date: formatNewsDate(article?.publishedAt || article?.seo?.lastModified || article?.date, requestedLocale),
    readTime: formatNewsReadTime(article, requestedLocale),
    sourceLocale,
    sourceLocaleCode: toPublicLocaleCode(sourceLocale),
    isFallback: sourceLocale !== requestedLocale,
  }
}

function resolveNewsArticleBodyByEntity(payload = EMPTY_NEWS_EXPORT, article, fallbackIdentifier, locale = DEFAULT_PUBLIC_LOCALE) {
  const requestedLocale = normalizePublicLocale(article?.locale || locale)
  const routeGroup = resolveContentRouteGroup('news', article || fallbackIdentifier)
  const candidates = uniqueValues([
    ...newsLookupCandidates(article || fallbackIdentifier, requestedLocale),
    routeGroup?.contentKey,
    routeGroup?.contentKey ? `${routeGroup.contentKey}__${requestedLocale}` : '',
  ])

  return lookupNewsValue(payload.newsBodiesBySlug || {}, candidates)
    || lookupNewsValue(payload.newsArticleBodies || {}, candidates)
    || null
}

function resolveNewsArticleFromPayload(payload = EMPTY_NEWS_EXPORT, identifier, locale = DEFAULT_PUBLIC_LOCALE) {
  return decorateNewsArticle(resolveNewsPayloadEntry(payload, identifier, locale), locale)
}

function resolveNewsArticleBodyFromPayload(payload = EMPTY_NEWS_EXPORT, identifier, locale = DEFAULT_PUBLIC_LOCALE) {
  const article = resolveNewsArticleFromPayload(payload, identifier, locale)

  if (!article) {
    return null
  }

  return decorateNewsArticleBody(
    resolveNewsArticleBodyByEntity(payload, article, String(identifier || '').trim(), locale),
    locale,
  )
}

export function resolveNewsArticleRoute(article, locale = DEFAULT_PUBLIC_LOCALE) {
  return decorateNewsArticle(article, locale)?.resolvedPath || ''
}

export async function useNewsContent() {
  const { locale } = usePublicLocale()
  const newsIndex = useResolvedPage('news')
  const { data: newsExport } = await useAsyncData(
    () => `news-export:${normalizePublicLocale(locale.value)}`,
    () => loadNewsLocaleExport(locale.value),
    {
      watch: [locale],
      default: () => EMPTY_NEWS_EXPORT,
    },
  )

  const newsArticles = computed(() => (newsExport.value?.newsArticles || [])
    .map((item) => decorateNewsArticle(item, locale.value))
    .filter(Boolean))

  function useResolvedNewsArticle(idRef) {
    return computed(() => resolveNewsArticleFromPayload(newsExport.value || EMPTY_NEWS_EXPORT, unref(idRef), locale.value))
  }

  function useResolvedNewsArticleBody(idRef) {
    return computed(() => resolveNewsArticleBodyFromPayload(newsExport.value || EMPTY_NEWS_EXPORT, unref(idRef), locale.value))
  }

  return {
    newsIndex,
    newsArticles,
    useResolvedNewsArticle,
    useResolvedNewsArticleBody,
  }
}
