import { DEFAULT_PUBLIC_LOCALE, normalizePublicLocale, stripPublicLocalePrefix } from '~/utils/public-locales'

function normalizeEntityKey(value) {
  const raw = String(value || '').trim()

  if (!raw) {
    return ''
  }

  if (raw === '/') {
    return '/'
  }

  if (raw.startsWith('/')) {
    const path = stripPublicLocalePrefix(raw)
    return path === '/' ? '/' : path.replace(/\/+$/, '')
  }

  return raw.replace(/^\/+|\/+$/g, '')
}

function collectEntityKeys(entity) {
  const keys = new Set()

  const addKey = (value) => {
    const normalized = normalizeEntityKey(value)

    if (!normalized) {
      return
    }

    keys.add(normalized)

    if (normalized !== '/' && !normalized.startsWith('/')) {
      keys.add(`/${normalized}`)
    }
  }

  addKey(entity?.contentKey)
  addKey(entity?.slug)
  addKey(entity?.publicSlug)
  addKey(entity?.path)

  ;(entity?.localized || []).forEach((localized) => {
    addKey(localized?.slug)
    addKey(localized?.publicSlug)
    addKey(localized?.path)
  })

  return keys
}

function matchesEntity(entity, identifier) {
  const normalizedIdentifier = normalizeEntityKey(identifier)

  if (!normalizedIdentifier) {
    return false
  }

  return collectEntityKeys(entity).has(normalizedIdentifier)
}

function findLocalizedMatch(items, locale, identifiers) {
  return items.find((item) => {
    if (normalizePublicLocale(item?.locale) !== locale) {
      return false
    }

    return identifiers.some((identifier) => matchesEntity(item, identifier))
  }) || null
}

function getLocalizedIdentifiers(entity, locale) {
  return (entity?.localized || [])
    .filter((item) => normalizePublicLocale(item?.locale) === locale)
    .flatMap((item) => [item?.slug, item?.publicSlug, item?.path])
    .filter(Boolean)
}

export function resolveLocalizedEntity(items = [], identifier, locale = DEFAULT_PUBLIC_LOCALE) {
  const normalizedLocale = normalizePublicLocale(locale)
  const identifiers = [identifier].filter(Boolean)
  const directMatch = findLocalizedMatch(items, normalizedLocale, identifiers)

  if (directMatch) {
    return directMatch
  }

  const baseEntity = items.find((item) => identifiers.some((candidate) => matchesEntity(item, candidate))) || null

  if (!baseEntity) {
    return null
  }

  if (normalizePublicLocale(baseEntity.locale) === normalizedLocale) {
    return baseEntity
  }

  const localizedIdentifiers = getLocalizedIdentifiers(baseEntity, normalizedLocale)
  const localizedMatch = findLocalizedMatch(items, normalizedLocale, localizedIdentifiers)

  if (localizedMatch) {
    return localizedMatch
  }

  return baseEntity
}

export function resolveLocalizedCollection(items = [], locale = DEFAULT_PUBLIC_LOCALE) {
  const normalizedLocale = normalizePublicLocale(locale)
  const localizedItems = items.filter((item) => normalizePublicLocale(item?.locale) === normalizedLocale)

  if (localizedItems.length) {
    return localizedItems
  }

  const englishItems = items.filter((item) => normalizePublicLocale(item?.locale) === DEFAULT_PUBLIC_LOCALE)

  return englishItems.length ? englishItems : items
}

export function resolveLocalizedCollectionByKey(
  items = [],
  locale = DEFAULT_PUBLIC_LOCALE,
  resolveKey = (item) => item?.contentKey || item?.id || item?.slug || item?.path,
) {
  const normalizedLocale = normalizePublicLocale(locale)
  const groups = new Map()

  for (const item of items) {
    const key = String(resolveKey(item) || '').trim()

    if (!key) {
      continue
    }

    if (!groups.has(key)) {
      groups.set(key, [])
    }

    groups.get(key).push(item)
  }

  return [...groups.values()].map((group) => {
    const localized = group.find((item) => normalizePublicLocale(item?.locale) === normalizedLocale)

    if (localized) {
      return localized
    }

    const english = group.find((item) => normalizePublicLocale(item?.locale) === DEFAULT_PUBLIC_LOCALE)

    if (english) {
      return english
    }

    return group[0]
  })
}
