<template>
  <div class="relative w-full h-full">
    <div ref="mapContainer" class="w-full h-full rounded-none" />
  </div>
</template>

<script setup lang="ts">
import type { Map, Marker, DivIcon } from 'leaflet'

interface Pratique {
  id: number
  nom: string
  lat?: number | null
  lng?: number | null
  pays?: string
  ville?: string
  type?: string
  score?: number
}

const props = defineProps<{
  orgs: Pratique[]
  selectedId?: number | null
}>()

const emit = defineEmits<{
  'select-org': [id: number]
}>()

const mapContainer = ref<HTMLElement | null>(null)
let mapInstance: Map | null = null
let clusterGroup: any = null
const markers = new Map<number, Marker>()
let tileLayerInstance: any = null

function createPinIcon(score: number, isSelected = false): DivIcon {
  const L = (window as any).L
  // Couleur selon score (1-5) : du pale au vif
  const bg = score >= 4 ? '#f5b342' : score >= 3 ? 'rgba(26,34,56,0.75)' : 'rgba(26,34,56,0.5)'
  const border = isSelected ? '#f5b342' : '#ffffff'
  const size = isSelected ? 18 : 14
  const shadow = isSelected ? '0 0 0 4px rgba(245,179,66,0.5)' : 'none'

  return L.divIcon({
    className: '',
    html: `<div style="
      width: ${size}px;
      height: ${size}px;
      border-radius: 50%;
      background: ${bg};
      border: 2px solid ${border};
      box-shadow: ${shadow};
      transition: all 0.2s;
    "></div>`,
    iconSize: [size, size],
    iconAnchor: [size / 2, size / 2],
    popupAnchor: [0, -(size / 2 + 4)],
  })
}

async function initMap() {
  if (!mapContainer.value) return

  const Lmod = await import('leaflet')
  const L: any = (Lmod as any).default || Lmod
  await import('leaflet/dist/leaflet.css')
  // @ts-ignore
  await import('leaflet.markercluster/dist/MarkerCluster.css')
  // @ts-ignore
  await import('leaflet.markercluster/dist/MarkerCluster.Default.css')

  ;(window as any).L = L
  // @ts-ignore
  await import('leaflet.markercluster')
  const MarkerClusterGroup = L.MarkerClusterGroup

  mapInstance = L.map(mapContainer.value, {
    center: [50.0, 10.0],
    zoom: 4,
    zoomControl: true,
    attributionControl: true,
    maxBounds: [[30.0, -15.0], [72.0, 40.0]],
    maxBoundsViscosity: 0.8,
    minZoom: 3,
    maxZoom: 18,
  })

  const isDark = typeof document !== 'undefined' && document.documentElement.classList.contains('dark')
  const tileUrl = isDark
    ? 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'
    : 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png'

  tileLayerInstance = L.tileLayer(tileUrl, {
    attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
    maxZoom: 19,
  })
  tileLayerInstance.addTo(mapInstance!)

  clusterGroup = new MarkerClusterGroup({
    disableClusteringAtZoom: 12,
    maxClusterRadius: 50,
    showCoverageOnHover: false,
    iconCreateFunction: (cluster: any) => {
      const count = cluster.getChildCount()
      return L.divIcon({
        html: `<div style="
          width: 36px; height: 36px; border-radius: 50%;
          background: var(--nav-primary);
          color: var(--nav-text-on-primary);
          display: flex; align-items: center; justify-content: center;
          font-weight: 700; font-size: 13px;
          border: 2px solid white;
          font-family: var(--nav-font);
        ">${count}</div>`,
        className: '',
        iconSize: [36, 36],
        iconAnchor: [18, 18],
      })
    },
  })

  mapInstance.addLayer(clusterGroup)
  updateMarkers(L)
}

// Vue initiale (centre Europe + zoom 4) - sauvegardee pour reset
const INITIAL_CENTER: [number, number] = [50.0, 10.0]
const INITIAL_ZOOM = 4

let initialFitDone = false

function updateMarkers(L?: any) {
  if (!mapInstance || !clusterGroup) return
  const leaflet = L || (window as any).L
  if (!leaflet) return

  clusterGroup.clearLayers()
  markers.clear()

  const orgsWithCoords = props.orgs.filter(
    (o) => o.lat != null && o.lng != null
  )

  orgsWithCoords.forEach((org) => {
    const isSelected = org.id === props.selectedId
    const icon = createPinIcon(org.score ?? 1, isSelected)

    const marker = leaflet.marker([org.lat!, org.lng!], { icon })

    marker.bindPopup(`
      <div style="font-family: var(--nav-font); min-width: 180px; padding: 4px 0;">
        <div style="font-weight: 700; color: var(--nav-text); margin-bottom: 4px;">${org.nom}</div>
        ${org.pays ? `<div style="font-size: 11px; color: var(--nav-text-muted);">${org.pays}${org.ville ? ' · ' + org.ville : ''}</div>` : ''}
        ${org.type ? `<div style="font-size: 11px; color: var(--nav-text-muted); margin-top: 2px;">${org.type}</div>` : ''}
        <a href="/pratique/${org.id}" style="
          display: inline-block; margin-top: 8px; font-size: 12px;
          color: var(--nav-primary-solid); text-decoration: underline;
        ">Voir la fiche →</a>
      </div>
    `, { maxWidth: 240 })

    marker.on('click', () => emit('select-org', org.id))

    markers.set(org.id, marker)
    clusterGroup.addLayer(marker)
  })

  // Bug E2E L3 : recadrer la carte sur les resultats filtres
  // Conditions : 1+ resultat, et au moins 1 marker hors viewport actuel.
  // On evite de recadrer au tout premier rendu (laisser la vue initiale).
  if (orgsWithCoords.length > 0 && initialFitDone) {
    try {
      const bounds = leaflet.latLngBounds(
        orgsWithCoords.map((o) => [o.lat!, o.lng!])
      )
      // On recadre uniquement si la liste filtree est restreinte
      // (evite un recadrage permanent quand toutes les fiches sont la).
      if (orgsWithCoords.length <= 15) {
        mapInstance.fitBounds(bounds, {
          padding: [40, 40],
          maxZoom: 10,
          animate: true,
        })
      }
    } catch (e) {
      console.warn('[EuropeMap] fitBounds echoue:', e)
    }
  }
  initialFitDone = true
}

watch(
  () => props.orgs,
  () => updateMarkers(),
  { deep: false }
)

watch(
  () => props.selectedId,
  (newId, oldId) => {
    if (!mapInstance) return
    const leaflet = (window as any).L
    if (!leaflet) return

    if (oldId != null) {
      const oldMarker = markers.get(oldId)
      const oldOrg = props.orgs.find(o => o.id === oldId)
      if (oldMarker && oldOrg) {
        oldMarker.setIcon(createPinIcon(oldOrg.score ?? 1, false))
      }
    }
    if (newId != null) {
      const newMarker = markers.get(newId)
      const newOrg = props.orgs.find(o => o.id === newId)
      if (newMarker && newOrg) {
        newMarker.setIcon(createPinIcon(newOrg.score ?? 1, true))
        const latLng = newMarker.getLatLng()
        mapInstance.panTo(latLng, { animate: true })
      }
    }
  }
)

function updateTileTheme(dark: boolean) {
  if (!mapInstance || !tileLayerInstance) return
  const L = (window as any).L
  if (!L) return
  const url = dark
    ? 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'
    : 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png'
  tileLayerInstance.setUrl(url)
}

let themeObserver: MutationObserver | null = null

onMounted(() => {
  initMap()

  themeObserver = new MutationObserver(() => {
    const dark = document.documentElement.classList.contains('dark')
    updateTileTheme(dark)
  })
  themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] })
})

onUnmounted(() => {
  themeObserver?.disconnect()
  if (mapInstance) {
    mapInstance.remove()
    mapInstance = null
  }
})
</script>
