import { format, setHours, setMinutes, startOfDay } from 'date-fns'
import { buildSearchScarcity, formatSearchType, resolveSearchDeliveryBadgeLabel, resolveSearchMarketingBadgeLabel } from '~/constants/search-ui'
import { resolvePublicAssetUrl } from '~/content/utils'
import { usePublicLocale } from '~/composables/usePublicLocale'
import { resolvePublicUiValue } from '~/i18n/public-ui'

function parseDateTime(value, fallback) {
  if (!value) {
    return fallback
  }

  const parsed = new Date(String(value))

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

  return parsed
}

function buildDateTime(date, time = '12:00') {
  const nextDate = new Date(date)
  const [hours, minutes] = String(time).split(':').map((value) => Number(value))
  return setMinutes(setHours(nextDate, hours || 0), minutes || 0)
}

function extractTimeLabel(date, fallback) {
  if (!date || Number.isNaN(date.getTime())) {
    return fallback
  }

  return format(date, 'HH:mm')
}

function dedupe(values) {
  return [...new Set(values.filter(Boolean))]
}

function roundComparePrice(price) {
  if (!price) {
    return null
  }

  return Math.ceil(price / 10) * 10
}

function normalizeRating(value) {
  return value && value > 0 ? Number(value) : null
}

function buildSearchCatalogLabels(locale) {
  return {
    featuredLabel: resolvePublicUiValue(locale, 'search.featuredLabel'),
    luxuryBadgeLabel: resolvePublicUiValue(locale, 'search.luxuryBadgeLabel'),
    newArrivalBadgeLabel: resolvePublicUiValue(locale, 'search.newArrivalBadgeLabel'),
    hotDealBadgeLabel: resolvePublicUiValue(locale, 'search.hotDealBadgeLabel'),
    bestValueLabel: resolvePublicUiValue(locale, 'search.bestValueLabel'),
    ratingNewLabel: resolvePublicUiValue(locale, 'search.ratingNewLabel'),
    soldOutSelectedDatesLabel: resolvePublicUiValue(locale, 'search.soldOutSelectedDatesLabel'),
    onlyOneLeftTemplate: resolvePublicUiValue(locale, 'search.onlyOneLeftTemplate'),
    onlyFewLeftTemplate: resolvePublicUiValue(locale, 'search.onlyFewLeftTemplate'),
    transferServiceLabel: resolvePublicUiValue(locale, 'search.transferServiceLabel'),
    oneWayAvailableLabel: resolvePublicUiValue(locale, 'search.oneWayAvailableLabel'),
    typeVehicleLabel: resolvePublicUiValue(locale, 'search.typeVehicleLabel'),
    typeEconomyLabel: resolvePublicUiValue(locale, 'search.typeEconomyLabel'),
    typeStandardLabel: resolvePublicUiValue(locale, 'search.typeStandardLabel'),
    typeSedanLabel: resolvePublicUiValue(locale, 'search.typeSedanLabel'),
    typeSuvLabel: resolvePublicUiValue(locale, 'search.typeSuvLabel'),
    typeVansLabel: resolvePublicUiValue(locale, 'search.typeVansLabel'),
    typeLuxuryLabel: resolvePublicUiValue(locale, 'search.typeLuxuryLabel'),
  }
}

function localizeSalesTag(tag, labels) {
  const normalized = String(tag || '').trim().toLowerCase()

  if (normalized === 'featured') {
    return labels.featuredLabel || tag
  }

  if (normalized === 'luxury' || normalized === 'premium') {
    return labels.luxuryBadgeLabel || tag
  }

  if (normalized === 'new' || normalized === 'new arrival') {
    return labels.newArrivalBadgeLabel || tag
  }

  if (normalized === 'hot deal') {
    return labels.hotDealBadgeLabel || tag
  }

  if (normalized === 'best value') {
    return labels.bestValueLabel || tag
  }

  return tag
}

function normalizeConditions(item, labels) {
  return dedupe([
    resolveSearchDeliveryBadgeLabel(item, labels),
    ...(item.salesTags || []).map((tag) => localizeSalesTag(tag, labels)),
  ])
}

function normalizeOptions(item) {
  return dedupe([
    ...(item.features || []),
    ...(item.featureBullets || []),
  ])
}

function normalizeImages(item, apiBaseUrl) {
  return dedupe([
    resolvePublicAssetUrl(item.imageUrl, apiBaseUrl),
    ...(item.availableVehicles || []).map((vehicle) => resolvePublicAssetUrl(vehicle.imageUrl, apiBaseUrl)),
  ])
}

function normalizeBrand(item) {
  return item.model?.make || item.vehicle?.make || item.name || 'Bent'
}

function normalizeModel(item) {
  return item.model?.name || item.vehicle?.model || item.name || 'Vehicle'
}

function normalizeYear(item) {
  return item.model?.year || item.vehicle?.year || null
}

function normalizeType(item, labels) {
  if (item.isPremium) {
    return labels.typeLuxuryLabel || 'Luxury'
  }

  return formatSearchType(item.category, labels)
}

function normalizeSearchItem(item, labels, apiBaseUrl) {
  const images = normalizeImages(item, apiBaseUrl)
  const price = Number(item.pricePerDay || item.pricing?.dailyRate || 0)
  const compareAtPrice = Number(item.compareAtPrice || 0) || roundComparePrice(price * 1.2)
  const rating = normalizeRating(item.reviewAggregate?.rating)
  const features = (item.featureBullets || item.features || []).slice(0, 3)
  const options = normalizeOptions(item)
  const salesTags = (item.salesTags || []).map((tag) => localizeSalesTag(tag, labels))
  const conditions = normalizeConditions({
    ...item,
    salesTags,
  }, labels)
  const demandSignals = item.demandSignals || {}
  const availabilityStatus = String(item.availabilityStatus || item.availability_status || '').trim().toLowerCase()
  const availableCount = Number(item.availableCount || item.available_count || 0)
  const isExplicitlyUnavailable = availabilityStatus === 'sold_out' || availabilityStatus === 'unavailable'
  const isAvailableFlag = item.available === true || item.available === 1 || item.available === '1'
  const isPromoInvalid = String(item.reason || '').trim().toLowerCase().includes('promo code is not valid')
  const hasInventory = availableCount > 0
  const resolvedAvailable = !isExplicitlyUnavailable && (isAvailableFlag || hasInventory || isPromoInvalid)

  return {
    id: item.id,
    slug: item.slug,
    brand: normalizeBrand(item),
    model: normalizeModel(item),
    year: normalizeYear(item),
    type: normalizeType(item, labels),
    price,
    oldPrice: compareAtPrice,
    rating,
    reviews: Number(item.reviewAggregate?.count || 0),
    images,
    features,
    featureKeys: Array.isArray(item.featureKeys)
      ? item.featureKeys
      : Array.isArray(item.filterMeta?.featureKeys)
        ? item.filterMeta.featureKeys
        : [],
    paymentMethods: Array.isArray(item.paymentMethods)
      ? item.paymentMethods
      : Array.isArray(item.filterMeta?.paymentMethods)
        ? item.filterMeta.paymentMethods
        : [],
    filterMeta: item.filterMeta || null,
    filterFlags: item.filterFlags || null,
    prices: item.prices || item.filterMeta?.prices || item.pricing?.prices || null,
    seats: Number(item.seats || item.vehicle?.seats || item.model?.seats || 0),
    transmission: item.transmission || item.vehicle?.transmission || item.model?.transmission || 'Auto',
    engine: item.fuelType || item.vehicle?.fuelType || item.model?.powertrain || 'Petrol',
    fuelConsumptionPer100Km: item.fuelConsumptionPer100Km ?? item.vehicle?.fuelConsumptionPer100Km ?? null,
    options,
    conditions,
    available: resolvedAvailable,
    availability: item.availability || null,
    tags: salesTags,
    hotDeal: !!item.compareAtPrice && item.compareAtPrice > price,
    viewers: Number(demandSignals.viewers || 0),
    bookedToday: Number(demandSignals.bookedToday || 0),
    scarcity: buildSearchScarcity(item, labels),
    marketingBadge: resolveSearchMarketingBadgeLabel(item, labels),
    isNewArrival: typeof item.isNewArrival === 'boolean'
      ? item.isNewArrival
      : (item.salesTagKeys || []).includes('new_arrival'),
    deliveryTag: resolveSearchDeliveryBadgeLabel(item, labels),
    ratingFallbackLabel: labels.ratingNewLabel || 'New',
    acceleration: null,
    topSpeed: null,
    currency: item.currency || item.pricing?.currency || 'USD',
    totalPrice: Number(item.totalPrice || item.pricing?.finalTotal || 0),
    availableCount,
    vehicleGroupId: item.id,
    vehicle: item.vehicle || null,
    raw: item,
  }
}

function isPromoInvalidCatalog(items = []) {
  if (!Array.isArray(items) || !items.length) {
    return false
  }

  return items.every((item) => {
    const reason = String(item?.reason || '').trim().toLowerCase()
    return reason.includes('promo') && reason.includes('not valid')
  })
}

export function useSearchCatalog() {
  const config = useRuntimeConfig()
  const { locale } = usePublicLocale()
  const { buildDateTime: buildStableDateTime } = usePublicDateDefaults()

  async function requestCatalog(payload) {
    const response = await $fetch(`${config.public.apiBaseUrl}/public-catalog`, {
      method: 'POST',
      body: payload,
    })

    return response?.data || {}
  }

  async function fetchCatalog(payload) {
    const labels = buildSearchCatalogLabels(locale.value)
    const initialCatalog = await requestCatalog(payload)
    const promoCode = String(payload?.promo_code || '').trim()
    const shouldRetryWithoutPromo = promoCode && isPromoInvalidCatalog(initialCatalog.items)
    const catalog = shouldRetryWithoutPromo
      ? await requestCatalog({
        ...payload,
        promo_code: undefined,
      })
      : initialCatalog

    return {
      trip: catalog.trip || null,
      extras: Array.isArray(catalog.extras) ? catalog.extras : [],
      items: Array.isArray(catalog.items)
        ? catalog.items.map((item) => normalizeSearchItem(item, labels, config.public.apiBaseUrl))
        : [],
      promoInvalid: Boolean(shouldRetryWithoutPromo),
      promoInvalidMessage: shouldRetryWithoutPromo
        ? resolvePublicUiValue(locale.value, 'offers.promoInvalid', 'Promo code is not valid.')
        : '',
    }
  }

  function buildCatalogPayload({
    pickupLocationId,
    dropoffLocationId,
    pickupDate,
    dropoffDate,
    pickupTime,
    dropoffTime,
    currency,
    promoCode,
    offerSlug,
  }) {
    return {
      service_type: 'rental',
      pickup_location_id: Number(pickupLocationId),
      dropoff_location_id: Number(dropoffLocationId),
      pickup_at: buildDateTime(pickupDate, pickupTime).toISOString(),
      dropoff_at: buildDateTime(dropoffDate, dropoffTime).toISOString(),
      currency,
      promo_code: promoCode || undefined,
      offer_slug: offerSlug || undefined,
    }
  }

  function parseSearchQuery(query) {
    const fallbackPickup = buildStableDateTime(0, '12:30')
    const fallbackDropoff = buildStableDateTime(2, '08:30')
    const pickupDateTime = parseDateTime(query.pickupAt, fallbackPickup)
    const dropoffDateTime = parseDateTime(query.dropoffAt, fallbackDropoff)

    return {
      pickupLocationId: Number(query.pickupLocationId || 0) || null,
      dropoffLocationId: Number(query.dropoffLocationId || query.pickupLocationId || 0) || null,
      pickupDateTime,
      dropoffDateTime,
      pickupDate: startOfDay(pickupDateTime),
      dropoffDate: startOfDay(dropoffDateTime),
      pickupTime: extractTimeLabel(pickupDateTime, '12:30'),
      dropoffTime: extractTimeLabel(dropoffDateTime, '08:30'),
      promoCode: String(query.promoCode || ''),
    }
  }

  return {
    buildCatalogPayload,
    fetchCatalog,
    parseSearchQuery,
  }
}
