import sourceWMTS from "ol/source/WMTS";
import WMTSTileGrid from "ol/tilegrid/WMTS";
import * as olExtent from "ol/extent";
import TileLayer from "ol/layer/Tile";
import XYZ from "ol/source/XYZ.js";
import { WKT } from "ol/format";
import BufferOp from "jsts/org/locationtech/jts/operation/buffer/BufferOp.js";
import { OL3Parser } from "jsts/org/locationtech/jts/io";
import * as geom from "ol/geom";
import Feature from "ol/Feature";

const jstsParser = new OL3Parser();
jstsParser.inject(
  geom.Point,
  geom.LineString,
  geom.LinearRing,
  geom.Polygon,
  geom.MultiPoint,
  geom.MultiLineString,
  geom.MultiPolygon
);

function CodeToRGB(code) {
  const result = [];
  result.push(parseInt(code.substring(1, 3), 16));
  result.push(parseInt(code.substring(3, 5), 16));
  result.push(parseInt(code.substring(5), 16));
  return result;
}

function createGDWmts() {
  return new TileLayer({
    source: new XYZ({
      url: "http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}",
    }),
    visible: false,
  });
}

function crtLayerWMTS(wmtsData, opacity, projection) {
  const projectionExtent = projection.getExtent();
  const size = olExtent.getWidth(projectionExtent) / 256;
  const resolutions = new Array(19);
  const matrixIds = new Array(19);
  for (let z = 1; z < 19; ++z) {
    resolutions[z] = size / Math.pow(2, z);
    matrixIds[z] = z;
  }

  const source = new sourceWMTS({
    url: wmtsData.url,
    layer: wmtsData.layer,
    matrixSet: wmtsData.matrixSet,
    format: "tiles",
    projection: projection,
    crossOrigin: "anonymous",
    tileGrid: new WMTSTileGrid({
      origin: olExtent.getTopLeft(projectionExtent),
      resolutions: resolutions,
      matrixIds: matrixIds,
    }),
    style: "default",
    wrapX: true,
  });

  const layer = new TileLayer({
    zIndex: wmtsData.zIndex,
    source: source,
    visible: true,
    opacity: opacity ?? 1,
  });
  layer.id = wmtsData.layer + "_" + wmtsData.matrixSet;
  return layer;
}

function wktCastGeom(wkt) {
  return new WKT().readGeometry(wkt);
}

function fit(wkt, view, zoom) {
  const extent = wktCastGeom(wkt).getExtent();
  extent[0] = extent[0] / zoom;
  extent[1] = extent[1] / zoom;
  extent[2] = extent[2] * zoom;
  extent[3] = extent[3] * zoom;
  view.fit(extent, { duration: 700 });
}

function fitExtent(extent, view, zoom) {
  const extent2 = [];
  extent2[0] = extent[0] / zoom;
  extent2[1] = extent[1] / zoom;
  extent2[2] = extent[2] * zoom;
  extent2[3] = extent[3] * zoom;
  view.fit(extent2, { duration: 700 });
}

const fitBuffer = (pointWkt, map, meter) => {
  let geometry = new WKT().readGeometry(pointWkt);
  const degree = (meter / (2 * Math.PI * 6371004)) * 360;
  geometry = jstsParser.write(BufferOp.bufferOp(jstsParser.read(geometry), degree, 8));
  map.getView().fit(geometry, { duration: 1000 });
};

const newAreaFeature = (data, fieldGeom) => {
  const geometry = new WKT().readGeometry(data[fieldGeom || "geom"]);
  const feature = new Feature({ geometry });
  feature.set("nodeType", "area");
  feature.setId(data.id);
  for (const key in data) {
    if (key != "geom") {
      feature.set(key, data[key]);
    }
  }
  return feature;
};

export {
  crtLayerWMTS,
  CodeToRGB,
  createGDWmts,
  wktCastGeom,
  fit,
  fitBuffer,
  fitExtent,
  newAreaFeature,
};
