import L from 'leaflet';
import * as LeafletDraw from 'leaflet-draw';
console.log(LeafletDraw); // TODO: this has to be here for leaflet draw to initialize, is there another way?
const MIN_LAT = -90;
const MAX_LAT = 90;
const MIN_LNG = -180;
const MAX_LNG = 180;
export class Leaflet {
  constructor() {
    this.listeners = [];
    this.mapboxLayer = L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
      attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
      tileSize: 512,
      maxZoom: 18,
      zoomOffset: -1,
      id: 'mapbox/streets-v11',
      accessToken: 'pk.eyJ1Ijoiam9uY2FybHNvbm5hc2EiLCJhIjoiY2ptbTYyOWI5MGZwajNxbWxjdmYweTE5eiJ9.PgiaxHKrA5elPqzN7Ask6w',
    });
  }
  initializeMap(container, options) {
    if (this.map) {
      this.map.off();
      this.map.remove();
    }
    const southWest = L.latLng(-90, -360);
    const northEast = L.latLng(90, 360);
    const maxBounds = L.latLngBounds(southWest, northEast);
    this.map = L.map(container, {
      zoomControl: false,
      maxBounds,
      maxBoundsViscosity: 0.8,
    });
    this.setView(options);
    this.mapboxLayer.addTo(this.map);
  }
  setView(options) {
    this.map.setView([options.latitude, options.longitude], options.zoom, {
      minZoom: options.minZoom,
      maxZoom: options.maxZoom,
    });
  }
  setZoom(zoomLevel) {
    this.map.setZoom(zoomLevel);
  }
  addNavigationControl(position) {
    this.navigationControl = L.control.zoom({ position });
    this.navigationControl.addTo(this.map);
  }
  removeNavigationControl() {
    if (!this.navigationControl)
      return;
    this.navigationControl.remove();
    this.navigationControl = null;
  }
  addDrawControl(position = 'topleft') {
    this.drawnItems = new L.FeatureGroup();
    this.drawnItems.addTo(this.map);
    let options = {
      position,
      draw: {
        polyline: false,
        polygon: false,
        rectangle: {},
        circle: false,
        marker: false,
        circlemarker: false,
      },
      edit: {
        featureGroup: this.drawnItems,
      },
    };
    this.drawControl = new L.Control.Draw(options);
    this.drawControl.addTo(this.map);
    this.map.on(L.Draw.Event.CREATED, e => {
      this.drawnItems.clearLayers();
      this.drawnItems.addLayer(e.layer);
      this.trigger('draw', this.drawnItems.getLayers()[0]);
    });
    this.map.on(L.Draw.Event.EDITED, () => this.trigger('draw', this.drawnItems.getLayers()[0]));
    this.map.on(L.Draw.Event.DELETED, () => this.trigger('clear'));
  }
  removeDrawControl() {
    if (!this.drawControl)
      return;
    this.drawControl.remove();
    this.drawControl = null;
  }
  drawRectangle(bounds) {
    this.drawnItems.clearLayers();
    L.rectangle(bounds, {
      stroke: true,
      color: '#3388ff',
      weight: 4,
      opacity: 0.5,
      fill: true,
      fillColor: null,
      fillOpacity: 0.2,
    }).addTo(this.drawnItems);
  }
  refreshSize() {
    this.map.invalidateSize();
  }
  fitWorld() {
    this.map.fitBounds([
      [-180, -90],
      [180, 90],
    ]);
  }
  on(eventName, callback) {
    this.listeners.push({
      eventName,
      callback,
    });
  }
  trigger(eventName, detail = null) {
    this.listeners.filter(listener => listener.eventName === eventName).forEach(listener => listener.callback(detail));
  }
  normalizePoint({ lat, lng }) {
    return this.map.wrapLatLng({ lat, lng });
  }
  normalizeLat(lat) {
    if (lat > MAX_LAT)
      return MAX_LAT;
    else if (lat < MIN_LAT)
      return MIN_LAT;
    return lat;
  }
  normalizeLng(lng) {
    if (lng < MIN_LNG || lng > MAX_LNG) {
      let rem = lng % MAX_LNG;
      return (rem < 0 ? MAX_LNG : MIN_LNG) + rem;
    }
    return lng;
  }
  normalizeBox(box) {
    return [this.normalizeLng(parseFloat(box[0])), this.normalizeLat(parseFloat(box[1])), this.normalizeLng(parseFloat(box[2])), this.normalizeLat(parseFloat(box[3]))];
  }
}
