<template>
  <div>
    <CatalogPage
      ref="catalogPageRef"
      :loading="isLoading"
      :use-server-clustering="useServerClustering"
      :use-typed-clusters="useServerClustering"
      :cluster-node-type="clusterNodeType"
      panel-width="w-[32rem]"
      map-id="unified-catalog-map"
      :point-color="mapPointColor"
      :items="mapItems"
      :hovered-id="hoveredItemId ?? undefined"
      :show-panel="showPanel && !kycSheetUuid"
      :filter-by-bounds="filterByBounds"
      :related-points="relatedPoints"
      :info-loading="mapInfoLoading"
      :force-info-mode="forceInfoMode"
      :hide-view-toggle="hideViewToggle"
      :show-offers-toggle="showOffersToggle"
      :show-hubs-toggle="showHubsToggle"
      :show-suppliers-toggle="showSuppliersToggle"
      :cluster-product-uuid="clusterProductUuid"
      :cluster-hub-uuid="clusterHubUuid"
      :cluster-supplier-uuid="clusterSupplierUuid"
      @select="onMapSelect"
      @bounds-change="onBoundsChange"
      @update:filter-by-bounds="onToggleBoundsFilter"
    >
      <!-- Panel slot - shows selection list OR info OR quote results -->
      <template #panel>
        <!-- Selection mode: show list for picking product/hub/supplier -->
        <SelectionPanel
          v-if="selectMode"
          :select-mode="selectMode"
          :products="filteredProducts"
          :hubs="filteredHubs"
          :suppliers="filteredSuppliers"
          :loading="selectionLoading"
          :loading-more="selectionLoadingMore"
          :has-more="selectionHasMore && !filterByBounds"
          @select="onSelectItem"
          @pin="onPinItem"
          @close="onClosePanel"
          @load-more="onLoadMore"
          @hover="onHoverItem"
        />

        <!-- Info mode: show detailed info about selected entity -->
        <InfoPanel
          v-else-if="infoId"
          :entity-type="infoId.type"
          :entity-id="infoId.uuid"
          :entity="entity"
          :related-products="relatedProducts"
          :related-hubs="relatedHubs"
          :related-suppliers="relatedSuppliers"
          :related-offers="relatedOffers"
          :selected-product="infoProduct ?? null"
          :loading="infoLoading"
          :loading-products="isLoadingProducts"
          :loading-hubs="isLoadingHubs"
          :loading-suppliers="isLoadingSuppliers"
          :loading-offers="isLoadingOffers"
          @close="onInfoClose"
          @open-info="onInfoOpenRelated"
          @select-product="onInfoSelectProduct"
          @select-offer="onSelectOffer"
          @open-kyc="onOpenKyc"
          @pin="onPinItem"
        />

        <!-- Quote results: show offers after search -->
        <QuotePanel
          v-else-if="showQuoteResults"
          :loading="offersLoading"
          :offers="offers"
          :calculations="quoteCalculations"
          @select-offer="onSelectOffer"
        />
      </template>
    </CatalogPage>

    <!-- KYC Bottom Sheet (overlays everything) -->
    <KycBottomSheet
      :is-open="!!kycSheetUuid"
      :uuid="kycSheetUuid"
      @close="onCloseKycSheet"
    />
  </div>
</template>

<script setup lang="ts">
import { GetOffersDocument, type GetOffersQueryVariables } from '~/composables/graphql/public/exchange-generated'
import { GetNodeDocument, NearestOffersDocument, QuoteCalculationsDocument, type QuoteCalculationsQueryResult } from '~/composables/graphql/public/geo-generated'
import type { MapBounds } from '~/components/catalog/CatalogMap.vue'

type QuoteCalculation = NonNullable<NonNullable<QuoteCalculationsQueryResult['quoteCalculations']>[number]>
type QuoteOffer = NonNullable<NonNullable<QuoteCalculation['offers']>[number]>

definePageMeta({
  layout: 'topnav'
})

const { t } = useI18n()
const { execute } = useGraphQL()
const router = useRouter()
const localePath = useLocalePath()

// Ref to CatalogPage for accessing bounds
const catalogPageRef = ref<{ currentBounds: Ref<MapBounds | null> } | null>(null)

// Current map bounds (local state, updated when map moves)
const currentMapBounds = ref<MapBounds | null>(null)
const selectionBoundsBackup = ref<{ hadBounds: boolean; bounds: { west: number; south: number; east: number; north: number } | null } | null>(null)

// Hovered item for map highlight
const hoveredItemId = ref<string | null>(null)
const onHoverItem = (uuid: string | null) => {
  hoveredItemId.value = uuid
}

// Type for map items - must have required string uuid and number coordinates
type MapItemWithCoords = { uuid: string; name: string; latitude: number; longitude: number; country?: string }

// Helper to convert items to map-compatible format (filter null values)
const toMapItems = <T extends { uuid?: string | null; name?: string | null; latitude?: number | null; longitude?: number | null }>(
  items: T[]
): MapItemWithCoords[] =>
  items.filter((item): item is T & { uuid: string; latitude: number; longitude: number } =>
    item.uuid != null && item.latitude != null && item.longitude != null
  ).map(item => ({
    uuid: item.uuid,
    name: item.name || '',
    latitude: item.latitude,
    longitude: item.longitude
  }))

// Current selection items for hover highlighting on map
const currentSelectionItems = computed((): MapItemWithCoords[] => {
  if (showQuoteResults.value) return []
  if (selectMode.value === 'product') return [] // Products don't have coordinates
  if (selectMode.value === 'hub') return toMapItems(filteredHubs.value)
  if (selectMode.value === 'supplier') return toMapItems(filteredSuppliers.value)
  return []
})

// Handle bounds change from map
const onBoundsChange = (bounds: MapBounds) => {
  currentMapBounds.value = bounds
  // If filter by bounds is enabled, write to URL
  if (filterByBounds.value) {
    setBoundsInUrl(bounds)
  }
}

const {
  catalogMode,
  selectMode,
  infoId,
  infoProduct,
  productId,
  supplierId,
  hubId,
  canSearch,
  mapViewMode,
  setMapViewMode,
  entityColors,
  selectItem,
  cancelSelect,
  openInfo,
  closeInfo,
  setInfoProduct,
  setLabel,
  urlBounds,
  filterByBounds,
  setBoundsInUrl,
  clearBoundsFromUrl,
  setBoundsFilterEnabled
} = useCatalogSearch()

// Info panel composable
const {
  entity,
  relatedProducts,
  relatedHubs,
  relatedSuppliers,
  relatedOffers,
  selectedProduct,
  isLoading: infoLoading,
  isLoadingProducts,
  isLoadingHubs,
  isLoadingSuppliers,
  isLoadingOffers,
  loadInfo,
  selectProduct: selectInfoProduct,
  clearInfo
} = useCatalogInfo()

// Composables for data (initialize immediately when selectMode changes)
const {
  items: products,
  isLoading: productsLoading,
  isLoadingMore: productsLoadingMore,
  canLoadMore: productsCanLoadMore,
  loadMore: loadMoreProducts,
  init: initProducts,
  setSupplierFilter,
  setHubFilter,
  clearFilters: clearProductFilters,
  setBoundsFilter: setProductBoundsFilter
} = useCatalogProducts()
const { items: hubs, isLoading: hubsLoading, isLoadingMore: hubsLoadingMore, canLoadMore: hubsCanLoadMore, loadMore: loadMoreHubs, init: initHubs, setProductFilter: setHubProductFilter, setBoundsFilter: setHubBoundsFilter } = useCatalogHubs()
const { items: suppliers, isLoading: suppliersLoading, isLoadingMore: suppliersLoadingMore, canLoadMore: suppliersCanLoadMore, loadMore: loadMoreSuppliers, init: initSuppliers, setProductFilter: setSupplierProductFilter, setBoundsFilter: setSupplierBoundsFilter } = useCatalogSuppliers()

// Items are now filtered on the backend via setBoundsFilter
// These are simple pass-throughs to maintain template compatibility
const filteredProducts = computed(() => products.value)
const filteredHubs = computed(() => hubs.value)
const filteredSuppliers = computed(() => suppliers.value)

// Selection loading state
const selectionLoading = computed(() => {
  if (selectMode.value === 'product') return productsLoading.value
  if (selectMode.value === 'hub') return hubsLoading.value
  if (selectMode.value === 'supplier') return suppliersLoading.value
  return false
})

// Selection loading more state
const selectionLoadingMore = computed(() => {
  if (selectMode.value === 'product') return productsLoadingMore.value
  if (selectMode.value === 'hub') return hubsLoadingMore.value
  if (selectMode.value === 'supplier') return suppliersLoadingMore.value
  return false
})

// Selection has more state
const selectionHasMore = computed(() => {
  if (selectMode.value === 'product') return productsCanLoadMore.value
  if (selectMode.value === 'hub') return hubsCanLoadMore.value
  if (selectMode.value === 'supplier') return suppliersCanLoadMore.value
  return false
})

// Load more handler
const onLoadMore = () => {
  if (selectMode.value === 'product') loadMoreProducts()
  if (selectMode.value === 'hub') loadMoreHubs()
  if (selectMode.value === 'supplier') loadMoreSuppliers()
}

const getSelectionBounds = () => {
  const bounds = currentMapBounds.value ?? catalogPageRef.value?.currentBounds?.value ?? null
  if (!bounds) return null
  return { west: bounds.west, south: bounds.south, east: bounds.east, north: bounds.north }
}

const onToggleBoundsFilter = (enabled: boolean) => {
  if (enabled) {
    setBoundsFilterEnabled(true)
    const bounds = getSelectionBounds()
    if (bounds) {
      setBoundsInUrl(bounds)
    }
  } else {
    clearBoundsFromUrl()
  }
}

const applySelectionBounds = () => {
  if (!filterByBounds.value) return
  if (!selectionBoundsBackup.value) {
    selectionBoundsBackup.value = {
      hadBounds: !!urlBounds.value,
      bounds: urlBounds.value
    }
  }
  const bounds = getSelectionBounds()
  if (bounds) {
    setBoundsInUrl(bounds)
  }
}

const restoreSelectionBounds = () => {
  const prev = selectionBoundsBackup.value
  if (!prev) return
  if (prev.hadBounds && prev.bounds) {
    setBoundsInUrl(prev.bounds)
  } else {
    clearBoundsFromUrl()
  }
  selectionBoundsBackup.value = null
}

// Initialize data and sync map view when selectMode changes
watch(selectMode, async (mode) => {
  if (mode) {
    applySelectionBounds()
  } else {
    restoreSelectionBounds()
  }
  if (mode === 'product') {
    await initProducts()
    setMapViewMode('offers')
  }
  if (mode === 'hub') {
    await initHubs()
    setMapViewMode('hubs')
  }
  if (mode === 'supplier') {
    await initSuppliers()
    setMapViewMode('suppliers')
  }
}, { immediate: true })

// Apply filters to products based on selected supplier/hub
watch([supplierId, hubId], ([newSupplierId, newHubId]) => {
  if (newSupplierId) {
    setSupplierFilter(newSupplierId)
  } else if (newHubId) {
    setHubFilter(newHubId)
  } else {
    clearProductFilters()
  }
}, { immediate: true })

// Apply product filter to hubs and suppliers (cascading filter)
watch(productId, (newProductId) => {
  setHubProductFilter(newProductId || null)
  setSupplierProductFilter(newProductId || null)
}, { immediate: true })

// If a filter locks a view type, switch away from that view
watch([hubId, supplierId], ([newHubId, newSupplierId]) => {
  if (newHubId && mapViewMode.value === 'hubs') {
    setMapViewMode('offers')
  }
  if (newSupplierId && mapViewMode.value === 'suppliers') {
    setMapViewMode('offers')
  }
}, { immediate: true })

// Apply bounds filter when "filter by map bounds" is enabled
// Only watch URL bounds - currentMapBounds changes too often (every map move)
watch([filterByBounds, urlBounds], ([enabled, urlB]) => {
  // Apply bounds filter only when checkbox is ON and bounds are in URL
  const boundsToApply = enabled && urlB ? urlB : null
  setHubBoundsFilter(boundsToApply)
  setSupplierBoundsFilter(boundsToApply)
  setProductBoundsFilter(boundsToApply)
}, { immediate: true })

// Watch infoId to load info data
watch(infoId, async (info) => {
  if (info) {
    await loadInfo(info.type, info.uuid)
    // If URL has infoProduct, load offers for it
    if (infoProduct.value) {
      await selectInfoProduct(infoProduct.value)
    }
  } else {
    clearInfo()
  }
}, { immediate: true })

// Watch infoProduct URL param to load offers when it changes
watch(infoProduct, async (productUuid) => {
  if (productUuid && infoId.value) {
    await selectInfoProduct(productUuid)
  }
})

// Related points for Info mode (shown on map) - show current entity + all related entities
const infoRelatedPoints = computed(() => {
  if (!infoId.value) return []

  const points: Array<{
    uuid: string
    name: string
    latitude: number
    longitude: number
    type: 'hub' | 'supplier' | 'offer'
  }> = []

  // Add current entity first (the one we're viewing in InfoPanel)
  // For offers, coordinates are in locationLatitude/locationLongitude
  const lat = entity.value?.latitude ?? entity.value?.locationLatitude
  const lon = entity.value?.longitude ?? entity.value?.locationLongitude
  if (lat && lon) {
    points.push({
      uuid: infoId.value.uuid,
      name: entity.value.name || entity.value.productName || '',
      latitude: Number(lat),
      longitude: Number(lon),
      type: infoId.value.type
    })
  }

  // Add all related hubs
  relatedHubs.value.forEach(hub => {
    if (hub.uuid && hub.latitude && hub.longitude) {
      points.push({
        uuid: hub.uuid,
        name: hub.name || '',
        latitude: hub.latitude,
        longitude: hub.longitude,
        type: 'hub'
      })
    }
  })

  // Add all related suppliers
  relatedSuppliers.value.forEach(supplier => {
    if (supplier.uuid && supplier.latitude && supplier.longitude) {
      points.push({
        uuid: supplier.uuid,
        name: supplier.name || '',
        latitude: supplier.latitude,
        longitude: supplier.longitude,
        type: 'supplier'
      })
    }
  })

  return points
})

// Related points for Quote mode (shown on map)
const searchHubPoint = ref<MapItemWithCoords | null>(null)

const searchOfferPoints = computed(() =>
  offers.value
    .filter((offer) => offer.latitude != null && offer.longitude != null)
    .map((offer) => ({
      uuid: offer.uuid,
      name: offer.productName || '',
      latitude: Number(offer.latitude),
      longitude: Number(offer.longitude),
      type: 'offer' as const
    }))
)

const searchRelatedPoints = computed(() => {
  const points: Array<{
    uuid: string
    name: string
    latitude: number
    longitude: number
    type: 'hub' | 'supplier' | 'offer'
  }> = []

  if (searchHubPoint.value) {
    points.push({
      uuid: searchHubPoint.value.uuid,
      name: searchHubPoint.value.name,
      latitude: searchHubPoint.value.latitude,
      longitude: searchHubPoint.value.longitude,
      type: 'hub'
    })
  }

  searchOfferPoints.value.forEach((point) => points.push(point))
  return points
})

const relatedPoints = computed(() => {
  if (infoId.value) return infoRelatedPoints.value
  if (showQuoteResults.value) return searchRelatedPoints.value
  return []
})

// Offers data for quote results
const offers = ref<QuoteOffer[]>([])
const quoteCalculations = ref<QuoteCalculation[]>([])

const buildCalculationsFromOffers = (list: QuoteOffer[]) =>
  list.map((offer) => ({ offers: [offer] })) as QuoteCalculation[]
const offersLoading = ref(false)
const showQuoteResults = ref(false)


// Watch for search trigger from topnav
const searchTrigger = useState<number>('catalog-search-trigger', () => 0)
watch(searchTrigger, () => {
  if (canSearch.value) {
    onSearch()
  }
})

// Loading state
const isLoading = computed(() => offersLoading.value || selectionLoading.value || exploreOffersLoading.value)

// Info loading state for map fitBounds (true while any info data is still loading)
const isInfoLoading = computed(() =>
  infoLoading.value || isLoadingProducts.value || isLoadingHubs.value || isLoadingSuppliers.value || isLoadingOffers.value
)

const mapInfoLoading = computed(() =>
  isInfoLoading.value || (showQuoteResults.value && offersLoading.value)
)

const forceInfoMode = computed(() => showQuoteResults.value)
const hideViewToggle = computed(() => showQuoteResults.value)

const showOffersToggle = computed(() => true)
const showHubsToggle = computed(() => !hubId.value)
const showSuppliersToggle = computed(() => !supplierId.value)

const clusterProductUuid = computed(() => productId.value || undefined)
const clusterHubUuid = computed(() => hubId.value || undefined)
const clusterSupplierUuid = computed(() => supplierId.value || undefined)

// When a product filter is active and we're viewing hubs, use the same list data on the map
// to avoid mismatch between graph-filtered list and clustered map results.
const useServerClustering = computed(() => {
  if (productId.value && (mapViewMode.value === 'hubs' || mapViewMode.value === 'suppliers')) return false
  if (hubId.value && mapViewMode.value === 'offers') return false
  return true
})

// Offers for Explore map when hub filter is active (graph-based)
const exploreOffers = ref<QuoteOffer[]>([])
const exploreOffersLoading = ref(false)

const shouldLoadExploreOffers = computed(() =>
  catalogMode.value === 'explore' && mapViewMode.value === 'offers' && !!hubId.value
)

const loadExploreOffers = async () => {
  if (!hubId.value) return
  exploreOffersLoading.value = true
  try {
    const hubData = await execute(GetNodeDocument, { uuid: hubId.value }, 'public', 'geo')
    const hub = hubData?.node
    if (!hub?.latitude || !hub?.longitude) {
      exploreOffers.value = []
      return
    }
    const geoData = await execute(
      NearestOffersDocument,
      {
        lat: hub.latitude,
        lon: hub.longitude,
        hubUuid: hubId.value,
        productUuid: productId.value || null,
        limit: 500
      },
      'public',
      'geo'
    )
    exploreOffers.value = (geoData?.nearestOffers || []).filter((o): o is QuoteOffer => o !== null)
  } finally {
    exploreOffersLoading.value = false
  }
}

watch([shouldLoadExploreOffers, hubId, productId], ([enabled]) => {
  if (!enabled) {
    exploreOffers.value = []
    exploreOffersLoading.value = false
    return
  }
  loadExploreOffers()
}, { immediate: true })

const mapItems = computed((): MapItemWithCoords[] => {
  if (!useServerClustering.value) {
    if (mapViewMode.value === 'offers') {
      return exploreOffers.value
        .filter((offer) => offer.uuid && offer.latitude != null && offer.longitude != null)
        .map((offer) => ({
          uuid: offer.uuid,
          name: offer.productName || '',
          latitude: Number(offer.latitude),
          longitude: Number(offer.longitude)
        }))
    }
    if (mapViewMode.value === 'hubs') return toMapItems(filteredHubs.value)
    if (mapViewMode.value === 'suppliers') return toMapItems(filteredSuppliers.value)
  }
  return currentSelectionItems.value
})

// Show panel when selecting OR when showing info OR when showing quote results
const showPanel = computed(() => {
  return selectMode.value !== null || infoId.value !== null || showQuoteResults.value
})

// Cluster node type based on map view mode
const clusterNodeType = computed(() => {
  if (mapViewMode.value === 'offers') return 'offer'
  if (mapViewMode.value === 'hubs') return 'logistics'
  if (mapViewMode.value === 'suppliers') return 'supplier'
  return 'offer'
})

// Map point color based on map view mode
const mapPointColor = computed(() => {
  if (mapViewMode.value === 'offers') return entityColors.offer
  if (mapViewMode.value === 'hubs') return entityColors.hub
  if (mapViewMode.value === 'suppliers') return entityColors.supplier
  return entityColors.offer
})

// Map item type from CatalogMap
interface MapSelectItem {
  uuid?: string | null
  id?: string
  name?: string | null
}

// Handle map item selection
const onMapSelect = (item: MapSelectItem) => {
  // Get uuid from item - clusters use 'id', regular items use 'uuid'
  const itemId = item.uuid || item.id
  if (!itemId || itemId.startsWith('cluster-')) return

  const itemName = item.name || itemId.slice(0, 8) + '...'

  const itemType = (item as MapSelectItem & { type?: 'hub' | 'supplier' | 'offer' }).type

  // Default behavior - open Info directly
  let infoType: 'hub' | 'supplier' | 'offer'
  if (itemType === 'hub' || mapViewMode.value === 'hubs') infoType = 'hub'
  else if (itemType === 'supplier' || mapViewMode.value === 'suppliers') infoType = 'supplier'
  else infoType = 'offer'

  openInfo(infoType, itemId)
  setLabel(infoType, itemId, itemName)
}

// Handle selection from SelectionPanel - open info card (pin only via pin button)
const onSelectItem = (type: string, item: { uuid?: string | null; name?: string | null }) => {
  if (!item.uuid) return
  if (type === 'hub' || type === 'supplier') {
    if (item.name) {
      setLabel(type, item.uuid, item.name)
    }
    openInfo(type, item.uuid)
    return
  }
  if (type === 'product') {
    router.push(localePath(`/catalog/products/${item.uuid}`))
  }
}

const onPinItem = (type: 'product' | 'hub' | 'supplier', item: { uuid?: string | null; name?: string | null }) => {
  if (!item.uuid) return
  const label = item.name || item.uuid.slice(0, 8) + '...'
  selectItem(type, item.uuid, label)
}

// Close panel (cancel select mode)
const onClosePanel = () => {
  cancelSelect()
}

// Handle Info panel events
const onInfoClose = () => {
  closeInfo()
  clearInfo()
}


const onInfoOpenRelated = (type: 'hub' | 'supplier' | 'offer', uuid: string) => {
  openInfo(type, uuid)
}

// Handle product selection in InfoPanel - update URL which triggers loading
const onInfoSelectProduct = (uuid: string | null) => {
  setInfoProduct(uuid)
}

// KYC Bottom Sheet state
const kycSheetUuid = ref<string | null>(null)

// Handle KYC profile open - show bottom sheet instead of navigating
const onOpenKyc = (uuid: string | undefined) => {
  if (!uuid) return
  kycSheetUuid.value = uuid
}

// Close KYC bottom sheet
const onCloseKycSheet = () => {
  kycSheetUuid.value = null
}

// Search for offers
const onSearch = async () => {
  if (!canSearch.value) return

  offersLoading.value = true
  showQuoteResults.value = true
  searchHubPoint.value = null

  try {
    // Prefer geo-based offers with routes when hub + product are selected
    if (hubId.value && productId.value) {
      const hubData = await execute(GetNodeDocument, { uuid: hubId.value }, 'public', 'geo')
      const hub = hubData?.node
      if (hub?.latitude != null && hub?.longitude != null) {
        searchHubPoint.value = {
          uuid: hub.uuid,
          name: hub.name || hub.uuid,
          latitude: Number(hub.latitude),
          longitude: Number(hub.longitude)
        }
        try {
          const calcData = await execute(
            QuoteCalculationsDocument,
            {
              lat: hub.latitude,
              lon: hub.longitude,
              productUuid: productId.value,
              hubUuid: hubId.value,
              quantity: quantity.value ? Number(quantity.value) : null,
              limit: 10
            },
            'public',
            'geo'
          )

          let calculations = (calcData?.quoteCalculations || []).filter((c): c is QuoteCalculation => c !== null)
          if (supplierId.value) {
            calculations = calculations.map((calc) => ({
              ...calc,
              offers: (calc.offers || []).filter((offer): offer is QuoteOffer => offer !== null).filter(offer => offer.supplierUuid === supplierId.value)
            })).filter(calc => calc.offers.length > 0)
          }

          quoteCalculations.value = calculations
          offers.value = calculations.flatMap(calc => (calc.offers || []).filter((offer): offer is QuoteOffer => offer !== null))
        } catch (error) {
          const geoData = await execute(
            NearestOffersDocument,
            {
              lat: hub.latitude,
              lon: hub.longitude,
              productUuid: productId.value,
              hubUuid: hubId.value,
              limit: 12
            },
            'public',
            'geo'
          )

          let nearest = (geoData?.nearestOffers || []).filter((o): o is QuoteOffer => o !== null)
          if (supplierId.value) {
            nearest = nearest.filter(o => o?.supplierUuid === supplierId.value)
          }

          offers.value = nearest
          quoteCalculations.value = buildCalculationsFromOffers(nearest)
        }

        const first = offers.value[0]
        if (first?.productName) {
          setLabel('product', productId.value, first.productName)
        }
      } else {
        offers.value = []
        quoteCalculations.value = []
      }
    } else {
      searchHubPoint.value = null
      const vars: GetOffersQueryVariables = {}
      if (productId.value) vars.productUuid = productId.value
      if (supplierId.value) vars.teamUuid = supplierId.value
      if (hubId.value) vars.locationUuid = hubId.value

      const data = await execute(GetOffersDocument, vars, 'public', 'exchange')
      const exchangeOffers = (data?.getOffers || []).filter((o): o is NonNullable<typeof o> => o !== null)
      offers.value = exchangeOffers.map((offer) => ({
        uuid: offer.uuid,
        productUuid: offer.productUuid,
        productName: offer.productName,
        teamUuid: offer.teamUuid,
        quantity: offer.quantity,
        unit: offer.unit,
        pricePerUnit: offer.pricePerUnit,
        currency: offer.currency,
        locationName: offer.locationName,
        locationCountry: offer.locationCountry
      }))
      quoteCalculations.value = buildCalculationsFromOffers(offers.value)

      // Update labels from response
      const first = offers.value[0]
      if (first) {
        if (productId.value && first.productName) {
          setLabel('product', productId.value, first.productName)
        }
        if (hubId.value && first.locationName) {
          setLabel('hub', hubId.value, first.locationName)
        }
      }
    }
  } finally {
    offersLoading.value = false
  }
}

// Select offer - navigate to detail page
const onSelectOffer = (offer: { uuid: string; productUuid?: string | null }) => {
  if (offer.uuid && offer.productUuid) {
    router.push(localePath(`/catalog/offers/${offer.productUuid}?offer=${offer.uuid}`))
  }
}

// SEO
useHead(() => ({
  title: t('catalog.hero.title')
}))
</script>
