// import { AsyncExecute } from "../common/AsyncExecute";
import { Guid } from "@gvol-org/geovis-brain-core";
import { Http } from "../Http";
import { FeatureCollection } from "../models/FeatureCollection";
import { ImageCollection } from "../models/ImageCollection";
import { Layer } from "@gvol-org/geovis-brain-core";
import { Palette } from "../models/Palette";
import { Subject } from "rxjs";
import { Geometry } from "../models/Geometry";
import { Image } from "../models/Image";
import { Feature } from "../models/Feature";
import * as turf from '@turf/turf';
import { MosaicData } from "../models/MosaicData";
import { Widget } from "../uisdk/Widget";
import { codeParams, ifOverLoadingObject } from "../common/FunParams";

import { ui } from "../uisdk/ui";
import mapboxgl from "mapbox-gl";
import Compare from "mapbox-gl-compare";
import { AddLayer } from "../models/AddLayer";
import { processMapSDK } from "@gvol-org/geovis-brain-core";
import { MapUtil } from "@gvol-org/geovis-brain-core";
import { BatchProcessing } from "../batchProcessingsdk/BatchProcessing";

// declare const mapboxgl: any;
/**
 * Class description
 * @summary sdk
 */
export class MapSdk {

  static map: any;

  //因为mapbox可能会变,所以要保存初始值
  static originalMapbox: any;

  /**  features的像素信息在运行时保存的(目的:不用请求接口获取) */
  static featuresGeometry: Array<any> = [];

  /** features的图层信息在运行时保存的(目的:不用请求接口获取) */
  static featuresLayerInfo: Array<any> = [];

  static stateChanged$ = new Subject();
  static loadTileSubject$ = new Subject();
  static setSubject(sub: any) {
    MapSdk.stateChanged$ = sub;
  }

  //用于设置layer的波段等内容
  static addLayerSubject$ = new Subject();

  static scaleMap = new Map<number, number>();

  static mapUI: HTMLElement;//ui组件容器

  constructor() {

  }

  // /**
  //  * 设置一个Mapbox实例.
  //  *@param {any} mapbox -Mapbox实例.
  //  */
  private static setMap(mapbox: any) {
    MapSdk.map = mapbox;
    MapSdk.originalMapbox = mapbox;
    MapSdk.scaleMap.set(0, 156543.03);
    MapSdk.scaleMap.set(1, 78271.52);
    MapSdk.scaleMap.set(2, 39135.76);
    MapSdk.scaleMap.set(3, 19567.88);
    MapSdk.scaleMap.set(4, 9783.94);
    MapSdk.scaleMap.set(5, 4891.97);
    MapSdk.scaleMap.set(6, 2445.98);
    MapSdk.scaleMap.set(7, 1222.99);
    MapSdk.scaleMap.set(8, 611.50);
    MapSdk.scaleMap.set(9, 305.75);
    MapSdk.scaleMap.set(10, 152.87);
    MapSdk.scaleMap.set(11, 76.44);
    MapSdk.scaleMap.set(12, 38.22);
    MapSdk.scaleMap.set(13, 19.11);
    MapSdk.scaleMap.set(14, 9.55);
    MapSdk.scaleMap.set(15, 4.78);
    MapSdk.scaleMap.set(16, 2.39);
    MapSdk.scaleMap.set(17, 1.19);
    MapSdk.scaleMap.set(18, 0.60);
    MapSdk.scaleMap.set(19, 0.30);
    BatchProcessing.image.setBatchProcessMap(this);
  }

  //存放所有创建过的layer
  public static layerList: Array<Layer> = [];
  //public static layerMap: Map<string, Layer> = new Map();
  //存放bbox
  //public static bboxMap: Map<string, any> = new Map();
  //触发保存结果
  private static keepResult(data: any) {
    // Http.runDataSubject$.next({
    //   type: 'layer',
    //   content: {
    //     type: data.type,
    //     params: data.params,
    //     bbox: data.bbox,
    //   }
    // });
  }
  //运行结果调用
  public static runResult(data: any) {
    if (data) {
      switch (data.type) {
        case "Geojson":
          {
            const { geojsonData, sourceId, layerId, style, render_sld } = data.params;
            MapUtil.addSourceByGeojson(this.map, geojsonData, sourceId, layerId, style, render_sld);//绘制图层
            data.bbox = turf.bbox(geojsonData);
          }
          break;
        case "Pbf":
          {
            const { serviceInfo, sourceId, layerId, visParams } = data.params;
            MapUtil.addSourceByPbf(this.map, serviceInfo, sourceId, layerId, visParams);//绘制图层
          }
          break;
        case "Url":
          {
            const {
              serviceInfo,
              sourceId,
              layerId,
              urlTiles,
              visible,
              visParams
            } = data.params;
            MapUtil.addSourceByUrl(
              this.map,
              serviceInfo,
              sourceId,
              layerId,
              urlTiles,
              visible,
              visParams
            );//绘制图层
          }
          break;
        case "Mvt":
          {
            const { serviceInfo, sourceId, layerId, visParams } = data.params;
            MapUtil.addSourceByMvt(this.map, serviceInfo, sourceId, layerId, visParams);//绘制图层
          }
          break;
      }
      if (data.bbox) {
        MapSdk.map.fitBounds(data.bbox);//视角飞入
      }
    }
  }
  /**
   * 在地图上添加图层,图层类型可以是Image、Geometry、Feature、FeatureCollection,返回图层唯一的ID
   * @param {Image|Geometry|Feature|FeatureCollection} image 作为图层添加的图像数据
   * @param  {Object} [visParams] 可选参数,属性:style(应用到图层的样式),palette(用于图层的调色板), crop(WKT类型的Geometry对象或gpkg文件路径),min, max, gamma, brightness
   * @param {String} [name] 可选参数,给予图层的名称。
   * @param {Boolean} [visible] 可选参数,该图层是否可见,默认为true
   * @return {String} 添加图层的Id
   * @tutorial Map
 
   */

  //@imagepath
  //![运行结果](https://pic1.zhimg.com/v2-8197a9e080f0fe581e9f061986bab8f4_b.jpg)
  //返回一个layer对象
  public static addLayer(
    image: Image | Geometry | Feature | FeatureCollection | MosaicData,
    visParams?: Object,
    name?: string,
    visible?: boolean,
  ) {

    let options = { id: Guid.newGuid(), image, visParams, name, visible };
    return MapUtil.addLayer(options, this);
  }
  /**
   * 根据提供的ID移除图层
   * @param {String} Id 待删除图层的ID
   * @tutorial Map
   */
  public static removeLayer(id: string) {
    if (this.layerList) {
      let res = this.layerList.find((v: any) => { return v.id == id });
      res?.onLoadCompleted(() => {
        res?.mapboxLayresId.forEach((lid: any) => {
          this.map.removeLayer(lid);
        });
        res?.mapboxSourcesId.forEach((sid: any) => {
          this.map.removeSource(sid);
        });
      });
    }
  }

  /**
   * 设置地图中心显示
   * @param {Number} lon 地图显示中心点的经度
   * @param {Number} lat 地图显示中心点的经度
   * @param {Number} [zoom] 可选参数,地图显示缩放级别(0-24)
   * @tutorial Map
   */
  public static setCenter(lon: number, lat: number, zoom?: number) {
    MapSdk.map.setCenter([lon, lat]);
    if (zoom) {
      MapSdk.map.setZoom(zoom);
    }
  }
  /**
   * 设置地图显示缩放级别
   * @param {Number} zoom 地图显示缩放级别(0-24)
   * @tutorial Map
   */
  public static setZoom(zoom: number) {
    MapSdk.map.setZoom(zoom);
  }

  /**
   * 放大地图
   * @tutorial Map
   */
  public static zoomIn() {
    MapSdk.map.zoomIn();
  }
  /**
   * 缩小地图
   * @tutorial Map
   */
  public static zoomOut() {
    MapSdk.map.zoomOut();
  }



  /**
   * 清空已添加的所有图层
   * @param {String} [param] 影像的url
   * @tutorial Map
   */
  public static clear() {
    if (this.layerList) {
      this.layerList?.forEach((data: any) => {
        data?.onLoadCompleted(() => {
          data?.mapboxLayresId.forEach((lid: any) => {
            this.map.removeLayer(lid);
          });
          data?.mapboxSourcesId.forEach((sid: any) => {
            this.map.removeSource(sid);
          });
        });
      });
    }
    BatchProcessing.image.clearMap();
  }

  /**
  * 清空已添加的所有图层, no onLoadCompleted
  * @param {String} [param] 影像的url
  * @tutorial Map
  */
  public static clearCurrent() {
    // this.layerMap.forEach(function (value, key, map) {
    //   value.mapboxLayresId.forEach((lid) => {
    //     MapSdk.mapbox.removeLayer(lid);
    //   });
    //   value.mapboxSourcesId.forEach((sid) => {
    //     MapSdk.mapbox.removeSource(sid);
    //   });
    //   MapSdk.layerMap.delete(key);
    // });
  }
  /**
   * 相机飞入到制定图层位置
   * @param {String | Array<number>} param 图层的Id
   * @tutorial Map
   */
  public static flyto(param: string | Array<number>) {
    MapUtil.flyto(this, param);
  }


  /**
     * 图层过滤显示
     * @param {String} id 图层的id
     * @param {String} classId 过滤的图层类别
     */
  public static setFilter(id: string, classId: string) {
    MapUtil.setFilter(this, id, classId);
  }

  /**
   * 返回当前地图视图的近似像素比例,单位为米
   * @returns number
   * @tutorial Map
   */
  public static getScale() {
    let zoomLevel = Math.round(MapSdk.map.getZoom()) + 1;
    if (MapSdk.scaleMap.has(zoomLevel)) {
      return MapSdk.scaleMap.get(zoomLevel);
    }
    return null;
  }
  /**
   * 修改地图底图
   * @param {String} mapTypeId 可以是 "SATELLITE"、"ROADMAP" 或 "TERRAIN" 之一
   * @tutorial Map
   */
  public static setOptions(mapTypeId:string): any {
    return null;
  }

  /**
   * 返回地图视图的当前缩放级别
   * @returns number
   * @tutorial Map
   */
  public static getZoom(): number {
    const zoom = MapSdk.map.getZoom();
    return zoom

  }

  /**
   * 返回地图视图的地理中心
   * @returns Geometry.Point
   * @tutorial Map
   */
  public static getCenter() {
    const center = MapSdk.map.getCenter();
    return { lng: center.lng, lat: center.lat }

  }

  /**
   * 返回地图视图的地理边界
   * @param {boolean} asGeoJSON optional 如果asGeoJSON为true,则返回GeoJSON格式的边界 
   * @returns GeoJSONGeometry|Array<Number>|String
   * @tutorial Map
   */

  public static getBounds(asGeoJSON?: boolean) {
    const bounds = MapSdk.map.getBounds(asGeoJSON)
    return bounds
  }

  private static setMapUI(mapUI: any) {
    this.mapUI = mapUI;
  }

  /**
  * 在地图上添加自定义ui
  * @param {Widget} ui  自定义ui
  * @tutorial Map
  */
  public static addUI(ui: Widget) {
    if (this.mapUI) {
      //  console.log("addUI Code", ui['expressions']);
      if (!Http.isRunAddUICode) {
        Http.runDataSubject$.next({
          type: 'ui',
          content: Http.codeContent,
        });
        Http.isRunAddUICode = true;
      }
      if (ui.el) {
        let style = ui.style();
        // console.log('mapStyle:', style);
        if (!style.get('position')) {
          style.set('position', 'absolute');
          if (!style.get('right') && !style.get('bottom') && !style.get('left') && !style.get('top')) {
            style.set('left', '50%');
            style.set('top', '10px');
          }
        }
        style.set('z-index', '99');
        if (ui.getType() == 'Map') {
          if (!style.get('width') && !style.get('height')) {
            style.set('width', '300px');
            style.set('height', '200px');
          }
        }
      }
      this.mapUI.appendChild(ui.el as HTMLElement);
      Http.createUIMapSubject$.next(ui);
      if (ui['cht']) {
        (ui.el as HTMLElement).style.width = '300px';
        ui['cht']?.resize();
      }
    }
  }

  /**
  * 移除地图上的自定义ui
  * @param {Widget} ui  自定义ui
  * @tutorial Map
  */
  public static removeUI(ui: Widget) {
    if (this.mapUI) {
      this.mapUI.removeChild(ui.el as HTMLElement);
    }
  }


  //代替flyto,使用value接口
  /**
   * 相机飞入到指定图层位置
   * @param {Object} object 图层对象
   * @param {Number} [zoom] 地图显示缩放级别(0-24)
   */
  public static async centerObject(object: Object, zoom?: number) {
    await MapUtil.centerObject(this, object, zoom);
    // console.log("centerObject mapsdk", runData)
  }

  //卷帘加的底图,为了适配屏幕布局变化进行resize
  public static compareMapList: any[] = [];

  /**
  * 卷帘
  * @param {Image} left  左侧显示的Image实例
  * @param {Image} right 右侧显示的Image实例
  * @param {any[]} additionLayer 额外在左右两侧地图上都需要加的图层
  * @tutorial Map
  */
  public static CompareImage(left: Image, right?: Image, additionLayer?: any[]) {
    this.compareMapList = [];
    //先清除原有地图
    ui.root.clear();
    const link = document.createElement("link"); // 创建 link 元素
    link.rel = "stylesheet"; // 设置 link 的 rel 属性为 stylesheet
    link.href = "https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-compare/v0.4.0/mapbox-gl-compare.css"; // 设置 link 的 href 属性为 CSS 文件的 URL
    link.type = "text/css";
    (ui.root.el as any).appendChild(link); // 将 link 元素添加到指定元素的子节点中

    let mapStyle = {
      position: "absolute",
      top: 0,
      bottom: 0,
      width: "100%",
      height: "100%",
      "z-index": 1
    }
    let beforeDiv = ui.Panel(undefined, undefined, mapStyle);
    (beforeDiv.el as any).id = "before";
    let afterDiv = ui.Panel(undefined, undefined, mapStyle);
    (afterDiv.el as any).id = "after";
    let compareStyle = {
      height: "100%",
      width: "100%",
      position: "absolute",
      left: "0px",
      top: "0px",
      "z-index": 1
    }
    let compareDiv = ui.Panel([beforeDiv, afterDiv], ui.Panel.Layout.flow('horizontal'), compareStyle);
    (compareDiv.el as any).id = "comparison-container";
    ui.root.add(compareDiv);

    // 创建卷帘
    mapboxgl.accessToken = 'pk.eyJ1IjoiYXJhcGF5IiwiYSI6ImNsNXEyYXJhMDB2MWkzaWw4dWgxcWptOHYifQ.UYSWGUj_ufnOu-7KACtl4w';
    let center = MapSdk.getCenter();
    let zoom = MapSdk.getZoom();
    let mapStatus = {
      center: [center.lng, center.lat],
      zoom: zoom
    }
    let mapboxStyle = MapSdk.map.getStyle();
    let beforeMap = new AddLayer("before", mapStatus, mapboxStyle);
    let afterMap = new AddLayer("after", mapStatus, mapboxStyle);
    this.compareMapList.push(beforeMap.map);
    this.compareMapList.push(afterMap.map);
    let leftLayer = undefined;
    let rightLayer = undefined;
    if (left) {
      let leftLayerid = beforeMap.addLayer(left);
      leftLayer = beforeMap.layerList.find((v: any) => { return v.id == leftLayerid });
      // 加上额外的图层
      if (additionLayer && additionLayer.length > 0) {
        leftLayer.onLoadCompleted(() => {
          additionLayer.forEach(la => {
            let tempLayerid = beforeMap.addLayer(la, { style: { polygonFillOpacity: 0 } });
            let tempLayer = beforeMap.layerList.find((v: any) => { return v.id == tempLayerid });
            //每次都把新加的图层置于顶层
            for (let x = 0; x < tempLayer.mapboxLayresId.length; x++) {
              beforeMap.map.moveLayer(tempLayer.mapboxLayresId[x], undefined);
            }
          })
        })

      }
    }
    if (right) {
      let rightLayerid = afterMap.addLayer(right);
      rightLayer = afterMap.layerList.find((v: any) => { return v.id == rightLayerid });
      // 加上额外的图层
      if (additionLayer && additionLayer.length > 0) {
        rightLayer.onLoadCompleted(() => {
          additionLayer.forEach(la => {
            let tempLayerid = afterMap.addLayer(la, { style: { polygonFillOpacity: 0 } });
            let tempLayer = afterMap.layerList.find((v: any) => { return v.id == tempLayerid });
            //每次都把新加的图层置于顶层
            for (let x = 0; x < tempLayer.mapboxLayresId.length; x++) {
              afterMap.map.moveLayer(tempLayer.mapboxLayresId[x], undefined);
            }
          })
        })
      }
    }
    if (leftLayer && !rightLayer) {
      beforeMap.flyto(leftLayer.id);
    } else if (rightLayer) {
      afterMap.flyto(rightLayer.id);
    }
    const container = '#comparison-container';
    const map = new Compare(beforeMap.map, afterMap.map, container, {});
  }

}
processMapSDK(MapSdk, "MapSdk", codeParams, ifOverLoadingObject);