import { jsx } from 'react/jsx-runtime';
import React__default from 'react';
import { c as PropTypes, g as cx } from './vendors-91f80587.js';
import { m as mapboxgl } from './mapbox-gl-1ecda267.js';
import { f as lodashExports } from './lodash-a8cb2811.js';
import { globalConfig } from '@meniga/config';
import { g as getValidProps } from './index-416f1548.js';
import 'react-dom';
import '@meniga/utils';
import './svgs-a-4334a1e7.js';
import './svgs-b-f64291bb.js';
import './svgs-c-298b50d9.js';
import './svgs-d-2f489f4c.js';
import './svgs-e-181b3ec7.js';
import './svgs-f-36f4fc0c.js';
import './svgs-g-64a390e3.js';
import './svgs-h-6831c257.js';
import './svgs-i-30e19c3f.js';
import './svgs-j-039dc4c9.js';
import './svgs-l-f659229f.js';
import './svgs-m-22cdb183.js';
import './svgs-n-baa4c9d3.js';
import './svgs-o-4ac46c1d.js';
import './svgs-p-9b35973a.js';
import './svgs-q-8e27852e.js';
import './svgs-r-b2a74719.js';
import './svgs-s-0992564c.js';
import './svgs-t-17002f0e.js';
import './svgs-u-5b43cb3f.js';
import './svgs-v-17213055.js';
import './svgs-w-ee65b972.js';
import './svgs-y-6dbea3b1.js';
import './react-dom-b14b840d.js';
import '@meniga/redux';
import './gemoji-7224d030.js';
import '@meniga/dates';
import '@meniga/router';
import './markdown-it-950f0330.js';

const Maps = '';

const _mapConfig = globalConfig("mapbox", { accessToken: "", mapStyle: "mapbox://styles/mapbox/streets-v9", marker: null });
class MapLazy extends React__default.Component {
  static propTypes = {
    /**
     * List of address objects:
     * Note:
     * - 'title' and 'displayAddress' are used in a tooltip bubble when you hover over a marker
     * - 'latitude' and 'longitude' are used by default to locate a marker, however if they are not available, 'lookupAddress' can be used to do a
     * geolocation search for the latitude and longitude values.
     * - 'lookupAddress' should include as much info as possible to find the geolocation, format should be: Street, PostalCode City, Country.
     * - 'marker' can be null, but if it's used, it will override the default marker. marker can only be
     */
    addresses: PropTypes.arrayOf(PropTypes.shape({
      id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
      title: PropTypes.string.isRequired,
      displayAddress: PropTypes.string,
      lookupAddress: PropTypes.string,
      latitude: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
      longitude: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
    })),
    /**
     * Whether or not to allow the user to zoom in and out
     */
    allowZoom: PropTypes.bool,
    /**
     * Whether or not to allow the user to zoom in and out on scroll
     */
    allowScrollZoom: PropTypes.bool,
    /**
     * Your mapbox access token
     */
    accessToken: PropTypes.string,
    /**
     * Used for offsetting the center of the map. Can be pixels (number), percentages (string) or function
     * by pixels
     */
    offset: PropTypes.shape({
      top: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),
      left: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func])
    }),
    /**
     * Used for offsetting the center of the map. Can be pixels (number), percentages (string) or function
     * by pixels
     */
    center: PropTypes.shape({
      latitude: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
      longitude: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
      zoom: PropTypes.number,
      speed: PropTypes.number
    }),
    /**
     * Zoom level
     */
    zoomLevel: PropTypes.number,
    /**
     * Whether or not to fit/zoom so all markers are visible
     */
    fitAllMarkersOnMap: PropTypes.bool,
    /**
     * Show or hide markers, default true
     */
    showMarkers: PropTypes.bool,
    /**
     * Triggered when user clicks on a marker, passes the geoJson object for that marker
     */
    onMarkerClick: PropTypes.func,
    /**
     * Style URL with the map style (e.g. mapbox://styles/mapbox/dark-v9), more info here: https://www.mapbox.com/help/define-style/
     */
    mapStyle: PropTypes.string,
    /**
     * Options for enabling clustering of addresses
     */
    cluster: PropTypes.shape({
      radius: PropTypes.number,
      clusterMaxZoom: PropTypes.number,
      fillColor: PropTypes.string,
      // Default #6BC1D3
      textColor: PropTypes.string,
      // Default #ffffff
      size: PropTypes.number,
      // Size of icon
      textSize: PropTypes.number
      // Size of cluster counter
    }),
    /**
     * Show zoom and pan controls on map
     */
    showNavigation: PropTypes.bool,
    /**
     * Postion of navigation controls
     */
    navigationPosition: PropTypes.oneOf(["top-right", "top-left", "bottom-right", "bottom-left"]),
    /**
     * Mapbox Map options - https://www.mapbox.com/mapbox-gl-js/api/#Map
     */
    options: PropTypes.object,
    /**
     * Function to set custom html for marker popups, passes the geoJson object for the marker
     */
    popupHtml: PropTypes.func,
    /**
     * Function that is called when map has been initialized, mainly for custom functionality like custom layers
     * Get passed the map object and geoJson for all the addresses.
     */
    onMapCreated: PropTypes.func,
    /**
     * Function that is called when map data has been updated, mainly for custom functionality like custom layers
     * Get passed the map object and geoJson for all the addresses.
     */
    onMapUpdated: PropTypes.func
  };
  static defaultProps = {
    addresses: null,
    allowZoom: true,
    allowScrollZoom: false,
    accessToken: _mapConfig.accessToken,
    offset: null,
    zoomLevel: 16,
    showMarkers: true,
    mapStyle: _mapConfig.mapStyle,
    showNavigation: true,
    navigationPosition: "top-right"
  };
  state = {
    loaded: false
  };
  componentDidMount = () => {
    this._initializeMap();
  };
  componentDidUpdate = (prevProps) => {
    if (!lodashExports.isEqual(this.props.addresses, prevProps.addresses)) {
      const geoJson = this._createGeoJson(this.props.addresses);
      if (this.props.showMarkers)
        this.runAfterLoading(() => this._updateMarkers(geoJson));
      if (this.props.onMapUpdated)
        this.props.onMapUpdated(this.map, geoJson);
    }
    const center = prevProps.center || {};
    const nextCenter = this.props.center || {};
    if ((!lodashExports.isEqual(center.longitude, nextCenter.longitude) || !lodashExports.isEqual(center.latitude, nextCenter.latitude)) && !!nextCenter.longitude && !!nextCenter.latitude) {
      const flyTo = { ...nextCenter, center: [nextCenter.longitude, nextCenter.latitude], offset: this._calculateOffset(this.props.offset) };
      this.map.flyTo(flyTo);
    }
  };
  componentWillUnmount = () => {
    const map = this.map;
    if (map) {
      map.off();
      setTimeout(() => {
        map.remove();
      });
    }
    this.stopTaskRunner();
  };
  _initializeMap = () => {
    const { addresses, allowZoom, accessToken, mapStyle, allowScrollZoom, center, zoomLevel, options } = this.props;
    if (Boolean(this.map)) {
      this.map.remove();
    }
    mapboxgl.accessToken = accessToken;
    const firstAddress = addresses && addresses[0];
    this.map = new mapboxgl.Map({
      container: this.container,
      style: mapStyle,
      center: Boolean(center) ? [center.longitude, center.latitude] : Boolean(firstAddress) ? [firstAddress.longitude, firstAddress.latitude] : [0, 0],
      zoom: zoomLevel,
      scrollZoom: allowScrollZoom,
      doubleClickZoom: allowZoom,
      ...options
    });
    const geoJson = this._createGeoJson(this.props.addresses);
    this._initializeControls();
    this.map.once("load", () => this._handleMapCreated(geoJson));
  };
  _handleMapCreated = (geoJson) => {
    this._positionMap(geoJson);
    this._addMarkers();
    if (this.props.showMarkers)
      this._updateMarkers(geoJson);
    if (this.props.onMapCreated)
      this.props.onMapCreated(this.map, geoJson);
    this.setState({
      loaded: true
    });
  };
  _initializeControls = () => {
    const { showNavigation, allowZoom, navigationPosition } = this.props;
    if (showNavigation && allowZoom) {
      this.map.addControl(new mapboxgl.NavigationControl(), navigationPosition);
    }
  };
  _createGeoJson = (addresses) => {
    const geoJson = {
      "type": "FeatureCollection",
      "features": []
    };
    if (addresses && addresses.length > 0) {
      lodashExports.forEach(addresses, (address) => {
        geoJson.features.push({
          // this feature is in the GeoJSON format: see geojson.org
          // for the full specification
          type: "Feature",
          geometry: {
            type: "Point",
            coordinates: [address.longitude, address.latitude]
          },
          properties: {
            id: address.id,
            title: address.title,
            description: address.displayAddress || address.lookupAddress,
            icon: address.icon || "LocationPin"
          }
        });
      });
    }
    return geoJson;
  };
  addressesKey = "addresses";
  tasks = [];
  startTaskRunner = () => {
    clearInterval(this.timer);
    this.timer = setInterval(() => {
      if (this.state.loaded) {
        while (this.tasks.length > 0) {
          const task = this.tasks.shift();
          task();
        }
        clearInterval(this.timer);
      }
    }, 100);
  };
  stopTaskRunner = () => {
    clearInterval(this.timer);
  };
  runAfterLoading = (func) => {
    if (this.state.loaded) {
      func();
    } else {
      this.tasks.push(func);
      this.startTaskRunner();
    }
  };
  _updateMarkers = (geoJson) => {
    this.map.getSource(this.addressesKey).setData(geoJson);
  };
  _addMarkers = () => {
    const { cluster, marker } = this.props;
    const map = this.map;
    map.addSource(this.addressesKey, {
      type: "geojson",
      data: null,
      cluster: Boolean(cluster),
      clusterMaxZoom: Boolean(cluster) ? cluster.maxZoom : 0,
      clusterRadius: Boolean(cluster) ? cluster.radius : 0
    });
    map.addLayer({
      id: "unclustered-addresses",
      type: "symbol",
      source: this.addressesKey,
      filter: ["!has", "point_count"],
      layout: marker || {
        "icon-image": "{icon}",
        "icon-offset": [0, -20],
        "icon-size": 1
        //TODO: add this to props
      }
    });
    if (Boolean(cluster)) {
      map.addLayer({
        id: "clusters",
        type: "circle",
        source: this.addressesKey,
        paint: {
          "circle-color": cluster.fillColor || "#6BC1D3",
          "circle-radius": cluster.size || 20
        },
        filter: [">=", "point_count", 2]
      });
      map.addLayer({
        id: "cluster-count",
        type: "symbol",
        source: this.addressesKey,
        paint: {
          "text-color": cluster.textColor || "#ffffff"
        },
        layout: {
          "text-field": "{point_count}",
          "text-size": cluster.textSize || 16
        }
      });
    }
    map.on("click", this._handleMarkerClick);
    map.on("mousemove", (e) => {
      const features = map.queryRenderedFeatures(e.point, { layers: ["unclustered-addresses"] });
      map.getCanvas().style.cursor = features.length ? "pointer" : "";
    });
  };
  _handleMarkerClick = (e) => {
    const features = this.map.queryRenderedFeatures(e.point, { layers: ["unclustered-addresses"] });
    if (!features.length) {
      return;
    }
    const feature = features[0];
    if (this.props.onMarkerClick)
      this.props.onMarkerClick(feature);
    new mapboxgl.Popup({ closeButton: false, offset: 15 }).setLngLat(feature.geometry.coordinates).setHTML(this._getPopupHtml(feature)).addTo(this.map);
  };
  _getPopupHtml = (feature) => {
    if (this.props.popupHtml)
      return this.props.popupHtml(feature);
    return `<h1>${feature.properties.title}</h1><div>${feature.properties.description}</div>`;
  };
  _calculateOffset = (offset) => {
    const mapClientRect = this.container.getBoundingClientRect();
    if (lodashExports.isString(offset.left)) {
      offset.left = parseFloat(offset.left) / 100 * mapClientRect.width;
    } else if (lodashExports.isFunction(offset.left)) {
      offset.left = offset.left();
    }
    if (lodashExports.isString(offset.top)) {
      offset.left = parseFloat(offset.left) / 100 * mapClientRect.height;
    } else if (lodashExports.isFunction(offset.top)) {
      offset.top = offset.top();
    }
    return [offset.left * 2, offset.top * 2];
  };
  _positionMap = (geoJson) => {
    const { zoomLevel, fitAllMarkersOnMap } = this.props;
    const { offset } = this.props;
    const map = this.map;
    const maxZoom = !zoomLevel ? 16 : zoomLevel;
    let bounds = map.getBounds();
    const offsetOptions = {
      padding: 50,
      maxZoom
      //duration: 0 // TODO: take a look at inital loading and centering of map
    };
    if (offset && this.container) {
      offsetOptions.offset = this._calculateOffset(offset);
    }
    if (fitAllMarkersOnMap && geoJson.features.length >= 2) {
      bounds = new mapboxgl.LngLatBounds();
      geoJson.features.forEach((feature) => {
        bounds.extend(feature.geometry.coordinates);
      });
    }
    map.fitBounds(bounds, offsetOptions);
  };
  render() {
    const { className, style, children, ...rest } = this.props;
    const map = this.map;
    const classes = cx({
      name: "Maps"
    }, className);
    const cleanProps = getValidProps(rest);
    return /* @__PURE__ */ jsx("div", { className: classes(), style, ...cleanProps, children: /* @__PURE__ */ jsx(
      "div",
      {
        className: classes("box"),
        style: { width: "100%", height: "100%" },
        ref: (x) => {
          this.container = x;
        },
        children: Boolean(map) ? children : null
      }
    ) });
  }
}

export { MapLazy as default };
