import { Http } from "../Http";
import { AstHelper } from "@gvol-org/geovis-brain-core";
import { BatchAsync } from "./batchAsync";
import { FeatureCollection } from "../models/FeatureCollection";

/**
 * @class BatchProcessing.image
 * @since BatchProcessing
 * @todo image.toExec
 * @todo image.toJob
 */
export class image extends BatchAsync {
  /**
   * @hideconstructor
   * @see BatchProcessing.image
   * @returns BatchProcessing.image
   */
  constructor(...param: any[]) {
    super();
    if (!(this instanceof image)) {
      return new image(param);
    }
  }

  static setBatchProcessMap(mapsdk: any) {
    this.mapSdk = mapsdk;
  }

  static mapSdk: any;

  /**
   * 对影像进行批处理
   * @param {Object} args 批处理对象
   * @tutorial BatchProcessing.image
   */
  static toExec(args: Object) {
    if (!Http.userIsVip) {
      // window['httpp'].abortSubject$.next();
      throw new Error("仅支持vip用户使用批处理功能");
    }
    if (args["scale"]) {
      Http.scale = args["scale"].toString();
    }
    let newObj = JSON.parse(JSON.stringify(args));
    let { newChain, newOrder } = AstHelper.objectParamChain(newObj);

    newChain.push({
      "functionName": "BatchProcessing.image.toExec",
      "arguments": {
        "args": newObj
      },
      "order": newOrder
    })

    // console.log('执行toExec方法....创建调用链');
    let batchObj = new BatchAsync();
    batchObj.execute(async () => {
      let data = await Http.getRequest(newChain, false, true);
      Http.responseSubject$.next(data);
      // console.log("batch接到的数据>>>", data);
      if (data && data.data.status == "success") {
        batchObj.param = data;
        this.batchSubject$.next(data.data.detail);
      } else {
        console.log("应当删除batch");
      }
    });
    return batchObj;
  }

  static processLayerIds: string[] = [];

  /**
   * 批量导出
   * @param {Object} args 批处理对象
   * @tutorial BatchProcessing.image
   */
  static toJob(args: {
    result: FeatureCollection;
    resultType?: string;
    scale?: number;
    description?: string;
    export?: object;
    mergeFlag?:boolean
  }) {
    if (!Http.userIsVip) {
      throw new Error("仅支持vip用户使用批处理功能");
    }

    if (!this.mapSdk) {
      console.log("批处理函数需要预先设置map----by weiyc")
      return;
    }

    if (args["scale"]) {
      Http.scale = args["scale"].toString();
    }
    if(args.mergeFlag == undefined){
      args.mergeFlag = false;
    }
    let newObj = JSON.parse(JSON.stringify(args));
    let { newChain, newOrder } = AstHelper.objectParamChain(newObj);

    newChain.push({
      "functionName": "BatchProcessing.image.toJob",
      "arguments": {
        "args": newObj
      },
      "order": newOrder
    })

    let batchObj = new BatchAsync();
    batchObj.execute(async () => {
      // await this.getBatchProcessResult(newChain);
      let data = await Http.getRequest(newChain, false, true);
      Http.responseSubject$.next(data);
      if (data && data.data.status == "success") {
        batchObj.param = data;
        this.refreshTaskList$.next(true);
        // console.log("subjecttttt", this.exportSubject$);
        // this.exportSubject$.next(data.data.detail);
      }
    });
    return batchObj;
  }

  //轮询实时上球逻辑----已弃用
  private static async getBatchProcessResult(chain: any, lastSourceId?: string) {
    let data = await Http.getRequest(chain, false, true);
    Http.responseSubject$.next(data);
    console.log("batch接到的数据>>>", data);
    if (data && data.data.status == "success") {
      let detail = data.data.detail;

      if(detail.tempViewUrl){
        let sourceOption = {
          url: detail.tempViewUrl
        }
        if(detail["properties"] && detail["properties"]["bbox"]){
          sourceOption["bbox"] = detail["properties"]["bbox"];
        }
        lastSourceId = this.addProcessLayer(sourceOption, lastSourceId);
        // 一秒后再次轮询
        setTimeout(() => {
          this.getBatchProcessResult(chain, lastSourceId)
        }, 1000);
      }else if(detail.url){
        let sourceOption = {
          url: detail.url,
          sourceLayer: detail["sourceLayer"]
        }
        if (detail["properties"] && detail["properties"]["bbox"]) {
          sourceOption["bbox"] = detail["properties"]["bbox"];
        }
        // 上球最终图层
        this.addProcessLayer(sourceOption, lastSourceId);
      } else {
        console.log("批处理最终结果异常");
        return;
      }

    } else {
      console.log("batch返回结果失败");
    }
  }

  //根据requestid请求批处理结果上球预览
  public static async addBatchLayer(requestid: string){
    //请求批处理中间(最终)结果
    let url = `${Http.astUrl}/getResult?requestId=${requestid}`;
    let data = await window["httpp"].getData(url, requestid);
    console.log(data);
    if (data && data.data.status == "success") {
      let detail = data.data.detail;

      if(detail.tempViewUrl){
        let sourceOption = {
          url: detail.tempViewUrl
        }
        if(detail["properties"] && detail["properties"]["bbox"]){
          sourceOption["bbox"] = detail["properties"]["bbox"];
        }
        this.addProcessLayer(sourceOption, requestid);
      }else if(detail.url){
        let sourceOption = {
          url: detail.url,
          sourceLayer: detail["sourceLayer"]
        }
        if (detail["properties"] && detail["properties"]["bbox"]) {
          sourceOption["bbox"] = detail["properties"]["bbox"];
        }
        // 上球最终图层
        this.addProcessLayer(sourceOption, requestid);
      } else {
        console.log("批处理最终结果异常");
        return;
      }

    } else {
      console.log("batch返回结果失败");
    }

  }

  //根据requestid删除批处理上球图层
  public static removeBatchLayer(requestid: string){
    if (this.sourceLayerIdsMap.has(requestid)) {
      let layerIds = this.sourceLayerIdsMap.get(requestid);
      layerIds.forEach((lid: any) => {
        this.mapSdk.map.removeLayer(lid);
      });
      this.mapSdk.map.removeSource(requestid);
      this.sourceLayerIdsMap.delete(requestid);
    }
  }

  private static sourceLayerIdsMap: Map<string, string[]> = new Map();

  private static addProcessLayer(urlObj: object, lastSourceId?: string) {
    //删除上次的图层
    if (lastSourceId) {
      if (this.sourceLayerIdsMap.has(lastSourceId)) {
        let layerIds = this.sourceLayerIdsMap.get(lastSourceId);
        layerIds.forEach((lid: any) => {
          this.mapSdk.map.removeLayer(lid);
        });
        this.mapSdk.map.removeSource(lastSourceId);
        this.sourceLayerIdsMap.delete(lastSourceId);
      }
    }
    // 随机生成8位字符sourceId
    function generateRandom8CharString() {
      const possibleChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
      let randomString = '';
      for (let i = 0; i < 8; i++) {
        randomString += possibleChars.charAt(Math.floor(Math.random() * possibleChars.length));
      }
      return randomString;
    }

    //加图层,共.json/.TIF/.fgb/.pbf四种数据格式
    let sourceId = generateRandom8CharString();
    //提取url后缀
    var matches = urlObj["url"].match(/\.([^.]+)$/);
    var extension = matches ? matches[1] : "";
    if (extension == "json") {
      fetch(urlObj["url"], {
        signal: Http.signal
      }).then(
        response => response.json()).then(
          response => {
            console.log(".json文件结果", response)
            let geojsonData = {
              "type": response.type,
              "features": response.features
            };
            let source = {
              type: "geojson",
              data: geojsonData,
            };
            this.addLayerByVector(source, sourceId);
            this.sourceLayerIdsMap.set(sourceId, [sourceId + "Circle", sourceId + "Line", sourceId + "Fill"]);
          }).catch(error => {
            console.error('请求失败', error);
            return;
          });
    } else if (extension == "TIF") {
      let source = {
        'type': 'raster',
        'tiles': [urlObj["url"]],
        'tileSize': 256,
      };
      if(urlObj["bbox"]){
        source["bounds"] = urlObj["bbox"];
        //执行飞入
        this.mapSdk.map.fitBounds(urlObj["bbox"]);
      }
      this.addLayerByRaster(source, sourceId);
      this.sourceLayerIdsMap.set(sourceId, [sourceId + "Layer"]);
    } else if (extension == "fgb") {
          let source = {
            'type': 'raster',
            'tiles': [urlObj["url"] + "&param=null"],
            'tileSize': 256,
          };
          if(urlObj["bbox"]){
            source["bounds"] = urlObj["bbox"];
            //执行飞入
            this.mapSdk.map.fitBounds(urlObj["bbox"]);
          }
          this.addLayerByRaster(source, sourceId);
          this.sourceLayerIdsMap.set(sourceId, [sourceId + "Layer"]);

    } else if (extension == "pbf") {
      let source = {
        type: 'vector',
        tiles: [urlObj["url"]]
      };
      if(urlObj["bbox"]){
        source["bounds"] = urlObj["bbox"];
        //执行飞入
        this.mapSdk.map.fitBounds(urlObj["bbox"]);
      }
      this.addLayerByVector(source, sourceId, urlObj["sourceLayer"]);
      this.sourceLayerIdsMap.set(sourceId, [sourceId + "Circle", sourceId + "Line", sourceId + "Fill"]);
    } else {
      console.log("批处理返回未知数据格式");
      return undefined;
    }
    return sourceId;
  }

  private static addLayerByVector(source: object, sourceId: string, sourceLayer?: string) {
    this.mapSdk.map.addSource(sourceId, source);
    let circleLayer = {
      id: sourceId + "Circle",
      type: "circle",
      source: sourceId,
      paint: {
        "circle-opacity": 1,
        "circle-radius": 1,
        "circle-color": "#0000FF"
      }
    };
    let lineLayer = {
      id: sourceId + "Line",
      type: "line",
      source: sourceId,
      paint: {
        "line-color": "#0000FF",
        "line-opacity": 0.9,
        "line-width": 2,
      }
    };
    let fillLayer = {
      id: sourceId + "Fill",
      type: "fill",
      source: sourceId,
      paint: {
        "fill-color": "#0000FF",
        "fill-opacity": 0.5
      }
    };
    if(sourceLayer){
      circleLayer["source-layer"] = sourceLayer;
      lineLayer["source-layer"] = sourceLayer;
      fillLayer["source-layer"] = sourceLayer;
    }
    this.mapSdk.map.addLayer(circleLayer);
    this.mapSdk.map.addLayer(lineLayer);
    this.mapSdk.map.addLayer(fillLayer);
  }

  private static addLayerByRaster(source: object, sourceId: string){
    this.mapSdk.map.addSource(sourceId, source);
    this.mapSdk.map.addLayer({
      id: sourceId + "Layer",
      type: 'raster',
      source: sourceId,
      paint: {
        'raster-opacity': 1
      }
    });
  }

  static clearMap() {
    this.sourceLayerIdsMap.forEach((value: any, key: any) => {
      value.forEach((lid: any) => {
        this.mapSdk.map.removeLayer(lid);
      });
      const style = this.mapSdk.map.getStyle();
      let hasSource = style.sources.hasOwnProperty(key);
      if(hasSource){
        this.mapSdk.map.removeSource(key);
      }
      
    });
    this.sourceLayerIdsMap.clear();
  }

}