import { tools } from '@tools'
import { useQuasar } from 'quasar'
import type { PropType } from 'vue';
import { defineComponent, onMounted, ref, toRaw, computed, toRef, watch, shallowRef } from 'vue'

import 'leaflet/dist/leaflet.css'
// @ts-ignore
import * as L from 'leaflet'
import '../../utils/leaflet-extensions'; // Importa le estensioni
import 'leaflet.markercluster/dist/MarkerCluster.css'
import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
import 'leaflet.markercluster'

import { useUserStore } from '@src/store/UserStore'
import { useGlobalStore } from '@src/store/globalStore'
import { useI18n } from 'vue-i18n'
import { ICoordGPS } from '@src/model'

export default defineComponent({
  name: 'CMapByTable',
  emits: ['clickMarker', 'updateMapBoundaries', 'updateMapZoomOut'],
  props: {
    mytable: {
      type: String,
      required: true,
    },
    arrcordprop: {
      type: Array as PropType<any[]>,
      required: false,
      default: () => { return [] }
    }
  },
  setup(props, { emit }) {
    const $q = useQuasar()
    const { t } = useI18n()
    const userStore = useUserStore()
    const globalStore = useGlobalStore()

    const iconWidth = ref(25)
    const iconHeight = ref(40)
    const zoom = ref(8)

    const map = shallowRef(<any>null);

    const visiblePosition = ref(false)

    const markers = shallowRef(<any>null);

    const isTrackingLocation = ref(false)

    const debug = ref(tools.isDevelop())

    const currentMarkerPositionGPS = shallowRef<L.Marker | null>(null)

    const centerCoordinates = ref<{ lat: number; lng: number }>({ lat: 0, lng: 0 });  //

    const arrMarkers = ref(<any>[])

    const recordShowed = ref(<any>null)
    const markerShowed = shallowRef<any>(null)
    const markerTemporaneo = shallowRef<L.Marker | null>(null)

    const mapOptions = ref(<any>{
      zoomControl: false,
      zoomAnimation: false,
      fadeAnimation: true,
      markerZoomAnimation: true,
    })

    const tileLayerOptions = {
      maxZoom: 17,
      minZoom: 3,
    }

    const myIcon = L.icon({
      iconUrl: '/images/icon.png',
      iconSize: [30, 30],
      iconAnchor: [22, 35],
      popupAnchor: [-6, -36],
      shadowUrl: '/images/marker-shadow.png',
      shadowSize: [60, 30],
      shadowAnchor: [22, 35]
    });


    const myIconPosAtt = L.icon({
      iconUrl: '/images/icon.png',
      iconSize: [30, 30],
      iconAnchor: [22, 35],
      popupAnchor: [-6, -36],
      shadowUrl: '/images/marker-shadow.png',
      shadowSize: [60, 30],
      shadowAnchor: [22, 35]
    });

    const iconPosition = L.divIcon({
      className: 'custom-marker', // Classe CSS personalizzata
      html: '<span class="material-icons">location_on</span>',
      iconSize: [40, 40],
      iconAnchor: [22, 35],
      popupAnchor: [-6, -36],
    });

    const currentLocationIcon = L.divIcon({
      className: 'current-location-icon',
      iconSize: [20, 20],
      iconAnchor: [10, 10]
    });


    const arrcord = toRef(props, 'arrcordprop')

    const precZoomLevel = ref(0)

    const debounceTimer = ref(<any>null)

    watch(() => visiblePosition.value, () => {
      if (visiblePosition.value === true) {
        getCurrentPosition()
      } else {
        removeCurrentMarker()
      }
    })

    function mywidth() {
      return tools.getwidth($q) - 20
    }

    function myheight() {
      return $q.screen.height - 220
    }

    const iconUrl = computed(() => {
      return `https://placekitten.com/${iconWidth.value}/${iconHeight.value}`;
    })

    const iconSize = computed(() => {
      return [iconWidth.value, iconHeight.value];
    })

    function changeIcon() {
      iconWidth.value += 2;
      if (iconWidth.value > iconHeight.value) {
        iconWidth.value = Math.floor(iconHeight.value / 2);
      }
    }

    function getColor(d: any) {
      return d > 1000 ? '#800026' :
        d > 500 ? '#BD0026' :
          d > 200 ? '#E31A1C' :
            d > 100 ? '#FC4E2A' :
              d > 50 ? '#FD8D3C' :
                d > 20 ? '#FEB24C' :
                  d > 10 ? '#FED976' :
                    '#FFEDA0';
    }

    function style(feature: any) {
      return {
        fillColor: getColor(feature.properties.density),
        weight: 2,
        opacity: 1,
        color: 'white',
        dashArray: '3',
        fillOpacity: 0.7
      };
    }

    watch(arrcord.value, () => {
      updateMap()
    })

    onMounted(async () => {

      initMap()

    });

    function log(str: string) {
      console.log(str)
    }

    function getCoordinates(e: any) {
      // Ottieni la latitudine e la longitudine dal click
      const lat = e.latlng.lat
      const lng = e.latlng.lng

      // Fai qualcosa con le coordinate, ad esempio stamparle in console
      // console.log(`Latitudine: ${lat}, Longitudine: ${lng}`)
    }

    function getIconName(myrec: any) {
      const myarrSectors = myrec.sector
      if (!myarrSectors) return 'mdi-map-marker-outline'

      const sectId = myarrSectors[0]._id
      return globalStore.getIconBySector(sectId)
    }

    function updateBoundaries(updatedata: boolean) {
      if (map.value) {
        // Get the boubdaries of the map showed
        const bounds = map.value.getBounds();

        // tojson
        tools.setCookie(tools.COOK_MAPBOUNDS + 'ne', tools.objToStr(bounds.getNorthEast()))
        tools.setCookie(tools.COOK_MAPBOUNDS + 'sw', tools.objToStr(bounds.getSouthWest()))

        // Update Map Boundaries to the Parent
        emit('updateMapBoundaries', bounds.getNorthEast(), bounds.getSouthWest(), updatedata);
      }
    }

    function updateMapZoomOut() {
      emit('updateMapZoomOut', map.value.getZoom());

    }

    /**
     * Updates the center coordinates and zoom level of the map, and saves them in cookies.
     *
     * @return {void} This function does not return a value.
     */
    function onMoveEnd() {
      const center = map.value.getCenter(); // Ottieni le coordinate centrali
      centerCoordinates.value = { lat: center.lat, lng: center.lng }; // Salva le coordinate
      const currentZoomLevel = map.value.getZoom();
      tools.setCookie('last_lat', center.lat)
      tools.setCookie('last_lng', center.lng)
      tools.setCookie('zoom', currentZoomLevel)

      updateBoundaries(true)

      precZoomLevel.value = map.value.getZoom();
    }

    const onZoomEvent = () => {
      // Annulla il timer precedente se presente
      if (debounceTimer.value) {
        clearTimeout(debounceTimer.value);
      }

      // Inizia un nuovo timer di 1 secondo
      debounceTimer.value = setTimeout(() => {
        const currentZoomLevel = map.value.getZoom();

        if (currentZoomLevel < precZoomLevel.value) {
          // Aggiorna i dati della mappa
          updateMapZoomOut();

          // Aggiorna il livello di zoom precedente
          precZoomLevel.value = currentZoomLevel;
        }

      }, 500);
    }

    const onCustomButtonClick = () => {
      alert("Pulsante personalizzato cliccato!");
      // Logica aggiuntiva qui
    };

    function initMap() {
      if (true) {
        const getLastCoord = [tools.getCookie('last_lat', 42.71), tools.getCookie('last_lng', 12.934)]
        zoom.value = tools.getCookie('zoom', 8, true)
        // console.log('getLastCoord', getLastCoord, 'zoom', zoom.value)
        const newmapopt = {
          ...mapOptions.value,
          zoom: zoom.value,
          center: getLastCoord
        }
        map.value = L.map('map', newmapopt);
        L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', tileLayerOptions)
          .addTo(map.value);

        // Aggiunta dei controlli di zoom
        const zoomControl = L.control.zoom({
          position: "topright",
        }).addTo(map.value);

        // Aggiunta di un pulsante personalizzato
        // @ts-ignore
        const customButton = L.control({ position: "topright" });

        customButton.onAdd = function () {
          const button = L.DomUtil.create("button", "custom-zoom-button");
          button.innerHTML = t('grid.showlist'); // Testo del pulsante
          button.onclick = onCustomButtonClick; // Gestore evento click

          return button;
        };

        // customButton.addTo(map.value);

        map.value.on('moveend', () => {
          onMoveEnd()
        });

        map.value.on("zoomend", onZoomEvent);
        // @ts-ignore
        markers.value = L.markerClusterGroup();

        map.value.addLayer(markers.value);

        // Assicuriamoci che la mappa sia completamente caricata prima di procedere
        map.value.whenReady(() => {
          // console.log('Mappa inizializzata e pronta');
          updateMap();
          precZoomLevel.value = map.value.getZoom()
        });
      }
    }

    function createSingleMarkerByCoordinates(rec: any) {

      const markerHtml = `
      <div class="marker-wrapper">
        <img src="/images/marker-shadow.png" class="marker-shadow" alt="Shadow" />
        <img src="/images/icon.png" class="marker-icon" alt="" />

        <div class="marker-circle"></div>

        <div class="marker-mini-icon ${getIconName(rec)}"></div>
      </div>`;

      const markerIcon = L.divIcon({
        className: 'custom-marker', // Classe CSS personalizzata
        html: markerHtml,
        iconSize: [40, 40],
        iconAnchor: [22, 35],
        popupAnchor: [-6, -36],
        shadowUrl: '/images/marker-shadow.png',
        shadowSize: [60, 30],
        shadowAnchor: [22, 35]
      });

      // @ts-ignore
      const each_marker = new L.marker(
        [rec.coordinate_gps.coordinates[1], rec.coordinate_gps.coordinates[0]],
        {
          icon: markerIcon

        }
      )
        .bindPopup(() => {
          const container = L.DomUtil.create('div');
          const strHTML = `<span class="fake-link">${rec.descr}</span>`

          if (debug.value) {
            // strHTML += `<br> Lat: ${rec.coordinate_gps.coordinates[1]} <br> Lng: ${rec.coordinate_gps.coordinates[0]}`;
          }

          container.innerHTML = strHTML

          const fakeLink: any = container.querySelector('.fake-link');
          L.DomEvent.on(fakeLink, 'click', (e) => {
            L.DomEvent.stopPropagation(e);
            ApriScheda(rec._id);
            each_marker.closePopup();
          });

          return container;
        }, { closeButton: false }) // Rimuove il pulsante di chiusura dal popup

        .on('click', () => {
          if (!$q.screen.lt.sm) {
            markerClick(rec._id)
          }
        })
        .on('mouseover', () => {
          if (!$q.screen.lt.sm) {
            each_marker.openPopup()
          }
        })
        .on('mouseout', () => {
          if (!$q.screen.lt.sm) {
            each_marker.closePopup()
          }
        });

      // Salva l'ID del mio record, per poi poterlo trovare
      each_marker.mytable = props.mytable
      each_marker.idRec = rec._id

      // Aggiungi il marker all'array in memoria
      arrMarkers.value.push(each_marker)

      return each_marker

    }

    function updateMap() {
      if (!map.value || !markers.value) return;

      if (map.value) {
        // console.log('updateMap')

        markers.value.clearLayers()
        arrMarkers.value = []

        for (const rec of arrcord.value) {
          if (rec.coordinate_gps.coordinates) {

            const each_marker = createSingleMarkerByCoordinates(rec)

            markers.value.addLayer(each_marker);
          }
        }

        // Aggiungi il gruppo di marker cluster alla mappa
        map.value.addLayer(markers.value);

        // console.log('markerShowed', markerShowed.value)
        if (markerShowed.value) {
          markerShowed.value.closePopup()
          const trovatomarker = arrMarkers.value.find((marker: any) => markerShowed.value && (marker.idRec === markerShowed.value.idRec))
          if (!trovatomarker) {
            // non presente, quindi lo aggiunge
            markers.value.addLayer(markerShowed.value);
          } else {
            markerShowed.value = trovatomarker
          }
          markerShowed.value.openPopup(); // Mostra il popup
        }

        if (visiblePosition.value && currentMarkerPositionGPS.value) {
          // Aggiungi un marker per la posizione attuale, se desiderato
          /*const tempmark = L.marker(
            [currentMarkerPositionGPS.value.getLatLng().lat, currentMarkerPositionGPS.value.getLatLng().lng],
            { icon: currentLocationIcon }
          ).addTo(map.value)
            .bindPopup('Posizione attuale')
            // .openPopup();

          currentMarkerPositionGPS.value = tempmark*/
          markers.value.addLayer(currentMarkerPositionGPS.value);
        }

        updateBoundaries(false)
      }
    }

    function markerClick(id: any) {
      emit('clickMarker', id)
      // emit('clickMarker', id)
    }
    function ApriScheda(id: any) {
      emit('clickMarker', id)
    }

    function gotoCurrentLocation() {
      getCurrentPosition();
    }

    function flyToCoord(lat: number, lng: number, callback: () => void) {
      try {
        map.value.off('moveend', callback)

        if (map.value.getZoom() < 13) {
          zoom.value = 13;
        } else {
          zoom.value = map.value.getZoom()
        }
        // Centra la mappa sulla posizione attuale
        map.value.flyTo([lat, lng], zoom.value, {
          animate: true,
          duration: 0.7
        })
        // Usa l'evento 'moveend' per sapere quando l'animazione è completata
        map.value.on('moveend', callback);

      } catch (error) {

      }

    }

    const getCurrentPosition = () => {
      if (navigator.geolocation) {
        isTrackingLocation.value = true; // Setta lo stato a "in tracciamento"

        navigator.geolocation.getCurrentPosition(
          position => {
            const lat = position.coords.latitude
            const lng = position.coords.longitude

            flyToCoord(lat, lng, () => {
              if (currentMarkerPositionGPS.value) {
                map.value.removeLayer(currentMarkerPositionGPS.value)
              }

              // Aggiungi un marker per la posizione attuale, se desiderato
              currentMarkerPositionGPS.value = L.marker(
                [lat, lng],
                { icon: currentLocationIcon }
              ).addTo(map.value)
                .bindPopup('Posizione attuale')
              // .openPopup();

              isTrackingLocation.value = false; // Resetta lo stato di tracciamento


            })
          },
          error => {
            console.error('Errore nel recupero della posizione:', error);
            isTrackingLocation.value = false; // Resetta lo stato di tracciamento
          }
        );
      } else {
        console.error('Geolocalizzazione non supportata dal browser.');
      }
    }

    const removeCurrentMarker = () => {
      if (currentMarkerPositionGPS.value) {
        map.value.removeLayer(currentMarkerPositionGPS.value); // Rimuovi il marker dalla mappa
        currentMarkerPositionGPS.value = null; // Resetta il riferimento
      }
    }

    function findMarkerByIdRec(id: any) {
      const marker = arrMarkers.value.find((marker: any) => {
        return marker.idRec === id;
      });

      return marker;
    }

    function showInMap(rec: any) {
      // console.log('showInMap', rec)

      // Find if is already in the map
      let existingMarker = findMarkerByIdRec(rec._id)
      if (!existingMarker) {

        if (markerTemporaneo.value) {
          // Rimuovo il marker temporaneo usato in precedenza
          map.value.removeLayer(markerTemporaneo.value)
          markerTemporaneo.value = null
        }

        // Se non la trovo nella mappa, allora inserisco un nuovo marker temporaneo e lo aggiungo alla mappa
        existingMarker = createSingleMarkerByCoordinates(rec); // Crea un nuovo marker
        markers.value.addLayer(existingMarker);

        // console.log('***** Added marker TEMPORANEO', existingMarker)

        markerTemporaneo.value = existingMarker
      }

      if (existingMarker) {
        const lat = existingMarker.getLatLng().lat
        const lng = existingMarker.getLatLng().lng

        recordShowed.value = rec
        markerShowed.value = existingMarker

        // console.log('flyToCoord START ... ', lat, lng)

        // Passa una callback dopo il volo
        flyToCoord(lat, lng, () => {
          // console.log('flyToCoord END ... ', lat, lng)

          if (markerShowed.value) {
            //console.log('openPopup markerShowed', markerShowed.value)
            if (markerShowed.value.closePopup) {
              markerShowed.value.openPopup(); // Mostra il popup
            }
          }
        });
      }
    }



    return {
      mywidth,
      myheight,
      map,
      iconWidth,
      iconHeight,
      iconUrl,
      iconSize,
      changeIcon,
      zoom,
      log,
      getCoordinates,
      arrcord,
      getCurrentPosition,
      isTrackingLocation,
      visiblePosition,
      gotoCurrentLocation,
      showInMap,
    }
  }
})
