<template>
  <Section variant="plain" paddingY="md">
    <Stack gap="4">
      <Stack direction="row" align="center" gap="2">
        <Icon :name="transportIcon" size="24" />
        <Heading :level="2">{{ title }}</Heading>
      </Stack>

      <div v-if="edges.length === 0" class="text-base-content/60">
        {{ t('catalogHub.nearbyHubs.empty') }}
      </div>

      <div v-else class="grid grid-cols-1 lg:grid-cols-2 gap-4">
        <!-- Map -->
        <div class="order-2 lg:order-1">
          <ClientOnly>
            <MapboxMap
              :key="mapId"
              :map-id="mapId"
              style="height: 300px; width: 100%;"
              class="rounded-lg border border-base-300"
              :options="mapOptions"
              @load="onMapCreated"
            >
              <MapboxNavigationControl position="top-right" />
            </MapboxMap>

            <template #fallback>
              <div class="h-[300px] w-full bg-base-200 rounded-lg flex items-center justify-center">
                <Spinner />
              </div>
            </template>
          </ClientOnly>
        </div>

        <!-- Neighbors list -->
        <div class="order-1 lg:order-2">
          <Stack gap="2">
            <NuxtLink
              v-for="edge in edges"
              :key="edge.toUuid"
              :to="localePath(`/catalog/hubs/${edge.toUuid}`)"
              class="flex flex-col gap-2 p-3 rounded-lg border border-base-300 hover:bg-base-200 transition-colors"
            >
              <div class="flex items-center justify-between">
                <div class="flex items-center gap-3">
                  <div class="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center">
                    <Icon name="lucide:map-pin" size="16" class="text-primary" />
                  </div>
                  <div>
                    <div class="font-medium">{{ edge.toName }}</div>
                  </div>
                </div>
                <div class="text-right">
                  <div class="font-semibold text-primary">{{ edge.distanceKm }} km</div>
                </div>
              </div>
            </NuxtLink>
          </Stack>
        </div>
      </div>
    </Stack>
  </Section>
</template>

<script setup lang="ts">
import type { Map as MapboxMapType } from 'mapbox-gl'
import { LngLatBounds, Popup } from 'mapbox-gl'
import type { EdgeType } from '~/composables/graphql/public/geo-generated'

interface CurrentHub {
  uuid: string
  name: string
  latitude: number
  longitude: number
}

interface RouteGeometry {
  toUuid: string
  coordinates: [number, number][]
}

const props = defineProps<{
  edges: EdgeType[]
  currentHub: CurrentHub
  routeGeometries: RouteGeometry[]
  transportType: 'auto' | 'rail'
}>()

const { t } = useI18n()
const localePath = useLocalePath()
const mapRef = ref<MapboxMapType | null>(null)
const isMapReady = ref(false)
const didFitBounds = ref(false)

const mapId = computed(() => `nearby-hubs-${props.currentHub.uuid}-${props.transportType}`)

const transportIcon = computed(() =>
  props.transportType === 'auto' ? 'lucide:truck' : 'lucide:train'
)

const title = computed(() =>
  props.transportType === 'auto'
    ? t('catalogHub.nearbyHubs.byRoad')
    : t('catalogHub.nearbyHubs.byRail')
)

const geometryByUuid = computed(() => {
  const map = new Map<string, RouteGeometry>()
  props.routeGeometries.forEach((route) => {
    if (route?.toUuid) {
      map.set(route.toUuid, route)
    }
  })
  return map
})

const lineColor = computed(() =>
  props.transportType === 'auto' ? '#3b82f6' : '#10b981'
)

const mapCenter = computed<[number, number]>(() => {
  if (!props.currentHub.latitude || !props.currentHub.longitude) {
    return [0, 0]
  }

  const allLats = [props.currentHub.latitude, ...props.edges.map(e => e.toLatitude!).filter(Boolean)]
  const allLngs = [props.currentHub.longitude, ...props.edges.map(e => e.toLongitude!).filter(Boolean)]

  const avgLng = allLngs.reduce((a, b) => a + b, 0) / allLngs.length
  const avgLat = allLats.reduce((a, b) => a + b, 0) / allLats.length

  return [avgLng, avgLat]
})

const mapZoom = computed(() => {
  if (props.edges.length === 0) return 5

  const distances = props.edges.map(e => e.distanceKm || 0)
  const maxDistance = Math.max(...distances)

  if (maxDistance > 2000) return 2
  if (maxDistance > 1000) return 3
  if (maxDistance > 500) return 4
  if (maxDistance > 200) return 5
  return 6
})

const mapOptions = computed(() => ({
  style: 'mapbox://styles/mapbox/streets-v12',
  center: mapCenter.value,
  zoom: mapZoom.value
}))

const buildRouteFeatureCollection = () => ({
  type: 'FeatureCollection' as const,
  features: props.routeGeometries.map(route => ({
    type: 'Feature' as const,
    properties: { toUuid: route.toUuid },
    geometry: {
      type: 'LineString' as const,
      coordinates: route.coordinates
    }
  }))
})

const buildNeighborsFeatureCollection = () => ({
  type: 'FeatureCollection' as const,
  features: props.edges.filter(e => e.toLatitude && e.toLongitude).map(edge => ({
    type: 'Feature' as const,
    properties: {
      uuid: edge.toUuid,
      name: edge.toName,
      distanceKm: edge.distanceKm
    },
    geometry: {
      type: 'Point' as const,
      coordinates: [edge.toLongitude!, edge.toLatitude!]
    }
  }))
})

const updateRoutesSource = () => {
  const map = mapRef.value
  if (!map) return
  const source = map.getSource('routes') as mapboxgl.GeoJSONSource | undefined
  if (!source) return
  source.setData(buildRouteFeatureCollection())
  console.log('[NearbyHubsSection] routes source updated', {
    mapId: mapId.value,
    routes: props.routeGeometries.length
  })
}

const updateNeighborsSource = () => {
  const map = mapRef.value
  if (!map) return
  const source = map.getSource('neighbors') as mapboxgl.GeoJSONSource | undefined
  if (!source) return
  source.setData(buildNeighborsFeatureCollection())
  console.log('[NearbyHubsSection] neighbors source updated', {
    mapId: mapId.value,
    neighbors: props.edges.length
  })
}

const fitMapToRoutes = () => {
  const map = mapRef.value
  if (!map || didFitBounds.value) return

  const coordinates = props.routeGeometries.flatMap(route => route.coordinates || [])
  if (coordinates.length === 0) return

  const bounds = coordinates.reduce(
    (acc, coord) => acc.extend(coord as [number, number]),
    new LngLatBounds(
      coordinates[0] as [number, number],
      coordinates[0] as [number, number]
    )
  )

  map.fitBounds(bounds, {
    padding: 40,
    maxZoom: 8
  })

  didFitBounds.value = true
  console.log('[NearbyHubsSection] fitBounds applied', {
    mapId: mapId.value,
    points: coordinates.length
  })
}

const onMapCreated = (map: MapboxMapType) => {
  mapRef.value = map
  console.log('[NearbyHubsSection] map created', { mapId: mapId.value })

  const initMap = () => {
    map.addSource('routes', {
      type: 'geojson',
      data: buildRouteFeatureCollection()
    })

    // Route lines layer
    map.addLayer({
      id: 'routes-lines',
      type: 'line',
      source: 'routes',
      layout: {
        'line-join': 'round',
        'line-cap': 'round'
      },
      paint: {
        'line-color': lineColor.value,
        'line-width': 4,
        'line-opacity': 0.8
      }
    })

    // Add current hub marker source
    map.addSource('current-hub', {
      type: 'geojson',
      data: {
        type: 'Feature',
        properties: { name: props.currentHub.name },
        geometry: {
          type: 'Point',
          coordinates: [props.currentHub.longitude, props.currentHub.latitude]
        }
      }
    })

    // Current hub circle
    map.addLayer({
      id: 'current-hub-circle',
      type: 'circle',
      source: 'current-hub',
      paint: {
        'circle-radius': 10,
        'circle-color': lineColor.value,
        'circle-stroke-width': 2,
        'circle-stroke-color': '#ffffff'
      }
    })

    // Add neighbor markers source
    map.addSource('neighbors', {
      type: 'geojson',
      data: buildNeighborsFeatureCollection()
    })

    // Neighbor markers
    map.addLayer({
      id: 'neighbors-circles',
      type: 'circle',
      source: 'neighbors',
      paint: {
        'circle-radius': 8,
        'circle-color': '#ef4444',
        'circle-stroke-width': 2,
        'circle-stroke-color': '#ffffff'
      }
    })

    // Popups on click
    map.on('click', 'current-hub-circle', (e) => {
      const coordinates = (e.features![0].geometry as GeoJSON.Point).coordinates.slice() as [number, number]
      const name = e.features![0].properties?.name

      new Popup()
        .setLngLat(coordinates)
        .setHTML(`<strong>${name}</strong>`)
        .addTo(map)
    })

    map.on('click', 'neighbors-circles', (e) => {
      const coordinates = (e.features![0].geometry as GeoJSON.Point).coordinates.slice() as [number, number]
      const featureProps = e.features![0].properties
      const name = featureProps?.name
      const distanceKm = featureProps?.distanceKm

      new Popup()
        .setLngLat(coordinates)
        .setHTML(`<strong>${name}</strong><br/>${distanceKm} km`)
        .addTo(map)
    })

    // Cursor changes
    map.on('mouseenter', 'current-hub-circle', () => { map.getCanvas().style.cursor = 'pointer' })
    map.on('mouseleave', 'current-hub-circle', () => { map.getCanvas().style.cursor = '' })
    map.on('mouseenter', 'neighbors-circles', () => { map.getCanvas().style.cursor = 'pointer' })
    map.on('mouseleave', 'neighbors-circles', () => { map.getCanvas().style.cursor = '' })

    isMapReady.value = true
    updateRoutesSource()
    updateNeighborsSource()
    fitMapToRoutes()
    console.log('[NearbyHubsSection] map ready', { mapId: mapId.value })
  }

  if (map.loaded()) {
    initMap()
  } else {
    map.on('load', initMap)
  }
}

watch(
  () => props.routeGeometries,
  () => {
    didFitBounds.value = false
    updateRoutesSource()
    if (isMapReady.value) {
      fitMapToRoutes()
    }
  },
  { deep: true }
)

watch(
  () => props.edges,
  () => updateNeighborsSource(),
  { deep: true }
)

onMounted(() => {
  console.log('[NearbyHubsSection] mounted', {
    mapId: mapId.value,
    edges: props.edges.length,
    routes: props.routeGeometries.length,
    transportType: props.transportType
  })
})
</script>
