<template>
  <div class="map-wrap">
    <div ref="mapEl" class="map-canvas"></div>

    <!-- SDK 미로드/키 미설정 시 폴백 -->
    <div v-if="errorMsg" class="map-fallback flex flex-center column text-grey-6">
      <q-icon name="map" size="40px" color="secondary" />
      <div class="q-mt-sm text-caption text-center">{{ errorMsg }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { loadKakaoMaps } from '@/lib/kakaoMap'
import type { Spot } from '@/api/spots'

const props = defineProps<{
  spots: Spot[]
  selectedId: number | null
}>()
const emit = defineEmits<{ (e: 'select', id: number): void }>()

// 기본 중심: 서울시청
const DEFAULT_CENTER = { lat: 37.5666, lng: 126.9784 }

const mapEl = ref<HTMLElement | null>(null)
const errorMsg = ref('')

let map: kakao.maps.Map | null = null
let infoWindow: kakao.maps.InfoWindow | null = null
const markers = new Map<number, kakao.maps.Marker>()

onMounted(async () => {
  try {
    const kk = await loadKakaoMaps()
    if (!mapEl.value) return

    const center = firstCenter()
    map = new kk.maps.Map(mapEl.value, {
      center: new kk.maps.LatLng(center.lat, center.lng),
      level: 5, // 네이버 zoom 14 ≈ 카카오 level 5
    })
    // 확대/축소 +/- 컨트롤 (핀치 줌도 함께 동작)
    map.addControl(new kk.maps.ZoomControl(), kk.maps.ControlPosition.RIGHT)
    infoWindow = new kk.maps.InfoWindow({ removable: false })
    // 지도 아무 곳이나 탭하면 가장 가까운 스팟 선택 (마커가 겹쳐도 선택 가능)
    kk.maps.event.addListener(map, 'click', (e) => {
      if (!e) return
      const spot = nearestSpot(e.latLng.getLat(), e.latLng.getLng())
      if (spot) emit('select', spot.id)
    })
    renderMarkers(kk)
  } catch (e) {
    errorMsg.value = `${(e as Error).message} 지도 키(VITE_KAKAO_MAP_KEY)를 설정하세요.`
  }
})

onBeforeUnmount(() => {
  markers.forEach((m) => m.setMap(null))
  markers.clear()
})

// 스팟 목록이 갱신되면 마커 다시 그림
watch(
  () => props.spots,
  () => {
    if (map && window.kakao?.maps) renderMarkers(window.kakao)
  },
)

// 외부에서 선택된 스팟이 바뀌면 지도 중심 이동 + 정보창
watch(
  () => props.selectedId,
  (id) => {
    if (!map || id == null) return
    const spot = props.spots.find((s) => s.id === id)
    const marker = markers.get(id)
    if (spot?.latitude != null && spot?.longitude != null) {
      map.panTo(new window.kakao.maps.LatLng(spot.latitude, spot.longitude))
    }
    if (spot && marker) openInfo(spot, marker)
  },
)

function firstCenter() {
  const withCoord = props.spots.find((s) => s.latitude != null && s.longitude != null)
  return withCoord ? { lat: withCoord.latitude!, lng: withCoord.longitude! } : DEFAULT_CENTER
}

/** 클릭 좌표에서 가장 가까운 스팟(위경도 제곱거리 최소). */
function nearestSpot(lat: number, lng: number): Spot | null {
  let best: Spot | null = null
  let bestDist = Infinity
  for (const s of props.spots) {
    if (s.latitude == null || s.longitude == null) continue
    const dLat = s.latitude - lat
    const dLng = s.longitude - lng
    const dist = dLat * dLat + dLng * dLng
    if (dist < bestDist) {
      bestDist = dist
      best = s
    }
  }
  return best
}

function renderMarkers(kk: typeof kakao) {
  markers.forEach((m) => m.setMap(null))
  markers.clear()

  for (const spot of props.spots) {
    if (spot.latitude == null || spot.longitude == null) continue
    const marker = new kk.maps.Marker({
      position: new kk.maps.LatLng(spot.latitude, spot.longitude),
      map: map!,
      title: spot.name,
    })
    kk.maps.event.addListener(marker, 'click', () => {
      openInfo(spot, marker)
      emit('select', spot.id)
    })
    markers.set(spot.id, marker)
  }
}

function openInfo(spot: Spot, marker: kakao.maps.Marker) {
  if (!infoWindow || !map) return
  infoWindow.setContent(
    `<div style="padding:6px 12px;font-size:13px;font-weight:600;color:#3E92CC;white-space:nowrap;">📍 ${spot.name}</div>`,
  )
  infoWindow.open(map, marker)
}
</script>

<style scoped>
.map-wrap {
  position: relative;
  height: 240px;
  border-radius: 8px;
  overflow: hidden;
}
.map-canvas {
  width: 100%;
  height: 100%;
}
.map-fallback {
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, #eaf5fe 0%, #d7ecfb 100%);
  padding: 16px;
}
</style>