import {Map, NavigationControl, Marker, Popup} from 'maplibre-gl';
import { Map as Map$1, TileLayer, Marker as Marker$1, polygon } from 'leaflet';
import * as i0 from '@angular/core';
import { inject, PLATFORM_ID, output, Directive, Injector, input, runInInjectionContext, effect, ViewChild, Component } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import {LatLng} from "leaflet/src/geo/index.js";

function getLngLat(latLng) {
  return [latLng[1], latLng[0]];
}

class LibreAdapter {
  map;
  deliveryCheckMarker;
  popup;
  markers = {};
  init(container, options) {
    this.map = new Map({
      container,
      style: options.styleUrl,
      center: getLngLat(options.center),
      zoom: options.zoom,
    });
    this.map.addControl(new NavigationControl(), 'top-right');
  }
  setCenter(latLng) {
    this.map.setCenter(getLngLat(latLng));
  }
  setZoom(zoom) {
    this.map.setZoom(zoom);
  }
  addMarker(latLng, options) {
    const coords = getLngLat(latLng);
    
    if (options.id) {
      if (this.markers[options.id]) {
        this.markers[options.id].remove();
      }
      
      const marker = new Marker({ color: options.color || 'red' })
        .setLngLat(coords)
        .addTo(this.map);
      this.markers[options.id] = marker;
    } else {
      if (this.deliveryCheckMarker) {
        this.deliveryCheckMarker.remove();
      }
      this.deliveryCheckMarker = new Marker({ color: options?.color || 'red' })
        .setLngLat(coords)
        .addTo(this.map);
    }
  }
  removeMarker(id) {
    if (id) {
      if (this.markers[id]) {
        this.markers[id].remove();
        delete this.markers[id];
      }
    }
    else
    {
      if (this.deliveryCheckMarker)
      {
        this.deliveryCheckMarker.remove();
        this.deliveryCheckMarker = undefined;
      }
    }
  }
  destroy() {
    this.map.remove();
  }
  addZone(zones) {
    this.updateZone(zones);
  }
  updateZone(zones) {
    const features = zones.map((zone) => {
      const coords = zone.polygon.map((pt) => [pt.y, pt.x]);
      
      if (coords[0][0] !== coords[coords.length - 1][0] || coords[0][1] !== coords[coords.length - 1][1]) {
        coords.push(coords[0]);
      }
      
      return {
        type: 'Feature',
        properties: {
          id: zone.id,
          name: zone.name,
          color: zone.color ? zone.color : '#ff0000',
          opacity: zone.opacity ? zone.opacity : 0.4,
        },
        geometry: {
          type: 'Polygon',
          coordinates: [coords]
        },
      };
    });
    
    const geojson = {
      type: 'FeatureCollection',
      features,
    };
    
    if (this.map.getSource("zones")) {
      (this.map.getSource("zones").setData(geojson));
    }
    else {
      this.map.addSource("zones", {
        type: "geojson",
        data: geojson,
      });
      
      this.map.addLayer({
        id: "zones-fill",
        type: "fill",
        source: "zones",
        paint: {
          "fill-color": ["get", "color"],
          "fill-opacity": ["get", "opacity"],
        },
      });
      
      this.map.addLayer({
        id: "zones-outline",
        type: "line",
        source: "zones",
        paint: {
          "line-color": ["get", "color"],
          "line-width": 2,
        },
      });
    }
  }
  openZonePopup(zone)
  {
    let sumLng = 0;
    let sumLat = 0;
    zone.polygon.forEach(point => {
      sumLng += point.y;
      sumLat += point.x;
    });
    const centerLng = sumLng / zone.polygon.length;
    const centerLat = sumLat / zone.polygon.length;

    this.closePopup();
    this.popup = new Popup({
      closeButton: true,
      closeOnClick: false,
    })
      .setLngLat([centerLng, centerLat])
      .setHTML(`
        <div class="delivery-zone">
          ${zone.name ? `<p><strong>${zone.name}</strong></p>` : ''}
          ${zone.shippingFee ? `<p>Shipping: ${zone.shippingFee}$</p>` : ''}
          ${zone.deliverySchedule ? `<p>Delivery: ${zone.deliverySchedule}</p>` : ''}
        </div>`)
      .addTo(this.map);
  }
  closePopup()
  {
    if (this.popup) {
      this.popup.remove();
      this.popup = undefined;
    }
  }
  on(type, event,){
    this.map.on(type, event);
  }
}

class LeafletAdapter {
  map;
  deliveryCheckMarker;
  markers = {};
  popup;
  init(container, options) {
    this.map = new Map$1(container).setView(options.center, options.zoom);
    new TileLayer(options.tileUrl, {
      attribution: '&copy; OpenStreetMap contributors',
    }).addTo(this.map);
  }
  setCenter(latLng) {
    this.map.setView(latLng, this.map.getZoom());
    TileLayer.map
  }
  setZoom(zoom) {
    this.map.setZoom(zoom);
  }
  addMarker(latLng, options) {
    if (options.id) {
      if (this.markers[options.id]) {
        this.map.removeLayer(this.markers[options.id]);
      }
      const marker = new Marker$1(latLng)
        marker.addTo(this.map);
      this.markers[options.id] = marker;
    } else {
      if (this.deliveryCheckMarker) {
        this.map.removeLayer(this.deliveryCheckMarker);
      }
      this.deliveryCheckMarker = new Marker$1(latLng).addTo(this.map);
    }
  }
  
  removeMarker(id) {
    if (id) {
      if (this.markers[id]) {
        this.map.removeLayer(this.markers[id]);
        delete this.markers[id];
      }
    } else {
      if (this.deliveryCheckMarker) {
        this.map.removeLayer(this.deliveryCheckMarker);
        this.deliveryCheckMarker = undefined;
      }
    }
  }
  destroy() {
    this.map.remove();
  }
  addZone(zones) {
    this.updateZone(zones);
  }
  updateZone(zones) {
    for(let zone of zones)
    {
      const latlngs = zone.polygon.map((geoPoint) => {
        return new LatLng(geoPoint.x, geoPoint.y);
      });
      let color = "#ff0000"
      let opacity = 0.4;
      if(zone.color)
        color = zone.color;
      
      if (zone.opacity)
        opacity = zone.opacity;
      
      polygon(latlngs, { color, fillOpacity: opacity })
        .addTo(this.map);
    }
  }
  openZonePopup(zone)
  {
    let sumLat = 0;
    let sumLng = 0;
    zone.polygon.forEach(point => {
      sumLat += point.x;
      sumLng += point.y;
    });
    const centerLat = sumLat / zone.polygon.length;
    const centerLng = sumLng / zone.polygon.length;

    if (this.popup) {
      this.map.removeLayer(this.popup);
    }

    this.popup = new Marker$1([centerLat, centerLng], {
      opacity: 0
    })
      .addTo(this.map)
      .bindPopup(`
      <div >
        ${zone.name ? `<p><strong>${zone.name}</strong></p>` : ''}
        ${zone.shippingFee ? `<p>Shipping: ${zone.shippingFee}</p>` : ''}
        ${zone.deliverySchedule ? `<p>Delivery: ${zone.deliverySchedule}</p>` : ''}
      </div>`)
      .openPopup();
  }
  closePopup()
  {
    if (this.popup) {
      this.map.removeLayer(this.popup);
      this.popup = undefined;
    }
  }
  on(type, event) {
    this.map.on(type, event);
  }
}

class MapFacade {
  adapter;
  leafletZoomOffset = 1;
  constructor(forceRaster, webglAvailable) {
    if (forceRaster || !webglAvailable) {
      this.adapter = new LeafletAdapter();
    }
    else {
      this.adapter = new LibreAdapter();
    }
  }
  init(container, options) {
    if (this.adapter instanceof LeafletAdapter)
      options.zoom += this.leafletZoomOffset;
    this.adapter.init(container, options);
  }
  setCenter(latLng) {
    this.adapter.setCenter(latLng);
  }
  setZoom(zoom) {
    if (this.adapter instanceof LeafletAdapter)
      zoom += this.leafletZoomOffset;
    this.adapter.setZoom(zoom);
  }
  addMarker(latLng, options) {
    this.adapter.addMarker(latLng, options);
  }
  removeMarker() {
    this.adapter.removeMarker();
  }
  destroy() {
    this.adapter.destroy();
  }
  addZone(zones) {
    this.adapter.addZone(zones);
  }
  updateZone(zones) {
    this.adapter.updateZone(zones);
  }
  openZonePopup(zone) {
    this.adapter.openZonePopup(zone);
  }
  closePopup() {
    this.adapter.closePopup();
  }
  on(type, event,){
    this.adapter.on(type, event);
  }
}

class WebglDetectionDirective {
  platformId = inject(PLATFORM_ID);
  webglSupport = output();
  ngOnInit() {
    if (!isPlatformBrowser(this.platformId))
      return;
    const supported = this.checkWebGLSupport();
    this.webglSupport.emit(supported);
  }
  checkWebGLSupport() {
    let canvas = undefined;
    try {
      canvas = document.createElement('canvas');
      const gl = (canvas.getContext('webgl') ||
        canvas.getContext('experimental-webgl'));
      const supported = !!window.WebGLRenderingContext &&
        !!(gl);
      return supported;
    }
    catch {
      return false;
    }
    finally {
      canvas?.remove();
    }
  }
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: WebglDetectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: WebglDetectionDirective, isStandalone: true, selector: "[webglDetection]", outputs: { webglSupport: "webglSupport" }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: WebglDetectionDirective, decorators: [{
    type: Directive,
    args: [{
      selector: '[webglDetection]',
      standalone: true
    }]
  }] });

class OpenMapComponent {
  platformId = inject(PLATFORM_ID);
  injector = inject(Injector);
  webglSupported;
  map;
  mapContainer;
  options = input({
    center: [50.426606229502525, 30.56308375468811],
    zoom: 6,
    styleUrl: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
    tileUrl: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    forceRaster: false,
  });
  mapReady = output();
  ngAfterViewInit() {
    if (false === isPlatformBrowser(this.platformId))
      return;
    runInInjectionContext(this.injector, () => {
      effect(() => {
        if (undefined === this.webglSupported)
          return;
        if (!this.map)
          this.initializeMap();
      });
    });
  }
  webglDetection(supported) {
    this.webglSupported = supported;
    if (undefined === this.map)
      this.initializeMap();
  }
  initializeMap() {
    const options = this.options();
    this.map = new MapFacade(options.forceRaster, this.webglSupported);
    this.map.init(this.mapContainer.nativeElement, options);
    this.mapReady.emit(this.map);
  }
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: OpenMapComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.14", type: OpenMapComponent, isStandalone: true, selector: "open-map", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { mapReady: "mapReady" }, viewQueries: [{ propertyName: "mapContainer", first: true, predicate: ["mapContainer"], descendants: true, static: true }], ngImport: i0, template: "<div #mapContainer class=\"map-container\" webglDetection (webglSupport)=\"webglDetection($event)\">\n\n</div>\n", styles: [".map-container{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: WebglDetectionDirective, selector: "[webglDetection]", outputs: ["webglSupport"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: OpenMapComponent, decorators: [{
    type: Component,
    args: [{ selector: 'open-map', imports: [
        WebglDetectionDirective
      ], standalone: true, template: "<div #mapContainer class=\"map-container\" webglDetection (webglSupport)=\"webglDetection($event)\">\n\n</div>\n", styles: [".map-container{width:100%;height:100%}\n"] }]
  }], propDecorators: { mapContainer: [{
      type: ViewChild,
      args: ['mapContainer', { static: true }]
    }] } });

/*
 * Public API Surface of ngx-open-open-map-wrapper
 */
// Interfaces & types

/**
 * Generated bundle index. Do not edit.
 */

export { MapFacade, OpenMapComponent, WebglDetectionDirective, getLngLat };
//# sourceMappingURL=svrnty-ngx-open-map-wrapper.mjs.map
