import { CameraController } from "@polygonjs/polygonjs/dist/src/core/CameraController";
import { NodeContext } from "@polygonjs/polygonjs/dist/src/engine/poly/NodeContext";
import { MapboxCameraObjNode } from "../../../nodes/obj/MapboxCamera";
import { TypedSopNode } from "@polygonjs/polygonjs/dist/src/engine/nodes/sop/_Base";
import { NodeParamsConfig, ParamConfig } from "@polygonjs/polygonjs/dist/src/engine/nodes/utils/params/ParamsConfig";
export function MapboxListenerParamConfig(Base) {
  return class Mixin extends Base {
    constructor() {
      super(...arguments);
      this.useBounds = ParamConfig.BOOLEAN(0, { hidden: true });
      this.southWest = ParamConfig.VECTOR2([-0.11, 51.51], {
        visibleIf: { useBounds: 1 }
      });
      this.northEast = ParamConfig.VECTOR2([-0.1, 51.52], {
        visibleIf: { useBounds: 1 }
      });
      this.useZoom = ParamConfig.BOOLEAN(0, { hidden: true });
      this.zoom = ParamConfig.FLOAT(0, {
        visibleIf: { useZoom: 1 }
      });
      this.mapboxCamera = ParamConfig.NODE_PATH("", {
        nodeSelection: {
          context: NodeContext.OBJ,
          types: [MapboxCameraObjNode.type()]
        },
        callback: (node) => {
          MapboxListenerSopNode.PARAM_CALLBACK_update_mapbox_camera(node);
        }
      });
      this.zoomRange = ParamConfig.VECTOR2([0, 24]);
      this.updateAlwaysAllowed = ParamConfig.BOOLEAN(0, { hidden: true });
      this.updateAlways = ParamConfig.BOOLEAN(0, {
        visibleIf: { updateAlwaysAllowed: 1 }
      });
    }
  };
}
class MapboxListenerParamsConfig extends MapboxListenerParamConfig(NodeParamsConfig) {
}
export class MapboxListenerSopNode extends TypedSopNode {
  constructor() {
    super(...arguments);
    this._mapboxListener = new MapboxListener(this);
  }
  static PARAM_CALLBACK_update_mapbox_camera(node) {
    node.updateMapboxCamera();
  }
  updateMapboxCamera() {
    this._cameraNode = this.findCameraNode();
  }
  cameraNode() {
    return this._cameraNode;
  }
  cameraObject() {
    var _a;
    return (_a = this._cameraNode) == null ? void 0 : _a.object;
  }
  findCameraNode() {
    const node = this.pv.mapboxCamera.nodeWithContext(NodeContext.OBJ, this.states.error);
    if (node) {
      if (node.type() == MapboxCameraObjNode.type()) {
        return node;
      } else {
        this.states.error.set("found node is not a mapbox camera");
      }
    }
  }
}
class MapboxListenerSopNodeWithParams extends MapboxListenerSopNode {
  constructor() {
    super(...arguments);
    this.paramsConfig = new MapboxListenerParamsConfig();
  }
  _postInitController() {
  }
}
export class MapboxListener {
  constructor(_node) {
    this._node = _node;
    this._camera_controller = new CameraController(this._updateFromCamera.bind(this));
  }
  async cook() {
    let cameraNode = this._node.cameraNode();
    if (!cameraNode) {
      this._node.updateMapboxCamera();
      this._updateCameraController();
    }
    cameraNode = this._node.cameraNode();
    if (!cameraNode) {
      this._node.setObjects([]);
      return;
    }
    let zoom = cameraNode.zoom();
    const isMapboxActive = cameraNode != null;
    const isZoomInRange = zoom != null && zoom > this._node.pv.zoomRange.x && zoom < this._node.pv.zoomRange.y;
    const doPostInitController = !isMapboxActive || isZoomInRange;
    if (doPostInitController) {
      this._node._postInitController();
    } else {
      this._node.setObjects([]);
    }
  }
  _updateCameraController() {
    this._camera_controller.setUpdateAlways(this._node.pv.updateAlways || false);
    if (this._current_camera_path == null || this._current_camera_path !== this._node.pv.mapboxCamera.path()) {
      const cameraObject = this._node.cameraObject();
      if (cameraObject) {
        this._camera_controller.setTarget(cameraObject);
      } else {
        this._camera_controller.removeTarget();
      }
      this._current_camera_path = this._node.pv.mapboxCamera.path();
    }
  }
  _updateFromCamera() {
    if (this._node.cookController.isCooking()) {
      setTimeout(this._updateFromCamera.bind(this), 1e3);
    } else {
      const hasZoomParam = this._node.pv.useZoom;
      const hasBoundsParams = this._node.pv.useBounds;
      const cooker = this._node.scene().cooker;
      if (hasBoundsParams || hasZoomParam) {
        cooker.block();
      }
      const cameraNode = this._node.cameraNode();
      if (hasBoundsParams) {
        const sw_param = this._node.p.southWest;
        const ne_param = this._node.p.northEast;
        if (cameraNode) {
          const bounds = cameraNode.bounds();
          if (cameraNode != null && bounds != null) {
            const sw = bounds.getSouthWest();
            const ne = bounds.getNorthEast();
            sw_param.set([sw.lng, sw.lat]);
            ne_param.set([ne.lng, ne.lat]);
          }
        }
      }
      if (hasZoomParam) {
        if (cameraNode) {
          const zoom = cameraNode.zoom();
          if (zoom) {
            this._node.p.zoom.set(zoom);
          }
        }
      }
      if (hasBoundsParams || hasZoomParam) {
        cooker.unblock();
      }
      if (!hasBoundsParams && !hasZoomParam) {
        this._node.setDirty();
      }
    }
  }
}
