import { LinearFilter, FloatType, RGBFormat } from "three/src/constants";
import { DataTexture } from "three/src/textures/DataTexture";
import { TypedCopNode } from "@polygonjs/polygonjs/dist/src/engine/nodes/cop/_Base";
import { CoreMapboxUtils } from "../../../core/mapbox/Utils";
import { CoreImage } from "@polygonjs/polygonjs/dist/src/core/Image";
import { CoreMapboxClient } from "../../../core/mapbox/Client";
export var TileType = /* @__PURE__ */ ((TileType2) => {
  TileType2["ELEVATION"] = "elevation";
  TileType2["SATELLITE"] = "satellite";
  return TileType2;
})(TileType || {});
const TILE_TYPES = ["elevation" /* ELEVATION */, "satellite" /* SATELLITE */];
export var TileRes = /* @__PURE__ */ ((TileRes2) => {
  TileRes2[TileRes2["LOW"] = 256] = "LOW";
  TileRes2[TileRes2["HIGH"] = 512] = "HIGH";
  return TileRes2;
})(TileRes || {});
const ROOT_URL = "https://api.mapbox.com/v4";
import { NodeParamsConfig, ParamConfig } from "@polygonjs/polygonjs/dist/src/engine/nodes/utils/params/ParamsConfig";
class MapboxTileCopParamsConfig extends NodeParamsConfig {
  constructor() {
    super(...arguments);
    this.lngLat = ParamConfig.VECTOR2([-119.63, 37.73311]);
    this.zoom = ParamConfig.INTEGER(12, {
      range: [1, 24],
      rangeLocked: [true, true]
    });
    this.type = ParamConfig.INTEGER(0, {
      menu: {
        entries: TILE_TYPES.map((m) => ({
          name: m,
          value: TILE_TYPES.indexOf(m)
        }))
      }
    });
  }
}
const ParamsConfig = new MapboxTileCopParamsConfig();
export class MapboxTileCopNode extends TypedCopNode {
  constructor() {
    super(...arguments);
    this.paramsConfig = ParamsConfig;
    this._paramHires = true;
    this._texture = new DataTexture(new Float32Array(3 * 512 /* HIGH */ * 512 /* HIGH */), 512 /* HIGH */, 512 /* HIGH */, RGBFormat, FloatType);
  }
  static type() {
    return "mapboxTile";
  }
  initializeNode() {
    this._texture.image.data.fill(255);
    this._texture.minFilter = LinearFilter;
    this._texture.magFilter = LinearFilter;
    this._texture.flipY = true;
  }
  async cook() {
    const type = TILE_TYPES[this.pv.type];
    switch (type) {
      case "elevation" /* ELEVATION */: {
        await this._cookForElevation();
        break;
      }
      case "satellite" /* SATELLITE */: {
        await this._cookForSatellite();
        break;
      }
    }
    this._texture.needsUpdate = true;
    this.setTexture(this._texture);
  }
  async _cookForElevation() {
    const url = await this._url("mapbox.terrain-rgb");
    const image_data_rgba = await CoreImage.data_from_url(url);
    const data_rgba = image_data_rgba.data;
    const pixels_count = image_data_rgba.width * image_data_rgba.height;
    let src_stride, dest_stride;
    const dest_data = this._texture.image.data;
    if (this._paramHires) {
      let elevation, R, G, B;
      for (let i = 0; i < pixels_count; i++) {
        src_stride = i * 4;
        dest_stride = i * 3;
        R = data_rgba[src_stride + 0];
        G = data_rgba[src_stride + 1];
        B = data_rgba[src_stride + 2];
        elevation = (R * 256 * 256 + G * 256 + B) * 0.1 / (256 * 256);
        dest_data[dest_stride + 0] = elevation;
        dest_data[dest_stride + 1] = elevation;
        dest_data[dest_stride + 2] = elevation;
      }
    }
  }
  async _cookForSatellite() {
    const url = await this._url("mapbox.satellite");
    const image_data_rgba = await CoreImage.data_from_url(url);
    const data_rgba = image_data_rgba.data;
    const pixels_count = image_data_rgba.width * image_data_rgba.height;
    let src_stride, dest_stride;
    const dest_data = this._texture.image.data;
    if (this._paramHires) {
      for (let i = 0; i < pixels_count; i++) {
        src_stride = i * 4;
        dest_stride = i * 3;
        dest_data[dest_stride + 0] = data_rgba[src_stride + 0] / 255;
        dest_data[dest_stride + 1] = data_rgba[src_stride + 1] / 255;
        dest_data[dest_stride + 2] = data_rgba[src_stride + 2] / 255;
      }
    } else {
      const resolution = 256 /* LOW */;
      for (let i = 0; i < resolution; i++) {
        for (let j = 0; j < resolution; j++) {
          let k = i * resolution + j;
          src_stride = k * 4;
          dest_stride = k * 3;
          dest_data[dest_stride + 0] = data_rgba[src_stride + 0];
          dest_data[dest_stride + 1] = data_rgba[src_stride + 1];
          dest_data[dest_stride + 2] = data_rgba[src_stride + 2];
          k = (i + 1) * resolution + j;
          dest_stride = k * 3;
          dest_data[dest_stride + 0] = data_rgba[src_stride + 0];
          dest_data[dest_stride + 1] = data_rgba[src_stride + 1];
          dest_data[dest_stride + 2] = data_rgba[src_stride + 2];
          k = i * resolution + (j + 1);
          dest_stride = k * 3;
          dest_data[dest_stride + 0] = data_rgba[src_stride + 0];
          dest_data[dest_stride + 1] = data_rgba[src_stride + 1];
          dest_data[dest_stride + 2] = data_rgba[src_stride + 2];
          k = (i + 1) * resolution + (j + 1);
          dest_stride = k * 3;
          dest_data[dest_stride + 0] = data_rgba[src_stride + 0];
          dest_data[dest_stride + 1] = data_rgba[src_stride + 1];
          dest_data[dest_stride + 2] = data_rgba[src_stride + 2];
        }
      }
    }
  }
  async _url(endpoint) {
    const tile_number = CoreMapboxUtils.lnglat_to_tile_number(this.pv.lngLat.x, this.pv.lngLat.y, this.pv.zoom);
    const x = tile_number.x;
    const y = tile_number.y;
    const z = this.pv.zoom;
    const res = this._paramHires ? "@2x" : "";
    const token = CoreMapboxClient.token();
    return `${ROOT_URL}/${endpoint}/${z}/${x}/${y}${res}.pngraw?access_token=${token}`;
  }
}
