import { computed, unref } from 'vue'
import { format } from 'date-fns'
import { offerItems as rawOfferItems, offers as rawOffers, offersPage as rawOffersPage } from '~/generated/site/offers'
import { resolveOfferPresentation } from '~/content/offerPresentation'
import { resolveOfferPricingSummary, resolveOfferPricingTiers } from '~/content/offer-pricing'
import { resolveOfferMediaUrl } from '~/content/offer-media'
import {
  buildContentRouteSeo,
  resolveContentLocalizedEntry,
  resolveContentRouteGroup,
  resolveContentRoutePath,
} from '~/content/site-route-groups'
import { resolveFleetVehicle } from '~/content/vehicles'
import { resolveLocalizedCollection, resolveLocalizedCollectionByKey, resolveLocalizedEntity, 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'
import {
  buildRentExtrasRoute,
  buildRentSearchRoute,
  buildRentTripQuery,
  normalizeImplementedPublicInternalPath,
  normalizePublicInternalPath,
} from '~/utils/public-routes'

function ensureArray(value) {
  if (Array.isArray(value)) {
    return value
  }

  if (value === undefined || value === null || value === '') {
    return []
  }

  return [value]
}

function getOfferStructuredContent(item) {
  return item?.structuredContent && typeof item.structuredContent === 'object'
    ? item.structuredContent
    : {}
}

function splitBodyParagraphs(value) {
  return String(value || '')
    .split(/\n{2,}/)
    .map((item) => item.trim())
    .filter(Boolean)
}

function formatMoney(value, currency = 'USD') {
  const numericValue = Number(value)

  if (!Number.isFinite(numericValue)) {
    return null
  }

  const hasFraction = Math.abs(numericValue % 1) > 0.001

  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency,
    minimumFractionDigits: hasFraction ? 2 : 0,
    maximumFractionDigits: hasFraction ? 2 : 0,
  }).format(numericValue)
}

function formatDateLabel(value) {
  if (!value) {
    return null
  }

  const parsed = new Date(value)

  if (Number.isNaN(parsed.getTime())) {
    return null
  }

  return format(parsed, 'MMM d, yyyy')
}

function formatDateRangeLabel(pickupAt, dropoffAt) {
  const pickupLabel = formatDateLabel(pickupAt)
  const dropoffLabel = formatDateLabel(dropoffAt)

  if (pickupLabel && dropoffLabel) {
    return `${pickupLabel} - ${dropoffLabel}`
  }

  return pickupLabel || dropoffLabel || null
}

function resolveOffersPagePath(locale = DEFAULT_PUBLIC_LOCALE) {
  const normalizedLocale = normalizePublicLocale(locale)
  const localizedEntries = Array.isArray(rawOffersPage?.localized) ? rawOffersPage.localized : []
  const localizedEntry = localizedEntries.find((entry) => normalizePublicLocale(entry?.locale) === normalizedLocale)
  const defaultEntry = localizedEntries.find((entry) => normalizePublicLocale(entry?.locale) === DEFAULT_PUBLIC_LOCALE)

  return localizedEntry?.path || defaultEntry?.path || rawOffersPage?.path || '/offers'
}

function resolveOfferListEntities(locale) {
  const localizedOfferItems = resolveLocalizedCollectionByKey(
    rawOfferItems,
    locale,
    (item) => item?.contentKey || item?.slug || item?.id,
  )

  if (localizedOfferItems.length) {
    return localizedOfferItems
  }

  return resolveLocalizedCollectionByKey(
    rawOffers,
    locale,
    (item) => item?.contentKey || item?.slug || item?.id,
  )
}

function resolveOfferDetailEntity(identifier, locale) {
  const detailEntities = resolveLocalizedCollection(rawOffers, locale)
  const listEntities = resolveOfferListEntities(locale)

  return resolveLocalizedEntity(detailEntities.length ? detailEntities : listEntities, identifier, locale)
}

function resolveOfferSourceLocale(item, locale = DEFAULT_PUBLIC_LOCALE, routeGroup = null) {
  const requestedLocale = normalizePublicLocale(locale)
  const availableLocales = Array.isArray(routeGroup?.availableLocales) && routeGroup.availableLocales.length
    ? routeGroup.availableLocales
    : Array.isArray(item?.availableLocales) && item.availableLocales.length
    ? item.availableLocales.map((entry) => normalizePublicLocale(entry))
    : [normalizePublicLocale(item?.locale || DEFAULT_PUBLIC_LOCALE)]

  return availableLocales.includes(requestedLocale)
    ? requestedLocale
    : normalizePublicLocale(item?.locale || DEFAULT_PUBLIC_LOCALE)
}

function resolveOfferPath(item, locale, routeGroup = null) {
  const targetLocale = resolveOfferSourceLocale(item, locale, routeGroup)
  const routePath = resolveContentRoutePath(routeGroup, targetLocale, item?.path || '')

  if (routePath) {
    return routePath
  }

  const offersIndexPath = normalizePublicInternalPath(resolveOffersPagePath(targetLocale), targetLocale)
  const explicitPath = normalizeImplementedPublicInternalPath(item?.path, targetLocale)

  if (explicitPath && explicitPath !== offersIndexPath) {
    return explicitPath
  }

  const explicitCtaPath = normalizeImplementedPublicInternalPath(item?.cta?.url, targetLocale)

  if (explicitCtaPath && explicitCtaPath !== offersIndexPath) {
    return explicitCtaPath
  }

  return offersIndexPath
}

function resolveRelatedVehicle(item, locale = DEFAULT_PUBLIC_LOCALE) {
  const structuredContent = getOfferStructuredContent(item)
  const bookingPrefill = item?.bookingPrefill || structuredContent.bookingPrefill || {}
  const recommendedVehicle = item?.relatedVehicle
    || (structuredContent.relatedVehicle && typeof structuredContent.relatedVehicle === 'object' ? structuredContent.relatedVehicle : null)
      || (item?.recommendedVehicle && typeof item.recommendedVehicle === 'object' ? item.recommendedVehicle : null)
      || (structuredContent.recommendedVehicle && typeof structuredContent.recommendedVehicle === 'object' ? structuredContent.recommendedVehicle : {})
  const vehicleSlug = bookingPrefill.vehicleSlug || recommendedVehicle.slug || item?.vehicleSlug || null
  const vehicleGroupId = Number(bookingPrefill.vehicleGroupId || recommendedVehicle.vehicleGroupId || item?.vehicleGroupId || 0)
  const rawVehicle = resolveFleetVehicle(
    vehicleSlug || recommendedVehicle.contentKey || recommendedVehicle.entityId || recommendedVehicle.path || vehicleGroupId,
    locale,
  )

  if (recommendedVehicle && Object.keys(recommendedVehicle).length) {
    return {
      name: recommendedVehicle.name || [recommendedVehicle.brand, recommendedVehicle.model].filter(Boolean).join(' ') || rawVehicle?.name || rawVehicle?.brand || null,
      slug: recommendedVehicle.slug || rawVehicle?.slug || null,
      path: recommendedVehicle.path || rawVehicle?.path || null,
      image: recommendedVehicle.heroImage || recommendedVehicle.cardImage || recommendedVehicle.image || rawVehicle?.heroImage || rawVehicle?.image || null,
      category: recommendedVehicle.category || rawVehicle?.category || null,
      description: recommendedVehicle.description || rawVehicle?.description || null,
      vehicleGroupId: Number(recommendedVehicle.vehicleGroupId || vehicleGroupId || 0) || null,
    }
  }

  if (!rawVehicle) {
    return null
  }

  return {
    name: rawVehicle.name || [rawVehicle.brand, rawVehicle.model].filter(Boolean).join(' '),
    slug: rawVehicle.slug || rawVehicle.id,
    path: rawVehicle.path || null,
    image: rawVehicle.heroImage || rawVehicle.image || rawVehicle.cardImage || null,
    category: rawVehicle.category || null,
    description: rawVehicle.longDescription || rawVehicle.description || null,
    vehicleGroupId: Number(rawVehicle.vehicleGroupId || vehicleGroupId || 0) || null,
  }
}

function normalizeExtraItems(item) {
  const structuredContent = getOfferStructuredContent(item)
  const bookingPrefill = item?.bookingPrefill || structuredContent.bookingPrefill || {}
  const prefillExtras = bookingPrefill.prefillExtras
    || bookingPrefill.extras
    || item?.appliesTo?.extras
    || structuredContent?.appliesTo?.extras
    || []

  return ensureArray(prefillExtras)
    .map((entry) => {
      if (typeof entry === 'string') {
        return {
          code: entry,
          label: entry.replaceAll('_', ' '),
        }
      }

      return {
        code: entry?.code || entry?.id || entry?.slug || '',
        label: entry?.label || entry?.title || entry?.name || String(entry?.code || entry?.id || '').replaceAll('_', ' '),
      }
    })
    .filter((entry) => entry.code || entry.label)
}

function normalizeBookingPrefill(item, locale = DEFAULT_PUBLIC_LOCALE) {
  const structuredContent = getOfferStructuredContent(item)
  const source = item?.bookingPrefill || structuredContent.bookingPrefill || {}
  const relatedVehicle = resolveRelatedVehicle(item, locale)
  const extras = normalizeExtraItems(item)
  const pickupLocationId = Number(source.pickupLocationId || item?.pickupLocationId || 0) || null
  const dropoffLocationId = Number(source.dropoffLocationId || item?.dropoffLocationId || pickupLocationId || 0) || null
  const vehicleGroupId = Number(source.vehicleGroupId || item?.vehicleGroupId || relatedVehicle?.vehicleGroupId || 0) || null
  const returnToSameLocation = String(source.returnToSameLocation ?? item?.returnToSameLocation ?? (pickupLocationId && pickupLocationId === dropoffLocationId ? '1' : '0'))
  const promoCode = String(source.promoCode || item?.promo?.code || item?.promoCode || '').trim()
  const driverAge = String(source.driverAge || item?.driverAge || '').trim()

  return {
    pickupLocationId,
    dropoffLocationId,
    pickupAt: source.pickupAt || item?.pickupAt || item?.validFrom || null,
    dropoffAt: source.dropoffAt || item?.dropoffAt || item?.validTo || null,
    promoCode,
    vehicleGroupId,
    vehicleSlug: source.vehicleSlug || item?.vehicleSlug || relatedVehicle?.slug || null,
    prefillExtra: String(source.prefillExtra || extras[0]?.code || '').trim() || null,
    prefillExtras: extras.map((entry) => entry.code).filter(Boolean),
    driverAge: driverAge || null,
    returnToSameLocation: returnToSameLocation === '1' ? '1' : '0',
  }
}

function buildOfferFocusCards(item, bookingPrefill, relatedVehicle, locale = 'en') {
  const focusCards = []
  const dateRangeLabel = formatDateRangeLabel(bookingPrefill.pickupAt, bookingPrefill.dropoffAt)
  const promoCode = bookingPrefill.promoCode
  const extras = normalizeExtraItems(item)

  if (relatedVehicle?.name) {
    focusCards.push({
      id: 'vehicle',
      title: resolvePublicUiValue(locale, 'offers.offerVehicle'),
      value: relatedVehicle.name,
      description: relatedVehicle.category || relatedVehicle.description || resolvePublicUiValue(locale, 'offers.offerVehicleDescription'),
    })
  }

  if (dateRangeLabel) {
    focusCards.push({
      id: 'dates',
      title: resolvePublicUiValue(locale, 'offers.suggestedDates'),
      value: dateRangeLabel,
      description: resolvePublicUiValue(locale, 'offers.suggestedDatesDescription'),
    })
  }

  if (promoCode) {
    focusCards.push({
      id: 'promo',
      title: resolvePublicUiValue(locale, 'offers.promoCode'),
      value: promoCode,
      description: resolvePublicUiValue(locale, 'offers.promoCodeDescription'),
    })
  }

  if (extras.length) {
    focusCards.push({
      id: 'extras',
      title: resolvePublicUiValue(locale, 'offers.includedFocus'),
      value: extras.map((entry) => entry.label).join(', '),
      description: resolvePublicUiValue(locale, 'offers.includedFocusDescription'),
    })
  }

  return focusCards
}

function normalizeDetailSections(item) {
  const structuredContent = getOfferStructuredContent(item)

  return ensureArray(item?.detailSections || structuredContent.detailSections)
    .map((section, index) => ({
      id: section?.id || `section-${index + 1}`,
      eyebrow: section?.eyebrow || null,
      title: section?.title || null,
      description: section?.description || null,
      items: ensureArray(section?.items).map((entry) => ({
        title: entry?.title || entry?.label || entry?.name || null,
        description: entry?.description || null,
      })),
    }))
    .filter((section) => section.title || section.description || section.items.length)
}

export function resolveOfferForVehicleGroupId(offers = [], vehicleGroupId = null) {
  const numericId = Number(vehicleGroupId || 0)

  if (!numericId) {
    return null
  }

  return (Array.isArray(offers) ? offers : []).find((offer) => {
    const offerVehicleGroupId = Number(
      offer?.bookingPrefill?.vehicleGroupId
      || offer?.relatedVehicle?.vehicleGroupId
      || offer?.vehicleGroupId
      || 0,
    )

    return offerVehicleGroupId === numericId
  }) || null
}

function normalizeOfferDetail(item, locale, offersPage = rawOffersPage) {
  if (!item) {
    return null
  }

  const requestedLocale = normalizePublicLocale(locale)
  const routeGroup = resolveContentRouteGroup('offer', item)
  const sourceLocale = resolveOfferSourceLocale(item, requestedLocale, routeGroup)
  const localizedRouteEntry = resolveContentLocalizedEntry(routeGroup, requestedLocale)
  const page = offersPage || rawOffersPage
  const fallbackPresentation = {
    discount: page?.structuredContent?.ui?.defaultBadge || '',
    tags: item.tags?.length ? item.tags : (item.category ? [item.category] : []),
    validUntil: page?.structuredContent?.ui?.defaultValidity || resolvePublicUiValue(locale, 'offers.offerDetailsAvailable'),
    color: 'bg-brand-orange',
  }
  const itemPresentation = item.presentation || {}
  const pricingSummary = resolveOfferPricingSummary(item)
  const pricingTiers = resolveOfferPricingTiers(item)
  const presentation = resolveOfferPresentation(item.slug, {
    ...fallbackPresentation,
    discount: itemPresentation.discountLabel || fallbackPresentation.discount,
    tags: itemPresentation.tags?.length ? itemPresentation.tags : fallbackPresentation.tags,
    validUntil: itemPresentation.validUntilLabel || item.validity || fallbackPresentation.validUntil,
    color: itemPresentation.theme || fallbackPresentation.color,
    oldPrice: itemPresentation.homeCard?.oldPrice ? formatMoney(itemPresentation.homeCard.oldPrice, itemPresentation.homeCard.currency) : fallbackPresentation.oldPrice,
    newPrice: itemPresentation.homeCard?.newPrice ? formatMoney(itemPresentation.homeCard.newPrice, itemPresentation.homeCard.currency) : fallbackPresentation.newPrice,
    rating: itemPresentation.homeCard?.rating || fallbackPresentation.rating,
    reviews: itemPresentation.homeCard?.reviewCount || fallbackPresentation.reviews,
  })
  const relatedVehicle = resolveRelatedVehicle(item, locale)
  const bookingPrefill = normalizeBookingPrefill(item, locale)
  const focusCards = buildOfferFocusCards(item, bookingPrefill, relatedVehicle, locale)
  const detailSections = normalizeDetailSections(item)
  const fallbackParagraphs = splitBodyParagraphs(item.body || item.excerpt)
  const description = item.excerpt || item.body || page?.structuredContent?.ui?.defaultDescription || ''
  const ctaLabel = item.cta?.label || page?.structuredContent?.ui?.manualCtaLabel || resolvePublicUiValue(locale, 'offers.claimOffer')
  const detailPath = resolveOfferPath(item, locale, routeGroup)
  const seo = buildContentRouteSeo(routeGroup, requestedLocale, item?.seo || {})
  const rentQuery = {
    ...buildRentTripQuery({
      pickupLocationId: bookingPrefill.pickupLocationId || undefined,
      dropoffLocationId: bookingPrefill.dropoffLocationId || bookingPrefill.pickupLocationId || undefined,
      pickupAt: bookingPrefill.pickupAt || undefined,
      dropoffAt: bookingPrefill.dropoffAt || undefined,
      promoCode: bookingPrefill.promoCode || undefined,
      prefillExtra: bookingPrefill.prefillExtra || undefined,
      returnToSameLocation: bookingPrefill.returnToSameLocation || undefined,
      driverAge: bookingPrefill.driverAge || undefined,
      offerSlug: item.slug || item.publicSlug || item.id || undefined,
    }),
  }

  if (bookingPrefill.prefillExtras.length > 1) {
    rentQuery.prefillExtras = bookingPrefill.prefillExtras.join(',')
  }

  const bookingDestination = bookingPrefill.vehicleGroupId
    ? buildRentExtrasRoute(bookingPrefill.vehicleGroupId, rentQuery, { locale })
    : buildRentSearchRoute(rentQuery, { locale })

  return {
    id: item.slug || item.id,
    slug: item.slug || item.publicSlug || item.id,
    path: detailPath,
    sourceLocale,
    sourceLocaleCode: toPublicLocaleCode(sourceLocale),
    isFallback: sourceLocale !== requestedLocale,
    availableLocales: routeGroup?.availableLocales || item?.availableLocales || [sourceLocale],
    available_locales: routeGroup?.available_locales || item?.available_locales || [sourceLocale],
    localized: routeGroup?.localized || item?.localized || [],
    redirectFrom: routeGroup?.redirectFrom || item?.redirectFrom || item?.redirect_from || [],
    redirect_from: routeGroup?.redirect_from || item?.redirect_from || item?.redirectFrom || [],
    title: item.title,
    subtitle: item.subtitle || null,
    description,
    bodyParagraphs: fallbackParagraphs,
    image: resolveOfferMediaUrl(item, 'card'),
    heroImage: resolveOfferMediaUrl(item, 'hero'),
    cardImage: resolveOfferMediaUrl(item, 'card'),
    discount: itemPresentation.discountLabel || presentation.discount,
    tags: presentation.tags,
    validUntil: itemPresentation.validUntilLabel || item.validity || presentation.validUntil,
    color: itemPresentation.theme || presentation.color,
    ctaLabel,
    ctaUrl: detailPath,
    oldPrice: pricingSummary.oldPriceValue ? formatMoney(pricingSummary.oldPriceValue, pricingSummary.currency) : (itemPresentation.homeCard?.oldPrice ? formatMoney(itemPresentation.homeCard.oldPrice, itemPresentation.homeCard.currency) : presentation.oldPrice),
    newPrice: pricingSummary.newPriceValue ? formatMoney(pricingSummary.newPriceValue, pricingSummary.currency) : (itemPresentation.homeCard?.newPrice ? formatMoney(itemPresentation.homeCard.newPrice, itemPresentation.homeCard.currency) : presentation.newPrice),
    rating: itemPresentation.homeCard?.rating || presentation.rating,
    reviews: itemPresentation.homeCard?.reviewCount || presentation.reviews,
    relatedVehicle,
    bookingPrefill,
    bookingDestination,
    focusCards,
    detailSections,
    pricingTiers,
    canonical: localizedRouteEntry?.canonical || seo?.canonical || '',
    seo,
  }
}

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

  const offersPage = useResolvedPage('offers')
  const offerCards = computed(() => {
    return resolveOfferListEntities(locale.value).map((item) => normalizeOfferDetail(item, locale.value, offersPage.value))
  })
  const offersHero = computed(() => ({
    badge: offersPage.value?.subtitle,
    title: offersPage.value?.title,
    description: offersPage.value?.excerpt,
  }))
  const offersEmptyState = computed(() => ({
    title: offersPage.value?.structuredContent?.ui?.emptyTitle,
    description: offersPage.value?.structuredContent?.ui?.emptyDescription,
  }))
  const offersFooterCopy = computed(() => ({
    title: offersPage.value?.structuredContent?.ui?.footerTitle,
    description: offersPage.value?.structuredContent?.ui?.footerDescription,
    ctaLabel: offersPage.value?.structuredContent?.ui?.footerCtaLabel || offersPage.value?.cta?.label,
    ctaUrl: normalizePublicInternalPath(offersPage.value?.cta?.url, locale.value),
  }))

  function useResolvedOffer(identifierRef) {
    return computed(() => normalizeOfferDetail(
      resolveOfferDetailEntity(unref(identifierRef), locale.value),
      locale.value,
      offersPage.value,
    ))
  }

  return {
    offersPage,
    offerCards,
    offersHero,
    offersEmptyState,
    offersFooterCopy,
    useResolvedOffer,
  }
}
