<template>
  <LayoutContainer>
    <v-responsive :aspect-ratio="1" width="100%">
      <!-- /!\ We do not use the nuxt-leaflet library here,
      because in its current version it's way too slow to deal with hundreds of markers     -->
      <div id="map" />
    </v-responsive>

    <div class="advice">
      {{ $t("click_on_land_to_go_there") }}
    </div>

    <v-row class="map-shortcuts">
      <v-col v-for="shortcut in shortcuts" :key="shortcut.src" cols="2">
        <div @click="setMapBounds(shortcut.bounds)">
          <nuxt-img
            :src="shortcut.src"
            :alt="shortcut.alt"
          />
        </div>
      </v-col>
    </v-row>
  </LayoutContainer>
</template>

<script lang="ts">
import 'leaflet/dist/leaflet.css'
import Vue from 'vue'

let L: any
if (process.client) { // only require leaflet on client-side
  L = require('leaflet')
}

declare module 'vue/types/vue' {
  interface Vue {
    structures: Array<Structure>,
    zoomRequired: boolean,
    map: any,
    defaultBounds: L.LatLngBounds,
    shortcuts: Array<{src: string, alt: string, bounds: number[][] }>
  }
}

export default Vue.extend({
  props: {
    structures: {
      type: Array as () => Array<Structure>,
      required: false,
      default: () => []
    }
  },
  data () {
    return {
      map: null,
      defaultBounds: new L.LatLngBounds([51.03, -5.78], [41.2, 9.70]),
      shortcuts: [
        { src: '/images/metropole.png', alt: 'Metropole', bounds: [[51.03, -5.78], [41.2, 9.70]] },
        { src: '/images/guadeloupe.png', alt: 'Guadeloupe', bounds: [[16.62, -62.03], [15.74, -60.97]] },
        { src: '/images/martinique.png', alt: 'Martinique', bounds: [[14.95, -61.43], [14.28, -60.60]] },
        { src: '/images/mayotte.png', alt: 'Mayotte', bounds: [[-12.51, 44.86], [-13.19, 45.45]] },
        { src: '/images/la_reunion.png', alt: 'La Réunion', bounds: [[-20.65, 54.92], [-21.65, 56.15]] },
        { src: '/images/guyane.png', alt: 'Guyane', bounds: [[6.24, -54.62], [1.87, -50.59]] }
      ],
      zoomRequired: false
    }
  },
  watch: {
    structures (oldVal: Array<Structure>, newVal: Array<Structure>): void {
      if (oldVal !== newVal) {
        this.populateMarkers()
      }

      if (this.zoomRequired) {
        this._fitBoundsToMarkers()
        this.zoomRequired = false
      }
    }
  },
  mounted () {
    const defaultCenter: L.LatLngTuple = [46.71, 1.94]
    const defaultZoom: number = 5.75
    const layerSource: string = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png'
    const attribution: string = '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'

    const options: L.MapOptions = { scrollWheelZoom: false, zoomSnap: 0.25 }

    this.map = L.map('map', options)
    this.map.setView(defaultCenter, defaultZoom)
    L.tileLayer(layerSource, { attribution }).addTo(this.map)

    this.populateMarkers()

    this.map.on('zoomend moveend', () => {
      this.$emit('boundsUpdated', this.map.getBounds())
    })
  },
  beforeDestroy (): void {
    if (this.map) {
      this.map.remove()
    }
  },
  methods: {
    populateMarkers (): void {
      // remove any existant marker layers
      this.map.eachLayer((layer: L.Layer) => {
        if (layer instanceof L.MarkerClusterGroup) {
          this.map.removeLayer(layer)
        }
      })

      // populate new layer
      const clusters = L.markerClusterGroup()
      for (const s of this.structures) {
        if (!s.latitude || !s.longitude) { continue }

        const marker = L.marker([s.latitude, s.longitude])
        marker.bindPopup(`<b>${s.name}</b><br/>${s.postalCode} ${s.addressCity}<br/><a href="${s.website}" target="_blank">${s.website}</a>`)
        clusters.addLayer(marker)
      }
      this.map.addLayer(clusters)
    },
    setMapBounds (bounds: L.LatLngBoundsExpression): void {
      this.map.fitBounds(bounds) // << without this, the new bounds may not be properly set when the current view overlaps the new bounds.
    },
    resetBounds (): void {
      this.setMapBounds(this.defaultBounds)
    },
    zoomOnResults (): void {
      this.zoomRequired = true
    },
    _fitBoundsToMarkers (): void {
      const coords: L.LatLngBoundsLiteral = this.structures.filter(
        (s: Structure) => {
          return (
            s.latitude && typeof s.latitude !== 'undefined' &&
            s.longitude && typeof s.latitude !== 'undefined'
          )
        }
      ).map(
        (s: Structure) => { return [s.latitude as number, s.longitude as number] as L.LatLngTuple }
      )

      if (!coords) {
        return
      }
      this.setMapBounds(coords)
    }
  }
})
</script>

<style scoped>
  #map {
    height: 100%;
    width: 100%;
  }
  .advice {
    margin: 1rem 0;
    color: #262626;
    font-weight: 750;
    text-align: center;
    font-size: 0.9rem;
    width: 100%;
  }
  .map-shortcuts {
    padding: 12px 6px;
  }
  .map-shortcuts img {
      border: solid 1px #000;
      width: 75px;
      height: 75px;
    }
</style>
