import { computed } from 'vue'
import { loadVehicleDetailSnapshot } from '~/content/vehicles'
import { usePublicLocale } from '~/composables/usePublicLocale'
import { DEFAULT_PUBLIC_LOCALE, normalizePublicLocale } from '~/utils/public-locales'
import {
  dedupeCityRentalVehicles,
  normalizeCityRentalVehicleRecord,
} from '~/components/city-rental/vehicle-adapter'

const cityRentalVehicleModules = import.meta.glob('../generated/site/vehicles/by-slug/*.js')

const cityRentalVehicleCache = new Map()
const cityRentalVehicleDetailCache = new Map()

function uniqueValues(values = []) {
  return [...new Set((Array.isArray(values) ? values : [])
    .map((value) => normalizePublicLocale(value || DEFAULT_PUBLIC_LOCALE))
    .filter(Boolean))]
}

function cityRentalVehicleModuleKey(locale = DEFAULT_PUBLIC_LOCALE) {
  return `../generated/site/vehicles/by-slug/${normalizePublicLocale(locale)}.js`
}

async function loadCityRentalVehicleModule(locale = DEFAULT_PUBLIC_LOCALE) {
  const normalizedLocale = normalizePublicLocale(locale)

  for (const candidateLocale of uniqueValues([normalizedLocale, DEFAULT_PUBLIC_LOCALE])) {
    const loader = cityRentalVehicleModules[cityRentalVehicleModuleKey(candidateLocale)]

    if (!loader) {
      continue
    }

    const module = await loader()

    if (module?.vehiclesBySlug) {
      return module.vehiclesBySlug
    }
  }

  return {}
}

function cityRentalVehicleDetailCacheKey(locale = DEFAULT_PUBLIC_LOCALE, contentKey = '') {
  return `${normalizePublicLocale(locale)}:${String(contentKey || '').trim()}`
}

function cityRentalVehicleIdentity(vehicle = {}) {
  return String(
    vehicle?.contentKey
    || vehicle?.content_key
    || vehicle?.entityId
    || vehicle?.entity_id
    || vehicle?.id
    || vehicle?.slug
    || vehicle?.publicSlug
    || vehicle?.path
    || '',
  ).trim()
}

async function loadCityRentalVehicleDetail(locale = DEFAULT_PUBLIC_LOCALE, contentKey = '') {
  const normalizedLocale = normalizePublicLocale(locale)
  const normalizedContentKey = String(contentKey || '').trim()

  if (!normalizedContentKey) {
    return null
  }

  const cacheKey = cityRentalVehicleDetailCacheKey(normalizedLocale, normalizedContentKey)

  if (!cityRentalVehicleDetailCache.has(cacheKey)) {
    cityRentalVehicleDetailCache.set(cacheKey, (async () => {
      try {
        return await loadVehicleDetailSnapshot(normalizedContentKey, normalizedLocale)
      } catch {
        return null
      }
    })())
  }

  return cityRentalVehicleDetailCache.get(cacheKey)
}

async function normalizeCityRentalVehicleList(vehiclesBySlug = {}, locale = DEFAULT_PUBLIC_LOCALE) {
  const records = await Promise.all(Object.values(vehiclesBySlug || {})
    .map(async (item) => {
      const baseRecord = normalizeCityRentalVehicleRecord(item)

      if (!baseRecord?.contentKey) {
        return baseRecord
      }

      const detailRecord = await loadCityRentalVehicleDetail(locale, baseRecord.contentKey)

      if (!detailRecord) {
        return baseRecord
      }

      return normalizeCityRentalVehicleRecord({
        ...item,
        ...baseRecord,
        ...detailRecord,
        id: detailRecord.id || baseRecord.id,
        contentKey: detailRecord.contentKey || baseRecord.contentKey,
        content_key: detailRecord.content_key || baseRecord.content_key,
        entityId: detailRecord.entityId || baseRecord.entityId,
        entity_id: detailRecord.entity_id || baseRecord.entity_id,
        path: detailRecord.path || detailRecord.ctaUrl || baseRecord.path || baseRecord.ctaUrl,
        ctaUrl: detailRecord.ctaUrl || detailRecord.path || baseRecord.ctaUrl || baseRecord.path,
        image: detailRecord.image || detailRecord.heroImage || baseRecord.image || baseRecord.heroImage,
        heroImage: detailRecord.heroImage || detailRecord.image || baseRecord.heroImage || baseRecord.image,
        gallery: Array.isArray(detailRecord.gallery) && detailRecord.gallery.length
          ? detailRecord.gallery
          : baseRecord.gallery,
        prices: detailRecord.prices || baseRecord.prices,
        deposit: detailRecord.deposit ?? baseRecord.deposit,
        photosCount: detailRecord.photosCount ?? baseRecord.photosCount,
        price: detailRecord.price ?? baseRecord.price,
        priceFrom: detailRecord.priceFrom ?? baseRecord.priceFrom ?? null,
        displayPriceFrom: detailRecord.displayPriceFrom ?? baseRecord.displayPriceFrom ?? null,
        baseDailyRate: detailRecord.baseDailyRate ?? baseRecord.baseDailyRate ?? null,
        priceNote: detailRecord.priceNote ?? baseRecord.priceNote ?? '',
      })
    }))

  return dedupeCityRentalVehicles(records).sort((left, right) => {
    const leftOrder = Number(left.homeSortOrder || Number.MAX_SAFE_INTEGER)
    const rightOrder = Number(right.homeSortOrder || Number.MAX_SAFE_INTEGER)

    if (leftOrder !== rightOrder) {
      return leftOrder - rightOrder
    }

    const leftPrice = Number(left.price || 0)
    const rightPrice = Number(right.price || 0)

    if (leftPrice !== rightPrice) {
      return leftPrice - rightPrice
    }

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

export async function loadCityRentalVehiclesSnapshot(locale = DEFAULT_PUBLIC_LOCALE) {
  const normalizedLocale = normalizePublicLocale(locale)

  if (!cityRentalVehicleCache.has(normalizedLocale)) {
    cityRentalVehicleCache.set(normalizedLocale, (async () => {
      const vehiclesBySlug = await loadCityRentalVehicleModule(normalizedLocale)

      return normalizeCityRentalVehicleList(vehiclesBySlug, normalizedLocale)
    })())
  }

  return cityRentalVehicleCache.get(normalizedLocale)
}

export function mergeCityRentalVehicles(baseVehicles = [], fallbackVehicles = []) {
  const fallbackLookup = new Map()

  for (const vehicle of Array.isArray(fallbackVehicles) ? fallbackVehicles : []) {
    for (const candidate of [
      cityRentalVehicleIdentity(vehicle),
      String(vehicle?.path || '').trim(),
      String(vehicle?.slug || '').trim(),
      String(vehicle?.publicSlug || '').trim(),
    ]) {
      if (candidate) {
        fallbackLookup.set(candidate, vehicle)
      }
    }
  }

  const merged = (Array.isArray(baseVehicles) ? baseVehicles : []).map((vehicle) => {
    const fallback = fallbackLookup.get(cityRentalVehicleIdentity(vehicle)) || null

    if (!fallback) {
      return vehicle
    }

    return {
      ...vehicle,
      ...fallback,
      id: vehicle?.id || fallback?.id || '',
      contentKey: fallback?.contentKey || vehicle?.contentKey || vehicle?.content_key || '',
      content_key: fallback?.content_key || fallback?.contentKey || vehicle?.content_key || vehicle?.contentKey || '',
      entityId: fallback?.entityId || vehicle?.entityId || vehicle?.contentKey || vehicle?.content_key || '',
      entity_id: fallback?.entity_id || fallback?.entityId || vehicle?.entity_id || vehicle?.entityId || vehicle?.contentKey || vehicle?.content_key || '',
      path: fallback?.path || fallback?.ctaUrl || vehicle?.path || vehicle?.ctaUrl || '',
      ctaUrl: fallback?.ctaUrl || fallback?.path || vehicle?.ctaUrl || vehicle?.path || '',
      image: fallback?.image || fallback?.heroImage || vehicle?.image || vehicle?.heroImage || '',
      heroImage: fallback?.heroImage || fallback?.image || vehicle?.heroImage || vehicle?.image || '',
      gallery: Array.isArray(fallback?.gallery) && fallback.gallery.length
        ? fallback.gallery
        : (Array.isArray(vehicle?.gallery) ? vehicle.gallery : []),
      prices: fallback?.prices || vehicle?.prices || {},
      price: fallback?.price ?? fallback?.displayPriceFrom ?? fallback?.priceFrom ?? vehicle?.price ?? 0,
      displayPriceFrom: fallback?.displayPriceFrom ?? vehicle?.displayPriceFrom ?? null,
      priceFrom: fallback?.priceFrom ?? vehicle?.priceFrom ?? null,
      baseDailyRate: fallback?.baseDailyRate ?? vehicle?.baseDailyRate ?? null,
      priceNote: fallback?.priceNote ?? vehicle?.priceNote ?? '',
      deposit: fallback?.deposit ?? vehicle?.deposit ?? null,
      photosCount: fallback?.photosCount ?? vehicle?.photosCount ?? 0,
      specs: fallback?.specs || vehicle?.specs || {},
    }
  })

  return dedupeCityRentalVehicles(merged.length ? merged : (Array.isArray(fallbackVehicles) ? fallbackVehicles : []))
}

export function useCityRentalVehicles() {
  const { locale } = usePublicLocale()

  const { data: cityRentalVehiclesData } = useAsyncData(
    () => `city-rental-vehicles:${normalizePublicLocale(locale.value)}`,
    () => loadCityRentalVehiclesSnapshot(locale.value),
    {
      watch: [locale],
      default: () => [],
    },
  )

  const cityRentalVehicles = computed(() => Array.isArray(cityRentalVehiclesData.value)
    ? cityRentalVehiclesData.value
    : [])

  return {
    cityRentalVehicles,
  }
}
