import { PerspectiveCamera } from "three/src/cameras/PerspectiveCamera";
import { Vector3 } from "three/src/math/Vector3";
import { Matrix4 } from "three/src/math/Matrix4";
import {
  TypedCameraObjNode,
  CameraMainCameraParamConfig
} from "@polygonjs/polygonjs/dist/src/engine/nodes/obj/_BaseCamera";
import mapboxgl from "mapbox-gl";
import { MapboxViewer } from "../../viewers/Mapbox";
import { CoreMapboxClient } from "../../../core/mapbox/Client";
import { ParamConfig, NodeParamsConfig } from "@polygonjs/polygonjs/dist/src/engine/nodes/utils/params/ParamsConfig";
import { isBooleanTrue } from "@polygonjs/polygonjs/dist/src/core/Type";
const PRESETS = {
  LONDON: {
    style: "mapbox://styles/mapbox/dark-v10",
    lngLat: [-0.07956, 51.5146]
  },
  SAN_FRANCISCO: {
    style: "mapbox://styles/mapbox/dark-v10",
    lngLat: [-122.4726194, 37.7577627]
  },
  MOUNTAIN: {
    style: "mapbox://styles/mapbox-map-design/ckhqrf2tz0dt119ny6azh975y",
    lngLat: [-114.34411, 32.6141]
  }
};
const PRESET = PRESETS.LONDON;
class MapboxCameraObjParamConfig extends CameraMainCameraParamConfig(NodeParamsConfig) {
  constructor() {
    super(...arguments);
    this.style = ParamConfig.STRING(PRESET.style, {
      callback: (node) => {
        MapboxCameraObjNode.PARAM_CALLBACK_update_style(node);
      }
    });
    this.lngLat = ParamConfig.VECTOR2(PRESET.lngLat, {
      callback: (node) => {
        MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
      }
    });
    this.zoom = ParamConfig.FLOAT(15.55, {
      range: [0, 24],
      rangeLocked: [true, true],
      callback: (node) => {
        MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
      }
    });
    this.zoomRange = ParamConfig.VECTOR2([0, 24], {
      callback: (node) => {
        MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
      }
    });
    this.pitch = ParamConfig.FLOAT(60, {
      range: [0, 60],
      rangeLocked: [true, true],
      callback: (node) => {
        MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
      }
    });
    this.bearing = ParamConfig.FLOAT(60.373613, {
      range: [0, 360],
      callback: (node) => {
        MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
      }
    });
    this.updateParamsFromMap = ParamConfig.BUTTON(null, {
      label: "Set Navigation Params as Default",
      callback: (node, param) => {
        MapboxCameraObjNode.PARAM_CALLBACK_update_params_from_map(node);
      }
    });
    this.allowDragRotate = ParamConfig.BOOLEAN(1, {
      callback: (node) => {
        MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
      }
    });
    this.addZoomControl = ParamConfig.BOOLEAN(1, {
      callback: (node) => {
        MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
      }
    });
    this.tlayerBuildings = ParamConfig.BOOLEAN(0);
    this.tlayer3D = ParamConfig.BOOLEAN(0);
    this.tlayerSky = ParamConfig.BOOLEAN(0);
  }
}
const ParamsConfig = new MapboxCameraObjParamConfig();
export class MapboxCameraObjNode extends TypedCameraObjNode {
  constructor() {
    super(...arguments);
    this.paramsConfig = ParamsConfig;
    this._maps_by_container_id = /* @__PURE__ */ new Map();
    this._map_containers_by_container_id = /* @__PURE__ */ new Map();
    this._canvases_by_container_id = /* @__PURE__ */ new Map();
    this._controls_by_container_id = /* @__PURE__ */ new Map();
    this._moving_maps = false;
    this._inverse_proj_mat = new Matrix4();
    this._cam_pos = new Vector3();
    this._mouse_pos = new Vector3();
    this._view_dir = new Vector3();
  }
  static type() {
    return "mapboxCamera";
  }
  integration_data() {
    return CoreMapboxClient.integration_data();
  }
  createObject() {
    return new PerspectiveCamera();
  }
  async cook() {
    this.updateMaps();
    this.cookController.endCook();
  }
  prepareRaycaster(mouse, raycaster) {
    this._inverse_proj_mat.copy(this._object.projectionMatrix);
    this._inverse_proj_mat.invert();
    this._cam_pos.set(0, 0, 0);
    this._cam_pos.applyMatrix4(this._inverse_proj_mat);
    this._mouse_pos.set(mouse.x, mouse.y, 1);
    this._mouse_pos.applyMatrix4(this._inverse_proj_mat);
    this._view_dir.copy(this._mouse_pos).sub(this._cam_pos).normalize();
    raycaster.set(this._cam_pos, this._view_dir);
  }
  createMap(container) {
    const map = new mapboxgl.Map({
      style: this.pv.style,
      container,
      center: this.pv.lngLat.toArray(),
      zoom: this.pv.zoom,
      minZoom: this.pv.zoomRange.x,
      maxZoom: this.pv.zoomRange.y,
      pitch: this.pv.pitch,
      bearing: this.pv.bearing,
      dragRotate: this.pv.allowDragRotate,
      pitchWithRotate: this.pv.allowDragRotate,
      antialias: true
    });
    this._addRemoveControls(map, container.id);
    this._maps_by_container_id.set(container.id, map);
    this._map_containers_by_container_id.set(container.id, container);
    this._canvases_by_container_id.set(container.id, container.querySelector("canvas"));
    return map;
  }
  updateMaps() {
    this._maps_by_container_id.forEach((map, container_id) => {
      this.updateMapFromContainerId(container_id);
    });
  }
  updateMapFromContainerId(container_id) {
    const map = this._maps_by_container_id.get(container_id);
    if (!map) {
      return;
    }
    this.updateMapNav(map);
    this._addRemoveControls(map, container_id);
    map.setStyle(this.pv.style);
  }
  updateMapNav(map) {
    map.jumpTo(this.cameraOptionsFromParams());
    map.setMinZoom(this.pv.zoomRange.x);
    map.setMaxZoom(this.pv.zoomRange.y);
    const drag_rotate_handler = map.dragRotate;
    if (isBooleanTrue(this.pv.allowDragRotate)) {
      drag_rotate_handler.enable();
    } else {
      drag_rotate_handler.disable();
    }
  }
  firstMap() {
    let first_map;
    this._maps_by_container_id.forEach((map, id) => {
      if (!first_map) {
        first_map = map;
      }
    });
    return first_map;
  }
  firstId() {
    let first_id;
    this._maps_by_container_id.forEach((map, id) => {
      if (!first_id) {
        first_id = id;
      }
    });
    return first_id;
  }
  firstMapElement() {
    const id = this.firstId();
    if (id) {
      return this._map_containers_by_container_id.get(id);
    }
  }
  bounds() {
    const map = this.firstMap();
    if (map) {
      return map.getBounds();
    }
  }
  zoom() {
    const map = this.firstMap();
    if (map) {
      return map.getZoom();
    }
  }
  center() {
    const map = this.firstMap();
    if (map) {
      return map.getCenter();
    }
  }
  horizontal_lng_lat_points() {
    const id = this.firstId();
    if (id) {
      const map = this._maps_by_container_id.get(id);
      const element = this._canvases_by_container_id.get(id);
      if (map && element) {
        const y = element.clientHeight / 2;
        return [map.unproject([0, y]), map.unproject([100, y])];
      }
    }
  }
  centerLngLatPoint() {
    const id = this.firstId();
    if (id) {
      const map = this._maps_by_container_id.get(id);
      const element = this._canvases_by_container_id.get(id);
      if (map && element) {
        const x = element.clientWidth * 0.5;
        const y = element.clientHeight * 0.5;
        return map.unproject([x, y]);
      }
    }
  }
  verticalFarLngLatPoints() {
    const id = this.firstId();
    if (id) {
      const map = this._maps_by_container_id.get(id);
      const element = this._canvases_by_container_id.get(id);
      if (map && element) {
        const x = element.clientWidth;
        const y = 0;
        return [map.unproject([0, y]), map.unproject([x, y])];
      }
    }
  }
  verticalNearLngLatPoints() {
    const id = this.firstId();
    if (id) {
      const map = this._maps_by_container_id.get(id);
      const element = this._canvases_by_container_id.get(id);
      if (map && element) {
        const x = element.clientWidth;
        const y = element.clientHeight;
        return [map.unproject([0, y]), map.unproject([x, y])];
      }
    }
  }
  removeMap(container) {
    if (container) {
      const map = this._maps_by_container_id.get(container.id);
      if (map) {
        map.remove();
        this._maps_by_container_id.delete(container.id);
        this._map_containers_by_container_id.delete(container.id);
        this._canvases_by_container_id.delete(container.id);
        this._controls_by_container_id.delete(container.id);
      }
    }
  }
  onMoveEnd(container) {
    if (this._moving_maps === true) {
      return;
    }
    this._moving_maps = true;
    if (container != null) {
      const triggering_map = this._maps_by_container_id.get(container.id);
      if (triggering_map != null) {
        const camera_options = this.cameraOptionsFromMap(triggering_map);
        this._maps_by_container_id.forEach((map, container_id) => {
          if (container_id !== container.id) {
            const map2 = this._maps_by_container_id.get(container_id);
            map2 == null ? void 0 : map2.jumpTo(camera_options);
          }
        });
      }
    }
    this.object.dispatchEvent({ type: "moveend" });
    this._moving_maps = false;
  }
  lngLat() {
    const val = this.pv.lngLat;
    return {
      lng: val.x,
      lat: val.y
    };
  }
  cameraOptionsFromParams() {
    return {
      center: this.lngLat(),
      pitch: this.pv.pitch,
      bearing: this.pv.bearing,
      zoom: this.pv.zoom
    };
  }
  cameraOptionsFromMap(map) {
    return {
      center: map.getCenter(),
      pitch: map.getPitch(),
      bearing: map.getBearing(),
      zoom: map.getZoom()
    };
  }
  _addRemoveControls(map, container_id) {
    let nav_control = this._controls_by_container_id.get(container_id);
    if (nav_control) {
      if (!isBooleanTrue(this.pv.addZoomControl)) {
        map.removeControl(nav_control);
        this._controls_by_container_id.delete(container_id);
      }
    } else {
      if (isBooleanTrue(this.pv.addZoomControl)) {
        nav_control = new mapboxgl.NavigationControl();
        map.addControl(nav_control, "bottom-right");
        this._controls_by_container_id.set(container_id, nav_control);
      }
    }
  }
  updateParamsFromMap() {
    const map = this.firstMap();
    if (map) {
      const center = map.getCenter();
      const zoom = map.getZoom();
      const pitch = map.getPitch();
      const bearing = map.getBearing();
      this.p.lngLat.set([center.lng, center.lat]);
      this.p.zoom.set(zoom);
      this.p.pitch.set(pitch);
      this.p.bearing.set(bearing);
    }
  }
  static PARAM_CALLBACK_update_params_from_map(node) {
    node.updateParamsFromMap();
  }
  static PARAM_CALLBACK_update_style(node) {
    node.updateStyle();
  }
  static PARAM_CALLBACK_update_nav(node) {
    node.updateNav();
  }
  updateStyle() {
    this._maps_by_container_id.forEach((map, container_id) => {
      map.setStyle(this.pv.style);
    });
  }
  updateNav() {
    this._maps_by_container_id.forEach((map) => {
      this.updateMapNav(map);
    });
  }
  createViewer(options) {
    const viewer = new MapboxViewer(this);
    let element;
    if (options && options instanceof HTMLElement) {
      element = options;
    } else {
      element = options == null ? void 0 : options.element;
    }
    if (element) {
      viewer.mount(element);
    }
    this.scene().viewersRegister.registerViewer(viewer);
    return viewer;
  }
}
