import { computed } from 'vue'
import { locationsBySlug, siteLocationsSnapshot } from '~/generated/site/locations'
import { useResolvedPage } from '~/content/pages'
import {
  buildContentRouteSeo,
  resolveContentLocalizedEntry,
  resolveContentRouteGroup,
  resolveContentRoutePath,
} from '~/content/site-route-groups'
import { usePublicLocale } from '~/composables/usePublicLocale'
import { usePublicUi } from '~/composables/usePublicUi'
import { DEFAULT_PUBLIC_LOCALE, normalizePublicLocale } from '~/utils/public-locales'
import { buildRentSearchRoute, buildRentTripQuery, normalizePublicInternalPath } from '~/utils/public-routes'

const cityOrder = {
  Tbilisi: 10,
  Batumi: 20,
  Kutaisi: 30,
}

const typeOrder = {
  airport: 10,
  office: 20,
  delivery: 30,
}

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

function inferPointType(location) {
  if (location.isAirport || location.type === 'airport') {
    return 'airport'
  }

  if (String(location.name || '').toLowerCase().includes('office')) {
    return 'office'
  }

  return 'delivery'
}

function locationTypeLabels(ui = {}) {
  return {
    airport: ui.typeAirport || 'Airport',
    office: ui.typeOffice || 'Office',
    delivery: ui.typeDelivery || 'Delivery',
  }
}

function buildCityTypeLabel(locations, ui) {
  const pointTypes = new Set(locations.map((location) => inferPointType(location)))
  const labels = []
  const typeLabels = locationTypeLabels(ui)

  if (pointTypes.has('airport')) {
    labels.push(typeLabels.airport)
  }

  if (pointTypes.has('office')) {
    labels.push(typeLabels.office)
  }

  if (pointTypes.has('delivery')) {
    labels.push(typeLabels.delivery)
  }

  return labels.join(', ')
}

function buildMapUrl(location) {
  if (location?.mapUrl) {
    return location.mapUrl
  }

  const query = location?.address || location?.name || ''

  if (!query) {
    return ''
  }

  return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(query)}`
}

function pickPreferredCityLocation(locations) {
  const ranked = [...locations].sort((left, right) => {
    const leftPriority = typeOrder[inferPointType(left)] ?? 99
    const rightPriority = typeOrder[inferPointType(right)] ?? 99

    if (leftPriority !== rightPriority) {
      return leftPriority - rightPriority
    }

    return Number(left.id || 0) - Number(right.id || 0)
  })

  return ranked[0] || null
}

function resolveLocationLocalizedContent(location, locale = DEFAULT_PUBLIC_LOCALE) {
  const localized = location?.localizedContent && typeof location.localizedContent === 'object'
    ? location.localizedContent
    : {}

  return localized[locale] || localized[DEFAULT_PUBLIC_LOCALE] || {}
}

function mergeLocationForLocale(location, locale = DEFAULT_PUBLIC_LOCALE) {
  if (!location) {
    return null
  }

  const localizedContent = resolveLocationLocalizedContent(location, locale)
  const routeGroup = resolveContentRouteGroup('location', location)
  const routePath = resolveContentRoutePath(routeGroup, locale, '')
  const routeSeo = buildContentRouteSeo(routeGroup, locale, location?.seo || {})

  return {
    ...location,
    name: localizedContent.name || location.name,
    cityName: localizedContent.cityName || location.cityName || location.city,
    cityDescription: localizedContent.cityDescription || location.cityDescription || '',
    cityText: localizedContent.cityText || location.cityText || '',
    publicCodeLabel: localizedContent.publicCodeLabel || location.publicCodeLabel || '',
    path: routePath || location.path || '',
    availableLocales: routeGroup?.availableLocales || location?.availableLocales || location?.available_locales || [],
    available_locales: routeGroup?.available_locales || location?.available_locales || location?.availableLocales || [],
    localized: routeGroup?.localized || location?.localized || [],
    redirectFrom: routeGroup?.redirectFrom || location?.redirectFrom || location?.redirect_from || [],
    redirect_from: routeGroup?.redirect_from || location?.redirect_from || location?.redirectFrom || [],
    seo: routeSeo,
  }
}

function sortCities(left, right) {
  const leftPriority = cityOrder[left.city] ?? 999
  const rightPriority = cityOrder[right.city] ?? 999

  if (leftPriority !== rightPriority) {
    return leftPriority - rightPriority
  }

  return String(left.city || '').localeCompare(String(right.city || ''))
}

function sortLocationPoints(left, right) {
  const leftPriority = typeOrder[inferPointType(left)] ?? 99
  const rightPriority = typeOrder[inferPointType(right)] ?? 99

  if (leftPriority !== rightPriority) {
    return leftPriority - rightPriority
  }

  return String(left.name || '').localeCompare(String(right.name || ''))
}

function activeLocationSnapshot() {
  return siteLocationsSnapshot.filter((location) => String(location?.locale || DEFAULT_PUBLIC_LOCALE) === DEFAULT_PUBLIC_LOCALE)
}

function buildLocationSearchRoute(locationId, locale) {
  const numericId = Number(locationId || 0)

  if (numericId <= 0) {
    return buildRentSearchRoute({}, { locale })
  }

  return buildRentSearchRoute(buildRentTripQuery({
    pickupLocationId: numericId,
    dropoffLocationId: numericId,
    returnToSameLocation: '1',
  }), {
    locale,
  })
}

function buildLocationDetailRoute(location, locale = DEFAULT_PUBLIC_LOCALE) {
  const routeGroup = resolveContentRouteGroup('location', location)
  const exactPath = resolveContentRoutePath(routeGroup, locale, '')

  if (exactPath) {
    return exactPath
  }

  return normalizePublicInternalPath('/locations', locale)
}

function groupLocationsByCity(locationsContentPage, locale, ui) {
  const grouped = new Map()

  activeLocationSnapshot().forEach((location) => {
    const city = location.citySlug || location.cityName || location.city

    if (!city) {
      return
    }

    if (!grouped.has(city)) {
      grouped.set(city, [])
    }

    grouped.get(city).push(location)
  })

  return [...grouped.entries()].map(([city, locations]) => {
    const sortedLocations = [...locations].sort(sortLocationPoints)
    const primaryLocation = sortedLocations[0] || null
    const primaryLocalized = resolveLocationLocalizedContent(primaryLocation, locale)
    const snapshotMedia = locations.find((location) => location.cityHeroImage)?.cityHeroImage
    const snapshotDescription = locations.find((location) => location.cityDescription)?.cityDescription
    const preferredLocation = pickPreferredCityLocation(sortedLocations)
    const preferredLocationId = preferredLocation?.id ?? null
    const cityLabel = primaryLocalized.cityName || primaryLocation?.cityName || primaryLocation?.city || city

    return {
      city,
      cityLabel,
      type: buildCityTypeLabel(sortedLocations, ui),
      image: snapshotMedia || locationsContentPage?.heroImage || locationsContentPage?.featuredImage || '',
      description: primaryLocalized.cityDescription || snapshotDescription || '',
      searchCtaUrl: buildLocationSearchRoute(preferredLocationId, locale),
      points: sortedLocations.map((location) => {
        const localizedLocation = mergeLocationForLocale(location, locale)

        return {
          id: localizedLocation.id,
          code: localizedLocation.code,
          slug: localizedLocation.slug,
          name: localizedLocation.name,
          label: localizedLocation.name,
          type: inferPointType(localizedLocation),
          mapUrl: buildMapUrl(localizedLocation),
          detailUrl: buildLocationDetailRoute(localizedLocation, locale),
        }
      }),
    }
  }).sort(sortCities)
}

export function createStaticLocationsSnapshot() {
  return activeLocationSnapshot().map((location) => ({ ...location }))
}

export function resolveLocationBySlug(slug, locale = DEFAULT_PUBLIC_LOCALE) {
  const normalizedSlug = String(slug || '').trim().replace(/^\/+|\/+$/g, '')

  if (!normalizedSlug) {
    return null
  }

  const routeGroup = resolveContentRouteGroup('location', normalizedSlug)
  const routeContentKey = String(routeGroup?.contentKey || '').trim()
  const normalizedRouteContentKey = routeContentKey.replace(/^location_/i, '')
  const resolvedByRoute = routeContentKey
    ? activeLocationSnapshot().find((location) => {
      const locationContentKey = String(location?.contentKey || '').trim()
      const locationId = String(location?.id || '').trim()

      return uniqueValues([
        locationContentKey,
        locationContentKey.replace(/^location_/i, ''),
        locationId,
      ]).includes(normalizedRouteContentKey)
    })
    : null
  const resolvedBySlug = locationsBySlug[normalizedSlug]
    || activeLocationSnapshot().find((location) => uniqueValues([
      location?.slug,
      location?.publicSlug,
    ]).includes(normalizedSlug))
    || null
  const resolved = resolvedByRoute || resolvedBySlug

  if (!resolved) {
    return null
  }

  return {
    ...mergeLocationForLocale(resolved, locale),
    cityHeroImage: resolved.cityHeroImage || '',
  }
}

export function buildLocationsPageSeo(page, locale, origin = '') {
  const localizedPath = page?.path || ''
  const localized = Array.isArray(page?.localized) ? page.localized : []
  const hreflang = Array.isArray(page?.seo?.hreflang) && page.seo.hreflang.length
    ? page.seo.hreflang
    : localized
      .filter((entry) => entry?.locale && (entry?.href || entry?.path))
      .map((entry) => ({
        locale: entry.locale,
        href: entry.href || `${origin}${entry.path}`,
      }))

  return {
    title: page?.seo?.title || `${page?.title || 'Locations'} | bent.ge`,
    description: page?.seo?.description || page?.excerpt || '',
    ogTitle: page?.seo?.ogTitle || page?.seo?.title || page?.title || '',
    ogDescription: page?.seo?.ogDescription || page?.seo?.description || page?.excerpt || '',
    ogImage: page?.seo?.ogImage || page?.heroImage || page?.featuredImage || '',
    canonical: page?.seo?.canonical || (localizedPath ? `${origin}${localizedPath}` : ''),
    hreflang,
    xDefault: page?.seo?.xDefault || localized.find((entry) => normalizePublicLocale(entry?.locale) === DEFAULT_PUBLIC_LOCALE)?.href || '',
    robots: page?.seo?.robots || 'index,follow',
  }
}

export function buildLocationDetailSeo(location, locale = DEFAULT_PUBLIC_LOCALE, origin = '') {
  const routeGroup = resolveContentRouteGroup('location', location)
  const routeLocalizedEntry = resolveContentLocalizedEntry(routeGroup, locale)
  const canonicalPath = resolveContentRoutePath(routeGroup, locale, location?.path || '') || location?.path || ''
  const routeSeo = buildContentRouteSeo(routeGroup, locale, location?.seo || {})
  const hreflang = Array.isArray(routeSeo?.hreflang) && routeSeo.hreflang.length
    ? routeSeo.hreflang
    : []
  const canonical = routeLocalizedEntry?.canonical
    || routeLocalizedEntry?.href
    || routeSeo?.canonical
    || (canonicalPath ? `${origin}${canonicalPath}` : '')

  return {
    title: `${location?.name || 'Location'} | bent.ge`,
    description: location?.cityDescription || routeSeo?.description || '',
    ogTitle: location?.name || routeSeo?.ogTitle || routeSeo?.title || '',
    ogDescription: location?.cityDescription || routeSeo?.ogDescription || routeSeo?.description || '',
    ogImage: routeSeo?.ogImage || location?.cityHeroImage || '',
    canonical,
    hreflang,
    xDefault: routeSeo?.xDefault || routeSeo?.x_default || canonical,
    robots: routeSeo?.robots || 'index,follow',
  }
}

export function useLocationsContent() {
  const resolvedLocationsContentPage = useResolvedPage('locations')
  const { locale } = usePublicLocale()
  const ui = usePublicUi()
  const locationsContentPage = computed(() => resolvedLocationsContentPage.value || {})

  const locationCityCards = computed(() => groupLocationsByCity(
    locationsContentPage.value,
    locale.value,
    ui.value.locationsPage || {},
  ))

  const locationsBanner = computed(() => ({
    title: locationsContentPage.value?.structuredContent?.banner?.title,
    description: locationsContentPage.value?.structuredContent?.banner?.description,
    ctaLabel: locationsContentPage.value?.structuredContent?.banner?.ctaLabel || locationsContentPage.value?.cta?.label,
    ctaUrl: normalizePublicInternalPath(locationsContentPage.value?.cta?.url, locale.value),
  }))

  const locationsUi = computed(() => ({
    searchCtaPrefix: locationsContentPage.value?.structuredContent?.ui?.searchCtaPrefix,
    emptyTitle: locationsContentPage.value?.structuredContent?.ui?.emptyTitle,
    emptyDescription: locationsContentPage.value?.structuredContent?.ui?.emptyDescription,
    pointLinkLabel: ui.value.locationsPage?.pointLinkLabel || 'Open point',
  }))

  return {
    locationsContentPage,
    locationCityCards,
    locationsBanner,
    locationsUi,
    resolveLocation: (slug) => resolveLocationBySlug(slug, locale.value),
    buildLocationSearchRoute: (locationId) => buildLocationSearchRoute(locationId, locale.value),
    buildLocationMapUrl: buildMapUrl,
  }
}
