import { getCenterByExtent } from '@/utils/common.js';
import {
  Map,
  View,
  Collection,
  Feature
} from 'ol';
import WFS from 'ol/format/WFS.js';
import {
  transform,
  fromLonLat
} from 'ol/proj';
import { Point } from 'ol/geom';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import {
  Style,
  Stroke,
  Fill,
  Text,
  Circle,
  Icon
} from 'ol/style';
import { extend, createEmpty } from 'ol/extent';
import VectorLayer from 'ol/layer/Vector';
import Image from 'ol/layer/Image';
import ImageWMS from 'ol/source/ImageWMS.js';
import VectorSource from 'ol/source/Vector';
import TileWMS from 'ol/source/TileWMS';
import GeoJSON from 'ol/format/GeoJSON';
import { get as getProjection } from 'ol/proj';
import { getWidth, getTopLeft } from 'ol/extent';
import WMTSTileGrid from 'ol/tilegrid/WMTS';
import WKT from 'ol/format/WKT';
import WMTS from 'ol/source/WMTS';
import { Overlay } from 'ol';
const pointVectorSource = new VectorSource();
import PluggableMap from 'ol/PluggableMap';
import { MousePosition, defaults } from 'ol/control';
import { createStringXY } from 'ol/coordinate';
import { Draw, Modify } from 'ol/interaction';

import { get, post } from '@/api/index.js';
import { MultiPolygon } from 'ol/geom';
class GisUtils {
  map = null;
  overLayer = null;
  instance = null;


  constructor(domId) {
    this.getMap(domId)
    this.initView()
    return this
  }
  /**
 * 获取一个地图容器
 * @param {string} domId dom节点id
 */
  getMap (domId) {
    let view = new View({
      projection: 'EPSG:3857'
    });
    PluggableMap.prototype.getEventPixel = function (event) {
      // eslint-disable-next-line no-underscore-dangle
      const viewportPosition = this.viewport_.getBoundingClientRect();
      let size = [viewportPosition.width, viewportPosition.height];
      const view = this.getView();
      if (view) {
        size = view.getSizeFromViewport_();
      }
      const eventPosition =
        'changedTouches' in event /** @type {TouchEvent} */ ?
          event.changedTouches[0] /** @type {MouseEvent} */ :
          event;

      return [
        (eventPosition.clientX - viewportPosition.left) * size[0] /
        viewportPosition.width,
        (eventPosition.clientY - viewportPosition.top) * size[1] /
        viewportPosition.height
      ];

    };

    let mousePositionControl = new MousePosition({
      coordinateFormat: createStringXY(4),
      projection: 'EPSG:3857',
      className: 'custom-mouse-position',
      target: document.getElementById('mouse-position'),
      undefinedHTML: '&nbsp;'
    });
    let map = new Map({
      target: domId,
      view: view,
      controls: defaults({
        zoom: false,
        rotate: false,
        attribution: false,
        attributionOptions: {
          collapsible: false
        }
      }).extend([mousePositionControl]),
      layers: [
      ]
    });
    this.map = map;
    return this.map;
  }

  /**
   * 获取适量图层
   * @param {*} color 
   * @returns 
   */
  getVectorLayerByColor (color) {
    let layer = new VectorLayer({
      renderMode: 'webgl', // 使用WebGL渲染器
      source: new VectorSource(),
      zIndex: 101,
      style: new Style({
        fill: new Fill({
          color: color
        }),
        stroke: new Stroke({
          color: color,
          width: 2
        })
      })
    });
    this.map.addLayer(layer);
    return layer;
  }

  getVectorLayerByFs (features, zIndex = 1012) {
    const vectorSource = new VectorSource({
      features: features,
    });
    // 创建矢量图层
    let layer = new VectorLayer({
      zIndex,
      source: vectorSource
    });
    this.map.addLayer(layer)
    return layer
  }

  addLayer (layer) {
    this.map.addLayer(layer);
  }

  getPolygon (coordinates) {
    const polygon = new MultiPolygon([coordinates]);
    return polygon;
  }

  getFeature (info, icon) {
    let feature = new Feature({
      geometry: new Point(
        fromLonLat([info.lng, info.lat])
      ),
      deptId: info.id,
      deptName: info.label,
      orgCode: info.orgCode,
      lat: info.lat,
      lng: info.lng,
      deptLevel: info.deptLevel,
      level: 'deptPoint',
    })
    feature.setStyle(this.createFeatureStyle(feature, icon));
    return feature;
  }

  getFeature2 (info, icon) {
    let feature = new Feature({
      geometry: new Point(
        JSON.parse(info.theGeom).coordinates
      ),
      detail: info,
      level: 'permanent',
    })
    feature.setStyle(this.createFeatureStyle(feature, icon));
    return feature;
  }


  getFeature3 (item, fill, stroke) {
    let feature = new Feature({
      geometry: new MultiPolygon(JSON.parse(item.theGeom).coordinates),
      // name: item.centerName,
      // centerDeptId: item.deptId,
      level: 'resource',
      detail: item
    })
    feature.setStyle(this.createMultiPolygonFeatureStyle(fill, stroke));
    return feature;
  }

  createMultiPolygonFeatureStyle (fill, stroke) {
    return new Style({
      fill: new Fill({
        //矢量图层填充颜色，以及透明度
        color: fill,
      }),
      stroke: new Stroke({
        //边界样式
        color: stroke,
        width: 2,
      })
    });
  }

  // 设置坐标点的样式
  createFeatureStyle (feature, locationIcon) {
    return new Style({
      image: new Icon({
        //设置图标偏移
        anchor: [0.5, 1],
        //标注样式的起点位置
        anchorOrigin: "top-right",
        //X方向单位：分数
        anchorXUnits: "fraction",
        //Y方向单位：像素
        anchorYUnits: "pixels",
        //偏移起点位置的方向
        offsetOrigin: "top-right",
        //透明度
        opacity: 0.9,
        // rotation: (Math.PI / 180) * 20,
        //图片路径
        src: locationIcon,
      }),
      text: new Text({
        textAlign: "center", //位置
        textBaseline: "bottom", //基准线
        font: "normal 14px 微软雅黑", //文字样式
        text: feature.get("deptName"), //文本内容
        fill: new Fill({
          //文本填充样式（即文字颜色)
          color: "#ffff00",
        }),
      })
    });
  }

  writeFeature (fs) {
    return new GeoJSON().writeFeature(fs);
  }

  addModify (layer) {
    const modify = new Modify({
      features: new Collection(layer.getSource().getFeatures()),
      pixelTolerance: 4
    });
    return modify;
  }

  drawLineSplit (source) {
    let draw = new Draw({
      source: source,
      type: "LineString",
      style: new Style({
        image: new Circle({
          radius: 5,
          fill: new Fill({
            color: "#03a9f4"
          })
        }),
        stroke: new Stroke({
          color: "#03a9f4",
          width: 2
        }),
        fill: new Fill({
          color: "rgba(255, 255, 255, 0.7)"
        })
      })
    });
    return draw;

  }

  getMapContainer () {
    return this.map;
  }

  /**
   * 键入弹窗
   * @param {*} el dom
   * @param {*} coord 位置
   */
  addOverlay (el, coord) {
    let overLayer = new Overlay({
      element: el, // 挂载元素
      position: coord,
      className: 'overLay',
      positioning: 'top-center',
      autoPanAnimation: {
        duration: 250
      },
      stopEvent: true
    });
    this.map.addOverlay(overLayer);
    this.overLayer = overLayer;

  }

  /**
   * 移除弹窗
   */
  removeOverlay () {
    if (this.overLayer) {
      this.map.addOverlay(this.overLayer);
    }
  }

  /**
   * 飞入动画
  */
  flyTo (duration = 2000, position = [0, 0]) {
    this.map.getView().animate({
      center: position,
      duration: duration
    });
  }
  /**
   *
   * @param {*} evt 事件
   * @param {*} layerName 图层名称
   * @param {*} owsUrl 请求路径
   */
  async getFeatureByEvt (evt, layerName, owsUrl) {
    let point = new Point([evt.coordinate[0], evt.coordinate[1]]);
    let cql_filter = `INTERSECTS (the_geom,${new WKT().writeGeometry(point)})`;
    const params = this.getWFSparams(layerName, cql_filter);
    const feature = await this.getFeaturesByWFS(owsUrl, params);
    return feature;
  }

  /**
   * 获取一个视图
   * @param {array} extent 四至
   * @param {int} zoom 缩放级别
   * @param {int} minZoom 最小缩放级别
   * @param {int} maxZoom 最大缩放级别
   */
  initView (extent = [100, 100, 100, 100], zoom = 4, minZoom = 3, maxZoom = 18.4) {
    let view = new View({
      center: getCenterByExtent(extent),
      zoom,
      minZoom,
      maxZoom,
      projection: 'EPSG:3857'
    });
    this.map.setView(view);
    return view;
  }

  getView () {
    return this.map.getView()
  }

  /**
   * 获取WMS图层
   * @param {*} wmsurl wms路径
   * @param {*} layerName 图层名
   * @param {*} isShow 是否隐藏
   */
  getWMSLayer (wmsurl, layerName, isShow = false, zIndex = 50) {
    let layer = new TileLayer({
      visible: isShow,
      zIndex,
      source: new TileWMS({
        url: wmsurl,
        params: { 'LAYERS': layerName, 'TILED': true, SRID: 4326 },
        transition: 0
      })
    });
    this.map.addLayer(layer);
    return layer;
  }

  /**
   * 获取天地图图层
   * @param {string} url 最小缩放级别
   */
  addTianDiTuLayer (visible = true) {
    let tianDitTu = new TileLayer({
      visible,
      source: new XYZ({
        url: 'http://t{0-7}.tianditu.com/img_w/wmts?' + 'SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles' + '&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=cc4aba6e967096098249efa069733067'
      })
    });
    this.map.addLayer(tianDitTu);
    return tianDitTu;
  }

  /**
   * 获取天地图图层
   * @param {string} url 最小缩放级别
   */
  addAnnotationLayer (visible = true) {
    let tianDitTu = new TileLayer({
      visible,
      source: new XYZ({
        url: 'http://t{0-7}.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=cc4aba6e967096098249efa069733067'
      })
    });
    this.map.addLayer(tianDitTu);
    return tianDitTu;
  }

  addImageLayer (mapGeoServerUrl, layerName, deptIds) {
    let layer = new Image({
      source: new ImageWMS({
        url: mapGeoServerUrl + '/wms',
        params: {
          LAYERS: layerName,
          cql_filter: "dept_id in (" + deptIds + ")",
          SRID: 3857,
        }
      }),
      name: 'countyBorderLayer'
    });
    this.map.addLayer(layer)
    return layer
  }

  /**
   * 获取wfs服务请求参数
   * @param {string} typename 请求的图层名
   * @param {string} cql cql语句
   * @return {obj} params wfs 的请求参数
   */
  getWFSparams (typename, cql = null) {
    var params = {
      srsName: 'EPSG:4326',
      service: 'WFS',
      version: '1.0.0',
      request: 'GetFeature',
      typename,
      outputFormat: 'application/json'
    };
    if (cql) {
      params.CQL_FILTER = cql;
    }
    return params;
  }

  getVectorSource () {
    let source = new VectorSource();
    return source;
  }

  getVectorLayer () {
    let layer = new VectorLayer({
      editable: true, // 确保图层是可编辑的
      source: new VectorSource(),
      zIndex: 101,
      style: new Style({
        fill: new Fill({
          color: [255, 80, 80, 0.5]
        }),
        stroke: new Stroke({
          color: [255, 80, 80, 1],
          width: 2
        })
      })
    });
    this.map.addLayer(layer);
    return layer;
  }

  /**
   * 根据描边颜色获取新的要素集合
   * @param {string} strokeColor 描边颜色
   * @param {array} fsList 要素数组
   */
  getStrokeStyle (fsList, strokeColor = '#00FEFA', textName = 'NAME') {
    const arr = fsList.map(item => {
      item.setStyle(
        new Style({
          stroke: new Stroke({
            color: strokeColor,
            width: 1
          }),
          text: new Text({
            text: item.values_[textName],
            overflow: true,
            font: 'bold 11px serif',
            fill: new Fill({
              color: strokeColor
            })
          })
        })
      );
      return item;
    });
    return arr;
  }

  /**
   * 根据要素集合设置填充样式
   * @param {array} fsList 要素集合
   * @param {*} fillColor 填充色
   * @returns 返回矢量图层
   */
  getFillStyle (fsList, fillColor = '#00FEFA', testName = 'XZQHMC') {
    fsList.forEach(item => {
      item.setStyle(
        new Style({
          stroke: new Stroke({
            color: fillColor,
            width: 2
          }),
          text: new Text({
            text: item.values_[testName],
            overflow: true,
            font: 'bold 11px serif',
            fill: new Fill({
              color: '#00FEFA'
            })
          })
        })
      );
    });
    return fsList;
  }

  /**
   * 通过wfs服务拿到要素
   * @param {string} url 请求的路径
   * @param {obj} params 参数
   * @returns
   */
  async getFeaturesByWFS (url, params = {}) {
    const res = await get(url, params);
    const fs = new GeoJSON().readFeatures(res);
    return fs;
  }

  getStyle (strokeColor = [255, 0, 0, 1], fillColor = [255, 0, 0, 0.1]) {
    let style = new Style({
      stroke: new Stroke({
        color: strokeColor,
        width: 2
      }),
      fill: new Stroke({
        color: fillColor
      })
    });
    return style;
  }


  changeTextName (arr, layerName) {
    this.textName[layerName] = arr;
  }

  getStyleWithText (strokeColor = [180, 180, 0, 1], fillColor = [180, 180, 0, 0.1]) {
    let style = new Style({
      stroke: new Stroke({
        color: strokeColor,
        width: 2
      }),
      fill: new Stroke({
        color: fillColor
      }),
      text: new Text({
        text: '333',
        overflow: true,
        font: 'bold 11px serif',
        fill: new Fill({
          color: '#00FEFA'
        })
      })
    });
    return style;


  }

  /**
   *根据要素集合获得矢量图层
   * @param {array} fs 要素集合
   */
  getVectorLayerByFsWidthText (fs, zIndex = 200, opacity = 1, strokeColor = [0, 180, 241, 1], fillColor = [0, 180, 241, 0.1], layerName) {
    const source = new VectorSource({
    });
    if (fs.length) {
      source.addFeatures(fs);
    }

    const layer = new VectorLayer({
      renderMode: 'webgl',
      style: (feature) => {

        let arr = '';
        this.textName[layerName].forEach(item => {
          arr += feature.getProperties()[item] + '\n';
        });
        return new Style({
          fill: new Fill({
            color: fillColor
          }),
          text: new Text({
            overflow: false,
            text: arr,
            font: 'bold 12px serif',
            fill: new Fill({
              color: '#ffffff'
            })
          }),
          stroke: new Stroke({
            color: strokeColor,
            width: 1
          })
        });
      },
      opacity,
      source: source,
      zIndex: zIndex
    });
    this.map.addLayer(layer);
    return layer;
  }
  /**
   * 根据图层名获取瓦片图层
   */
  getTileLayerByLayerName (url, layerName, visible = true, zIndex = 50) {
    const layer = new TileLayer({
      visible,
      zIndex: zIndex,
      source: new TileWMS({
        url,
        params: { 'LAYERS': layerName, 'TILED': true, SRID: 3857 },
        transition: 0
      })
    });
    return layer;
  }
  /**
  * 键入弹窗
  * @param {*} el dom
  * @param {*} coord 位置
  */
  addOverlay (el, coord) {
    let overLayer = new Overlay({
      element: el, // 挂载元素
      position: coord,
      autoPanAnimation: {
        duration: 250
      },
      stopEvent: true
    });
    this.map.addOverlay(overLayer);
    this.overLayer = overLayer;
  }

  /**
   * 根据要素集合适配视图
   * @param {map} 地图容器
   * @param {*} featureList 要素集合
   */
  mapSetFit (featureList, padding = [100, 20, 20, 20], duration = 2000) {
    let options = {
      padding,
      duration
    };
    let extent = createEmpty();
    featureList.forEach(item => {
      const itemExtent = item.getGeometry().getExtent();
      extent = extend(extent, itemExtent);
    });
    if (featureList.length) {
      this.map.getView().fit(extent, options);
    }
  }
  /**
   * 坐标转换
   * @param {coordinate } openlayer 输出坐标值
   * Amap public index.html 导入
   */
  transform (coordinate) {
    return transform(coordinate, 'EPSG:3857', 'EPSG:4326');
  }
  // 在地图上添加点， 并添加点的样式
  setPoint (map, pointList) {
    pointVectorSource.clear();
    if (pointList.length === 0) return;
    const pointStyle = new Style({
      image: new Icon({
        src: locationIcon,
        scale: 1,
        anchor: [0.5, 0.5],
        rotateWithView: false,
        rotation: 45
      })
    });
    let pointFeature;
    pointList.forEach(item => {
      pointFeature = new Feature({
        geometry: new Point(new fromLonLat([item.longitude, item.latitude])),
        url: item.url,
        showText: true,
        showPicture: item.url ? true : false
      });
      pointFeature.setStyle(pointStyle);
      pointVectorSource.addFeature(pointFeature);
    });
    const vectorLayer = new VectorLayer({
      // zIndex: 999,
      source: pointVectorSource
    });
    map.addLayer(vectorLayer);
    // 每隔1秒旋转10度
    let rotation = 0;
    setInterval(() => {
      rotation += 5 * Math.PI / 180;
      pointStyle.getImage().setRotation(rotation);
      pointFeature.setStyle(pointStyle);
    }, 100);
  }

  // 初始化地块图层
  initDKlayer (layerName, extent) {
    // 地块图层
    let projection = getProjection('EPSG:3857');
    let projectionExtent = projection.getExtent();
    var size = getWidth(projectionExtent) / 256;
    var resolutions = [];
    for (var z = 0; z < 20; ++z) {
      resolutions[z] = size / Math.pow(2, z);
    }
    const layer = new TileLayer({
      zIndex: 51,
      visible: true,
      source: new WMTS({
        url: '/geoserver/gwc/service/wmts',
        layer: layerName,
        matrixSet: 'EPSG:3857',
        format: 'image/png',
        projection: projection,
        tileGrid: new WMTSTileGrid({
          tileSize: [256, 256],
          resolutions: resolutions,
          origin: getTopLeft(projectionExtent),
          matrixIds: ['EPSG:3857:0', 'EPSG:3857:1', 'EPSG:3857:2', 'EPSG:3857:3', 'EPSG:3857:4', 'EPSG:3857:5',
            'EPSG:3857:6', 'EPSG:3857:7', 'EPSG:3857:8', 'EPSG:3857:9', 'EPSG:3857:10', 'EPSG:3857:11', 'EPSG:3857:12',
            'EPSG:3857:13', 'EPSG:3857:14', 'EPSG:3857:15', 'EPSG:3857:16', 'EPSG:3857:17', 'EPSG:3857:18', 'EPSG:3857:19',
            'EPSG:3857:20', 'EPSG:3857:21', 'EPSG:3857:22', 'EPSG:3857:23', 'EPSG:3857:24', 'EPSG:3857:25', 'EPSG:3857:26',
            'EPSG:3857:27', 'EPSG:3857:28', 'EPSG:3857:29', 'EPSG:3857:30'],
          extent: extent
        }),
        style: '',
        wrapX: false
      })
    });
    this.map.addLayer(layer);
    return layer;
  }

  /**
   * 根据一个带有经纬度,返回一个矢量图层
   * @param {*} dataList 带有经纬度的数组
   *  { type: type,
        geometry: [经度, 维度]
      }
   * @param {*} icon 图标
   */
  getVectorLayerByGeometrylist (dataList, icon, zIndex = 100) {
    let featureList = [];
    const style = new Style({
      image: new Icon({
        anchor: [0.5, 28],
        anchorXUnits: 'fraction',
        anchorYUnits: 'pixels',
        src: icon
      })
    });
    dataList.forEach(item => {
      const iconFeature = new Feature({
        _geometry: item.geometry,
        geometry: new Point(fromLonLat(item.geometry))
        // geometry: new Point(item.geometry)
      });
      iconFeature.setProperties(item.data);
      iconFeature.setStyle(style);
      featureList.push(iconFeature);
    });
    const source = new VectorSource({
      features: featureList
    });

    const iconLayer = new VectorLayer({
      zIndex,
      source: source
    });

    this.map.addLayer(iconLayer);
    return iconLayer;
  }

  /**
   * 加载geojson数据
   */
  loadGeojsonData (geoData) {
    const fs = new GeoJSON().readFeatures(geoData);
    this.mapSetFit(fs);
    let layer = this.getVectorLayerByFs(fs);
    return layer;
  }

  removeLayer (layer) {
    this.map.removeLayer(layer);
  }


  /**
   * 增删改查要素
   * @param {*} inserts 要插入的要素集合
   * @param {*} updates 要更新的要素集合
   * @param {*} deletes 要删除的要素集合
   * @param {*} layer 要操作的图层
   * @param {*} fs 
   */
  async crudFs (inserts = null, updates = null, deletes = null, layer = 'cwd2') {
    const geoserverData = {
      workSpaceName: 'qianguo',
      uri: 'http://124.235.241.109:8080/geoserver/qianguo',
      wfsURL: 'http://124.235.241.109:8080/geoserver/qianguo/ows?',
      layer: layer
    };
    let wfs = new WFS();

    let transact_xml = wfs.writeTransaction(
      inserts, updates, deletes,
      {
        version: '1.1.0',
        srsName: 'EPSG:3857',
        featureNS: geoserverData.uri,
        featurePrefix: geoserverData.workSpaceName,
        featureType: [geoserverData.layer],
      }
    );

    let transact_str = (new XMLSerializer()).serializeToString(transact_xml);

    let updStr = transact_str.replace(/geometry/g, 'the_geom');
    let res = await post('/geoserver/wfs', updStr);
    let transactRes = wfs.readTransactionResponse(res);

    let str = transactRes.transactionSummary.totalInserted +
      " totalInserted!, insertIds: " + transactRes.insertIds + "\n";
    str += transactRes.transactionSummary.totalUpdated + " totalUpdated!\n";
    str += transactRes.transactionSummary.totalDeleted + " totalDeleted!";

  }


}
export default GisUtils;
