<template>
  <CatalogPage
    ref="catalogPageRef"
    :loading="isLoading"
    :use-server-clustering="true"
    :cluster-node-type="clusterNodeType"
    map-id="unified-catalog-map"
    :point-color="mapPointColor"
    :items="currentSelectionItems"
    :hovered-id="hoveredItemId ?? undefined"
    :show-panel="showPanel"
    :filter-by-bounds="filterByBounds"
    :related-points="relatedPoints"
    @select="onMapSelect"
    @bounds-change="onBoundsChange"
    @update:filter-by-bounds="filterByBounds = $event"
  >
    <!-- 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"
        @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"
        :current-tab="infoTab"
        :loading="infoLoading"
        :loading-products="isLoadingProducts"
        :loading-hubs="isLoadingHubs"
        :loading-suppliers="isLoadingSuppliers"
        :loading-offers="isLoadingOffers"
        @close="onInfoClose"
        @add-to-filter="onInfoAddToFilter"
        @open-info="onInfoOpenRelated"
        @select-product="onInfoSelectProduct"
        @update:current-tab="setInfoTab"
      />

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

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

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)

// Filter by map bounds state
const filterByBounds = ref(false)
const currentMapBounds = ref<MapBounds | null>(null)

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

// Current selection items for hover highlighting on map
const currentSelectionItems = computed(() => {
  if (selectMode.value === 'product') return filteredProducts.value
  if (selectMode.value === 'hub') return filteredHubs.value
  if (selectMode.value === 'supplier') return filteredSuppliers.value
  return []
})

// Handle bounds change from map
const onBoundsChange = (bounds: MapBounds) => {
  currentMapBounds.value = bounds
}

const {
  catalogMode,
  selectMode,
  infoId,
  infoTab,
  infoProduct,
  productId,
  supplierId,
  hubId,
  canSearch,
  mapViewMode,
  setMapViewMode,
  entityColors,
  selectItem,
  cancelSelect,
  openInfo,
  closeInfo,
  setInfoTab,
  setInfoProduct,
  setLabel
} = 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()
}

// Initialize data and sync map view when selectMode changes
watch(selectMode, async (mode) => {
  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 })

// Apply bounds filter when "filter by map bounds" is enabled
watch([filterByBounds, currentMapBounds], ([enabled, bounds]) => {
  const boundsToApply = enabled && bounds ? bounds : null
  setHubBoundsFilter(boundsToApply)
  setSupplierBoundsFilter(boundsToApply)
  setProductBoundsFilter(boundsToApply)
})

// 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) - filtered by active tab
const relatedPoints = computed(() => {
  if (!infoId.value) return []

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

  const currentTab = infoTab.value

  // Show content based on active tab
  // Hub entity: offers tab → offers, suppliers tab → suppliers
  // Supplier entity: offers tab → offers, hubs tab → hubs
  // Offer entity: hubs tab → hubs, suppliers tab → suppliers

  // Add hubs (for supplier's hubs tab or offer's hubs tab)
  if (currentTab === 'hubs') {
    relatedHubs.value.forEach(hub => {
      if (hub.latitude && hub.longitude) {
        points.push({
          uuid: hub.uuid,
          name: hub.name,
          latitude: hub.latitude,
          longitude: hub.longitude,
          type: 'hub'
        })
      }
    })
  }

  // Add suppliers (for hub's suppliers tab or offer's suppliers tab)
  if (currentTab === 'suppliers') {
    relatedSuppliers.value.forEach(supplier => {
      if (supplier.latitude && supplier.longitude) {
        points.push({
          uuid: supplier.uuid,
          name: supplier.name,
          latitude: supplier.latitude,
          longitude: supplier.longitude,
          type: 'supplier'
        })
      }
    })
  }

  // Add offers (for hub's/supplier's offers tab when product is selected)
  if (currentTab === 'offers' && infoProduct.value) {
    relatedOffers.value.forEach(offer => {
      if (offer.latitude && offer.longitude) {
        points.push({
          uuid: offer.uuid,
          name: offer.productName || offer.name,
          latitude: offer.latitude,
          longitude: offer.longitude,
          type: 'offer'
        })
      }
    })
  }

  return points
})

// Offers data for quote results
const offers = ref<any[]>([])
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)

// 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
})

// Handle map item selection
const onMapSelect = async (item: any) => {
  // 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) + '...'

  // If in selection mode, use map click to fill the selector
  if (selectMode.value) {
    // For hubs selection - click on hub fills hub selector
    if (selectMode.value === 'hub' && mapViewMode.value === 'hubs') {
      selectItem('hub', itemId, itemName)
      showQuoteResults.value = false
      offers.value = []
      return
    }

    // For supplier selection - click on supplier fills supplier selector
    if (selectMode.value === 'supplier' && mapViewMode.value === 'suppliers') {
      selectItem('supplier', itemId, itemName)
      showQuoteResults.value = false
      offers.value = []
      return
    }

    // For product selection viewing offers - fetch offer to get productUuid
    if (selectMode.value === 'product' && mapViewMode.value === 'offers') {
      // Fetch offer details to get productUuid (not available in cluster data)
      const data = await execute(GetOfferDocument, { uuid: itemId }, 'public', 'exchange')
      const offer = data?.getOffer
      if (offer?.productUuid) {
        selectItem('product', offer.productUuid, offer.productName || itemName)
        showQuoteResults.value = false
        offers.value = []
      }
      return
    }
  }

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

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

// Handle selection from SelectionPanel - add to filter (show badge in search)
const onSelectItem = (type: string, item: any) => {
  if (item.uuid && item.name) {
    selectItem(type, item.uuid, item.name)
  }
}

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

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

const onInfoAddToFilter = () => {
  if (!infoId.value || !entity.value) return
  const { type, uuid } = infoId.value

  // For offers, add the product to filter (not the offer itself)
  if (type === 'offer' && entity.value.productUuid) {
    const productName = entity.value.productName || entity.value.name || uuid.slice(0, 8) + '...'
    selectItem('product', entity.value.productUuid, productName)
  } else {
    // For hubs and suppliers, add directly
    const name = entity.value.name || uuid.slice(0, 8) + '...'
    selectItem(type, uuid, name)
  }

  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)
}

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

  offersLoading.value = true
  showQuoteResults.value = true

  try {
    const vars: any = {}
    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')
    offers.value = data?.getOffers || []

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

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

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