<template>
  <Stack gap="8">
    <!-- Loading state -->
    <Section v-if="isLoading" variant="plain" paddingY="md">
      <Card>
        <Stack align="center" justify="center" gap="3">
          <Spinner />
          <Text tone="muted">{{ t('catalogLanding.states.loading') }}</Text>
        </Stack>
      </Card>
    </Section>

    <template v-else>
      <!-- Map preview - clickable, links to /catalog/map -->
      <Section variant="plain" paddingY="md">
        <NuxtLink
          :to="localePath('/catalog/map')"
          class="relative block h-48 rounded-lg overflow-hidden cursor-pointer group"
        >
          <ClientOnly>
            <MapboxGlobe
              map-id="catalog-preview-map"
              :locations="mapLocations"
              :height="192"
            />
          </ClientOnly>
          <div class="absolute inset-0 flex items-center justify-center bg-black/30 group-hover:bg-black/40 transition-colors rounded-lg">
            <div class="flex items-center gap-2 px-4 py-2 bg-base-100 border border-base-300 rounded-lg shadow-lg text-base-content">
              <Icon name="lucide:maximize-2" size="20" />
              <span class="font-medium">{{ t('catalogLanding.actions.open_map') }}</span>
            </div>
          </div>
        </NuxtLink>
      </Section>

      <!-- Sections -->
      <CatalogHubsSection
        :hubs="locations"
        :total="totalHubs"
        :can-load-more="canLoadMoreHubs"
        :on-load-more="loadMoreHubs"
      />
      <CatalogOffersSection
        :offers="offers"
        :total="totalOffers"
        :can-load-more="canLoadMoreOffers"
        :on-load-more="loadMoreOffers"
      />
      <CatalogSuppliersSection
        :suppliers="suppliers"
        :total="totalSuppliers"
        :can-load-more="canLoadMoreSuppliers"
        :on-load-more="loadMoreSuppliers"
      />
    </template>
  </Stack>
</template>

<script setup lang="ts">
import { GetSuppliersDocument, GetOffersDocument } from '~/composables/graphql/public/exchange-generated'
import { GetNodesDocument } from '~/composables/graphql/public/geo-generated'

const localePath = useLocalePath()
const { t } = useI18n()

const { execute } = useGraphQL()
const PAGE_SIZE = 24

const suppliers = ref<any[]>([])
const offers = ref<any[]>([])
const locations = ref<any[]>([])
const totalSuppliers = ref(0)
const totalOffers = ref(0)
const totalHubs = ref(0)
const isLoadingMore = ref({
  suppliers: false,
  offers: false,
  hubs: false
})

function calculateDistance(lat: number, lng: number) {
  const moscowLat = 55.76
  const moscowLng = 37.64
  const distance = Math.sqrt(Math.pow(lat - moscowLat, 2) + Math.pow(lng - moscowLng, 2)) * 111
  return t('catalogLanding.labels.distance_km', { km: Math.round(distance) })
}

const {
  data: suppliersData,
  pending: suppliersPending
} = await useServerQuery(
  'catalog-suppliers',
  GetSuppliersDocument,
  { limit: PAGE_SIZE, offset: 0 },
  'public',
  'exchange'
)

const {
  data: offersData,
  pending: offersPending
} = await useServerQuery(
  'catalog-offers',
  GetOffersDocument,
  { limit: PAGE_SIZE, offset: 0 },
  'public',
  'exchange'
)

const {
  data: locationsData,
  pending: locationsPending
} = await useServerQuery(
  'catalog-locations',
  GetNodesDocument,
  { limit: PAGE_SIZE, offset: 0, transportType: null },
  'public',
  'geo'
)

watchEffect(() => {
  if (suppliersData.value?.getSuppliers) {
    suppliers.value = suppliersData.value.getSuppliers
    totalSuppliers.value = suppliersData.value.getSuppliersCount ?? suppliersData.value.getSuppliers.length
  }
})

watchEffect(() => {
  if (offersData.value?.getOffers) {
    offers.value = offersData.value.getOffers.map((offer: any) => ({
      ...offer,
      latitude: offer.locationLatitude,
      longitude: offer.locationLongitude
    }))
    totalOffers.value = offersData.value.getOffersCount ?? offersData.value.getOffers.length
  }
})

watchEffect(() => {
  if (locationsData.value?.nodes) {
    locations.value = locationsData.value.nodes.map((location: any) => ({
      ...location,
      distance:
        location?.latitude && location?.longitude
          ? calculateDistance(location.latitude, location.longitude)
          : t('common.values.not_available'),
    }))
    totalHubs.value = locationsData.value.nodesCount ?? locationsData.value.nodes.length
  }
})

const isLoading = computed(() => suppliersPending.value || offersPending.value || locationsPending.value)

const canLoadMoreSuppliers = computed(() => suppliers.value.length < totalSuppliers.value)
const canLoadMoreOffers = computed(() => offers.value.length < totalOffers.value)
const canLoadMoreHubs = computed(() => locations.value.length < totalHubs.value)

const loadMoreSuppliers = async () => {
  if (isLoadingMore.value.suppliers) return
  isLoadingMore.value.suppliers = true
  try {
    const data = await execute(
      GetSuppliersDocument,
      { limit: PAGE_SIZE, offset: suppliers.value.length },
      'public',
      'exchange'
    )
    suppliers.value = suppliers.value.concat(data?.getSuppliers || [])
    totalSuppliers.value = data?.getSuppliersCount ?? totalSuppliers.value
  } finally {
    isLoadingMore.value.suppliers = false
  }
}

const loadMoreOffers = async () => {
  if (isLoadingMore.value.offers) return
  isLoadingMore.value.offers = true
  try {
    const data = await execute(
      GetOffersDocument,
      { limit: PAGE_SIZE, offset: offers.value.length },
      'public',
      'exchange'
    )
    const next = (data?.getOffers || []).map((offer: any) => ({
      ...offer,
      latitude: offer.locationLatitude,
      longitude: offer.locationLongitude
    }))
    offers.value = offers.value.concat(next)
    totalOffers.value = data?.getOffersCount ?? totalOffers.value
  } finally {
    isLoadingMore.value.offers = false
  }
}

const loadMoreHubs = async () => {
  if (isLoadingMore.value.hubs) return
  isLoadingMore.value.hubs = true
  try {
    const data = await execute(
      GetNodesDocument,
      { limit: PAGE_SIZE, offset: locations.value.length, transportType: null },
      'public',
      'geo'
    )
    const next = (data?.nodes || []).map((location: any) => ({
      ...location,
      distance:
        location?.latitude && location?.longitude
          ? calculateDistance(location.latitude, location.longitude)
          : t('common.values.not_available'),
    }))
    locations.value = locations.value.concat(next)
    totalHubs.value = data?.nodesCount ?? totalHubs.value
  } finally {
    isLoadingMore.value.hubs = false
  }
}

// Collect all locations for the map
const mapLocations = computed(() => {
  const locs: Array<{
    uuid: string | null | undefined
    name: string | null | undefined
    latitude: number | null | undefined
    longitude: number | null | undefined
    country: string | null | undefined
  }> = []

  // Hubs
  locations.value.forEach(hub => {
    if (hub.latitude && hub.longitude) {
      locs.push({
        uuid: hub.uuid,
        name: hub.name,
        latitude: hub.latitude,
        longitude: hub.longitude,
        country: hub.country
      })
    }
  })

  // Offers (with coordinates mapping)
  offers.value.forEach(offer => {
    const lat = offer.latitude || offer.locationLatitude
    const lng = offer.longitude || offer.locationLongitude
    if (lat && lng) {
      locs.push({
        uuid: offer.uuid,
        name: offer.title,
        latitude: lat,
        longitude: lng,
        country: offer.locationName
      })
    }
  })

  return locs
})
</script>
