<template>
  <div class="space-y-6">
    <!-- Header -->
    <Card padding="lg" class="border border-base-300">
      <RouteSummaryHeader :title="summaryTitle" :meta="summaryMeta" />
    </Card>

    <!-- Loading -->
    <div v-if="pending" class="text-sm text-base-content/60">
      Загрузка маршрутов...
    </div>

    <!-- Error -->
    <div v-else-if="error" class="text-sm text-error">
      Ошибка загрузки маршрутов: {{ error.message }}
    </div>

    <!-- Results -->
    <div v-else-if="productRouteOptions.length > 0" class="space-y-4">
      <OfferResultCard
        v-for="(option, index) in productRouteOptions"
        :key="option.sourceUuid ?? index"
        :supplier-name="getSupplierName(option.sourceUuid)"
        :location-name="getOfferData(option.sourceUuid)?.locationName"
        :product-name="productName"
        :price-per-unit="parseFloat(getOfferData(option.sourceUuid)?.pricePerUnit || '0') || null"
        :quantity="getOfferData(option.sourceUuid)?.quantity"
        :currency="getOfferData(option.sourceUuid)?.currency"
        :unit="getOfferData(option.sourceUuid)?.unit"
        :stages="getRouteStages(option)"
        :total-time-seconds="option.routes?.[0]?.totalTimeSeconds ?? null"
        :kyc-profile-uuid="getKycProfileUuid(option.sourceUuid)"
        @select="navigateToOffer(option.sourceUuid)"
      />
    </div>

    <!-- Legacy routes (fallback) -->
    <div v-else-if="legacyRoutes.length > 0" class="space-y-6">
      <Card
        v-for="(route, routeIndex) in legacyRoutes"
        :key="routeIndex"
        padding="lg"
        class="border border-base-300"
      >
        <Stack gap="4">
          <div class="flex flex-wrap items-center justify-between gap-2">
            <Text weight="semibold">Маршрут {{ routeIndex + 1 }}</Text>
            <Text tone="muted" size="sm">
              {{ formatDistance(route.totalDistanceKm) }} км · {{ formatDuration(route.totalTimeSeconds) }}
            </Text>
          </div>

          <RouteStagesList :stages="mapRouteStages(route)" />

          <div class="divider my-0"></div>

          <RequestRoutesMap :routes="[route]" :height="240" />
        </Stack>
      </Card>
    </div>

    <!-- Empty -->
    <div v-else class="text-sm text-base-content/60">
      Маршруты не найдены. Возможно, нет связи между точками в графе.
    </div>
  </div>
</template>

<script setup lang="ts">
import { GetNodeDocument, NearestOffersDocument } from '~/composables/graphql/public/geo-generated'
import type { RouteStageItem } from '~/components/RouteStagesList.vue'

interface RouteStage {
  fromUuid?: string | null
  fromName?: string | null
  toName?: string | null
  distanceKm?: number | null
  travelTimeSeconds?: number | null
  transportType?: string | null
}

interface RoutePathType {
  totalDistanceKm?: number | null
  totalTimeSeconds?: number | null
  stages?: (RouteStage | null)[]
}
import { GetOfferDocument, GetSupplierProfileByTeamDocument, type GetOfferQueryResult, type GetSupplierProfileByTeamQueryResult } from '~/composables/graphql/public/exchange-generated'
import type { OfferWithRoute, RouteStage } from '~/composables/graphql/public/geo-generated'

const route = useRoute()
const localePath = useLocalePath()
const searchStore = useSearchStore()
const { execute } = useGraphQL()

const productName = computed(() => searchStore.searchForm.product || (route.query.product as string) || 'Товар')
const locationName = computed(() => searchStore.searchForm.location || (route.query.location as string) || 'Назначение')
const quantity = computed(() => (route.query.quantity as string) || searchStore.searchForm.quantity)

// Offer data for prices
type OfferData = NonNullable<GetOfferQueryResult['getOffer']>
const offersData = ref<Map<string, OfferData>>(new Map())
// Supplier data for KYC profile UUID (by team_uuid)
type SupplierData = NonNullable<GetSupplierProfileByTeamQueryResult['getSupplierProfileByTeam']>
const suppliersData = ref<Map<string, SupplierData>>(new Map())

const summaryTitle = computed(() => `${productName.value} → ${locationName.value}`)
const summaryMeta = computed(() => {
  const meta: string[] = []
  if (quantity.value) {
    meta.push(`${quantity.value}`)
  }
  return meta
})

// Determine context
const productUuid = computed(() => (route.query.productUuid as string) || searchStore.searchForm.productUuid)
const destinationUuid = computed(() => (route.query.locationUuid as string) || searchStore.searchForm.locationUuid)

type ProductRouteOption = {
  sourceUuid?: string | null
  sourceName?: string | null
  sourceLat?: number | null
  sourceLon?: number | null
  distanceKm?: number | null
  routes?: RoutePathType[] | null
}

const fetchOffersByHub = async () => {
  if (!productUuid.value || !destinationUuid.value) return null

  // 1. Get hub node to get coordinates
  const hubData = await execute(GetNodeDocument, { uuid: destinationUuid.value }, 'public', 'geo')
  const hub = hubData?.node

  if (!hub?.latitude || !hub?.longitude) {
    console.warn('Hub has no coordinates')
    return null
  }

  // 2. Find offers near hub for this product WITH routes calculated on backend
  const offersResponse = await execute(
    NearestOffersDocument,
    {
      lat: hub.latitude,
      lon: hub.longitude,
      productUuid: productUuid.value,
      hubUuid: destinationUuid.value, // Pass hubUuid to get routes calculated on backend
      radius: 500,
      limit: 5
    },
    'public',
    'geo'
  )

  const offers = offersResponse?.nearest_offers || []

  // Offers already include routes from backend
  const offersWithRoutes = offers
    .filter((offer): offer is NonNullable<OfferWithRoute> => offer !== null)
    .map((offer) => ({
      sourceUuid: offer.uuid,
      sourceName: offer.product_name,
      sourceLat: offer.latitude,
      sourceLon: offer.longitude,
      distanceKm: offer.distance_km,
      routes: offer.routes || []
    }))

  return { offersByHub: offersWithRoutes }
}

const { data: productRoutesData, pending, error } = await useAsyncData(
  () => `offers-by-hub-${productUuid.value}-${destinationUuid.value}`,
  async () => {
    if (productUuid.value && destinationUuid.value) {
      return await fetchOffersByHub()
    }
    return null
  },
  { watch: [productUuid, destinationUuid] }
)

const productRouteOptions = computed(() => {
  const options = productRoutesData.value?.offersByHub as ProductRouteOption[] | undefined
  return options?.filter(Boolean) || []
})

const legacyRoutes = computed<RoutePathType[]>(() => {
  return []  // Legacy routes removed
})

const mapRouteStages = (route: RoutePathType): RouteStageItem[] => {
  return (route.stages || [])
    .filter(Boolean)
    .map((stage, index) => ({
      key: stage?.fromUuid || `stage-${index}`,
      from: stage?.fromName || 'Начало',
      to: stage?.toName || 'Конец',
      distanceKm: stage?.distanceKm,
      durationSeconds: stage?.travelTimeSeconds,
      transportType: stage?.transportType
    }))
}

// Get route stages for OfferResultCard stepper
const getRouteStages = (option: ProductRouteOption) => {
  const route = option.routes?.[0]
  if (!route?.stages) return []
  return route.stages
    .filter((stage): stage is NonNullable<RouteStage> => stage !== null)
    .map((stage) => ({
      transportType: stage.transport_type,
      distanceKm: stage.distance_km,
      travelTimeSeconds: stage.travel_time_seconds,
      fromName: stage.from_name
    }))
}

// Get offer data for card
const getOfferData = (uuid?: string | null) => {
  if (!uuid) return null
  return offersData.value.get(uuid)
}

// Get KYC profile UUID by offer UUID
const getKycProfileUuid = (offerUuid?: string | null) => {
  if (!offerUuid) return null
  const offer = offersData.value.get(offerUuid)
  if (!offer?.teamUuid) return null
  const supplier = suppliersData.value.get(offer.teamUuid)
  return supplier?.kycProfileUuid || null
}

const getSupplierName = (offerUuid?: string | null) => {
  if (!offerUuid) return null
  const offer = offersData.value.get(offerUuid)
  if (!offer?.teamUuid) return null
  const supplier = suppliersData.value.get(offer.teamUuid)
  return supplier?.name || null
}

// Navigate to offer detail page
const navigateToOffer = (offerUuid?: string | null) => {
  if (!offerUuid) return
  navigateTo(localePath(`/catalog/offers/detail/${offerUuid}`))
}

// Load offer details for prices
const loadOfferDetails = async (options: ProductRouteOption[]) => {
  if (options.length === 0) {
    offersData.value.clear()
    suppliersData.value.clear()
    return
  }

  const newOffersData = new Map<string, OfferData>()
  const newSuppliersData = new Map<string, SupplierData>()
  const teamUuidsToLoad = new Set<string>()

  // First, load all offers
  await Promise.all(options.map(async (option) => {
    if (!option.sourceUuid) return
    try {
      const data = await execute(GetOfferDocument, { uuid: option.sourceUuid }, 'public', 'exchange')
      if (data?.getOffer) {
        newOffersData.set(option.sourceUuid, data.getOffer)
        if (data.getOffer.teamUuid) {
          teamUuidsToLoad.add(data.getOffer.teamUuid)
        }
      }
    } catch (error) {
      console.error('Error loading offer:', option.sourceUuid, error)
    }
  }))

  // Then, load supplier profiles for all team UUIDs
  await Promise.all([...teamUuidsToLoad].map(async (teamUuid) => {
    try {
      const data = await execute(GetSupplierProfileByTeamDocument, { teamUuid }, 'public', 'exchange')
      if (data?.getSupplierProfileByTeam) {
        newSuppliersData.set(teamUuid, data.getSupplierProfileByTeam)
      }
    } catch (error) {
      console.error('Error loading supplier:', teamUuid, error)
    }
  }))

  offersData.value = newOffersData
  suppliersData.value = newSuppliersData
}

// Watch for route options and load offers
watch(productRouteOptions, (options) => {
  if (options.length > 0) {
    loadOfferDetails(options)
  }
}, { immediate: true })

// Formatting helpers
const formatDistance = (km: number | null | undefined) => {
  if (!km) return '0'
  return Math.round(km).toLocaleString()
}

const formatDuration = (seconds: number | null | undefined) => {
  if (!seconds) return '-'
  const hours = Math.floor(seconds / 3600)
  const minutes = Math.floor((seconds % 3600) / 60)
  if (hours > 24) {
    const days = Math.floor(hours / 24)
    const remainingHours = hours % 24
    return `${days}д ${remainingHours}ч`
  }
  if (hours > 0) {
    return `${hours}ч ${minutes}м`
  }
  return `${minutes}м`
}
</script>
