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

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

import { useUserStore } from '@src/store/UserStore'

// Importa le immagini dei marker
import icon from 'leaflet/dist/images/marker-icon.png'
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
import type { ICoordGPS, ICoordLatLng } from '@src/model'

export default defineComponent({
  name: 'CMapEditAddressByCoord',
  props: {
    modelValue: {
      type: Object as PropType<ICoordGPS>,
      required: true,
    },
    editaddress: {
      type: Boolean,
      required: true,
    },
    visuMappa: {
      type: Boolean,
      required: false,
      default: true,
    }
  },
  setup(props, { emit }) {
    const $q = useQuasar()
    const userStore = useUserStore()

    const mapContainer = ref(<any>null);

    const iconWidth = ref(25)
    const iconHeight = ref(41)
    const map = shallowRef<L.Map | null>(null)
    const marker = ref<L.Marker | null>(null)
    const suggestions = ref([]);
    const isMapDialogOpen = ref(false)
    const mostraMappa = ref(true)

    const localAddress = ref(props.modelValue.address);
    const localAddressObj = ref({ label: '', value: '' });
    const localCoordinates = ref(<ICoordLatLng>{ lat: props.modelValue.coordinates[1], lng: props.modelValue.coordinates[0] });

    const modificato = ref(false)

    const fineLoad = ref(false)

    const zoomLevel = ref(17)

    const updateAll = () => {
      if (localAddress.value)
        emit('update:modelValue',
          {
            address: localAddress.value,
            type: 'Point',
            coordinates: [localCoordinates.value.lng, localCoordinates.value.lat]
          } as ICoordGPS);
    };

    // Funzione per aggiornare il nome
    const updateAddress = () => {
      if (localAddress.value)
        updateAll()
    };

    // Funzione per aggiornare il cognome
    const updateCoordinates = () => {
      updateAll()
    };

    // Monitoraggio delle modifiche alle props
    watch(() => props.modelValue.address, (newValue) => {
      localAddress.value = newValue;
    });

    watch(() => props.modelValue.coordinates, (newValue) => {
      localCoordinates.value.lat = newValue[1];
      localCoordinates.value.lng = newValue[0];
    });


    watch(() => localCoordinates.value.lat, (newValue) => {
      if (fineLoad.value) {
        modificato.value = true
      }
      updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
      getAddressFromCoordinates(localCoordinates.value.lat, localCoordinates.value.lng);
    });
    watch(() => localCoordinates.value.lng, (newValue) => {
      if (fineLoad.value) {
        modificato.value = true
      }
      updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
      getAddressFromCoordinates(localCoordinates.value.lat, localCoordinates.value.lng);

    });

    const myheight = computed(() => {
      return $q.screen.height - 150
    })

    // Funzione per ottenere e stampare il livello di zoom
    function getZoomLevel() {
      zoomLevel.value = map.value ? map.value.getZoom() : 17;
      // console.log('Current zoom level:', zoomLevel);
    }

    const initMap = () => {
      // Configura l'icona di default
      const DefaultIcon = L.icon({
        iconUrl: icon,
        shadowUrl: iconShadow,
        iconSize: [iconWidth.value, iconHeight.value],
        iconAnchor: [iconWidth.value / 2, iconHeight.value],
        popupAnchor: [1, -iconHeight.value],
        shadowSize: [iconHeight.value, iconHeight.value]
      })
      L.Marker.prototype.options.icon = DefaultIcon

      zoomLevel.value = 17

      map.value = L.map(mapContainer.value,
        {
          zoomControl: true, zoom: zoomLevel.value, zoomAnimation: true,
          fadeAnimation: true, markerZoomAnimation: true,
          center: [42.71, 12.934],
        }
      )
      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map.value)


      getZoomLevel();

      // Ottenere il livello di zoom quando la mappa viene ridimensionata
      map.value.on('zoomend', getZoomLevel);

      /*
      const closeButton = L.control({ position: 'topright' });

      closeButton.onAdd = function () {
        const button = L.DomUtil.create('button', 'leaflet-control-button');
        button.innerHTML = 'Chiudi'; // Testo del pulsante
        button.style.backgroundColor = 'red';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.borderRadius = '5px';
        button.style.padding = '10px';
        button.style.cursor = 'pointer';

        button.onclick = () => {
          mostraMappa.value = false; // Chiudi il dialog della mappa
        };

        return button;
      };

      closeButton.addTo(map.value);

      */

    }

    const onResize = () => {
      if (map.value) {
        map.value.invalidateSize();
      }
    };

    const updateMarker = (lat: number, lng: number) => {
      // console.log('aggiorna marker', lat, lng)
      if (fineLoad.value) {
        modificato.value = true
      }
      if (marker.value) {
        marker.value.setLatLng([lat, lng])
      } else {
        marker.value = L.marker([lat, lng], { draggable: true }).addTo(map.value!)
        marker.value.on('dragend', (event: L.LeafletEvent) => {
          const position = (event.target as L.Marker).getLatLng()
          localCoordinates.value = {
            lat: parseFloat(position.lat.toFixed(6)),
            lng: parseFloat(position.lng.toFixed(6)),
          };
          if (fineLoad.value) {
            mostraMappa.value = true
          }
          getAddressFromCoordinates(localCoordinates.value.lat, localCoordinates.value.lng);
          // updateCoordinates()
        })
      }
      map.value?.setView([lat, lng], zoomLevel.value)
    }

    function updateMap() {

      map.value?.setView([localCoordinates.value.lat, localCoordinates.value.lng], zoomLevel.value)
    }

    const searchAddress = async () => {
      try {
        const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(localAddress.value)}`)
        const data = await response.json()
        if (data && data.length > 0) {
          localCoordinates.value = { lat: parseFloat(data[0].lat), lng: parseFloat(data[0].lon) }
          localAddress.value = data[0].display_name
          if (fineLoad.value) {
            mostraMappa.value = true
          }
          isMapDialogOpen.value = true
        }
      } catch (error) {
        console.error('Error searching address:', error)
      }
    }

    // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
    const getAddressSuggestions = async (val: string, update: Function) => {
      try {
        if (val.length === 0) {
          suggestions.value = [];
          update();
          return;
        }

        const response = await fetch(
          `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(val)}`
        );
        const data = await response.json();
        suggestions.value = data.map((item: any) => ({
          label: item.display_name,
          value: item.display_name,
          lat: item.lat,
          lon: item.lon
        }));

        update();
      } catch (error) {
        console.error('Error fetching address suggestions:', error);
      }
    };

    const getAddressFromCoordinates = async (lat: number, lon: number) => {
      const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json`;

      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('Errore nella richiesta di geocoding');
        }
        const data = await response.json();
        localAddress.value = data.display_name; // Ottieni l'indirizzo
        localAddressObj.value = { label: localAddress.value, value: localAddress.value }
      } catch (error) {
        console.error('Errore durante il geocoding:', error);
        localAddress.value = ''; // In caso di errore, resetta l'indirizzo
        localAddressObj.value = { label: '', value: '' }
      }
    };

    watch(localAddressObj, (newAddress: any) => {
      if (newAddress) {
        const match: any = suggestions.value.find((suggestion: any) => suggestion.value === newAddress.value);
        if (match && match.lat) {
          localAddress.value = match.value;
          localCoordinates.value = {
            lat: parseFloat(parseFloat(match.lat).toFixed(6)),
            lng: parseFloat(parseFloat(match.lon).toFixed(6)),
          };
          updateCoordinates()
          updateAddress()

          updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
        }
      }
    });

    function salvaCoordinate() {
      updateCoordinates()
      updateAddress()
      $q.notify({
        type: 'positive',
        message: 'Coordinate modificate, Salvare per rendere effettiva la modifica',
        position: 'bottom',
        timeout: 2000
      })
      modificato.value = false
      mostraMappa.value = false
    }

    onMounted(() => {

      if (!props.modelValue.address) {
        localAddress.value = ''
        localAddressObj.value = { label: '', value: '' }
      } else {
        localAddressObj.value = { label: props.modelValue.address, value: props.modelValue.address }
      }
      if (!props.modelValue.coordinates) {
        localCoordinates.value = { lat: 0, lng: 0 }
      }

      initMap()

      updateMap()
      updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);

      if (!localCoordinates.value || !localCoordinates.value.lat) {
        mostraMappa.value = false
      }
      fineLoad.value = true
      window.addEventListener('resize', onResize);

      nextTick(() => {
        mostraMappa.value = props.visuMappa
      })
    })

    onBeforeUnmount(() => {
      window.removeEventListener('resize', onResize);
    });

    const getCurrentLocation = () => {
      if ('geolocation' in navigator) {
        navigator.geolocation.getCurrentPosition(
          (position) => {
            localCoordinates.value = {
              lat: parseFloat(position.coords.latitude.toFixed(6)),
              lng: parseFloat(position.coords.longitude.toFixed(6)),
            };
            if (fineLoad.value) {
              mostraMappa.value = true;
            }
            updateCoordinates();
            updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
          },
          (error) => {
            console.error('Error getting location:', error);
            $q.notify({
              type: 'negative',
              message: 'Errore durante il rilevamento della posizione.',
            });
          }
        );
      } else {
        $q.notify({
          type: 'negative',
          message: 'Geolocalizzazione non supportata dal browser.',
        });
      }
    };

    function annullaSalvataggio() {
      localCoordinates.value.lng = props.modelValue.coordinates[0]
      localCoordinates.value.lat = props.modelValue.coordinates[1]
      localAddress.value = props.modelValue.address
      updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
      mostraMappa.value = false
      modificato.value = false
    }

    // evento dopo il mounting
    return {
      searchAddress,
      myheight,
      isMapDialogOpen,
      suggestions,
      getAddressSuggestions,
      localAddress,
      localCoordinates,
      updateAddress,
      updateCoordinates,
      mostraMappa,
      localAddressObj,
      getCurrentLocation,
      salvaCoordinate,
      modificato,
      annullaSalvataggio,
      mapContainer,
      fineLoad,
    }
  }
})
