/**
 * 坐标转换函数模块
 * 用于地图坐标转换和判断
 */

// @ts-nocheck - 为了与原始 u-charts 代码保持兼容性，跳过类型检查

/**
 * 经纬度转墨卡托坐标
 * @param longitude 经度
 * @param latitude 纬度
 * @returns 墨卡托坐标 [x, y]
 */
export function lonlat2mercator(
  longitude: number,
  latitude: number
): [number, number] {
  const mercator: [number, number] = [0, 0];
  const x = (longitude * 20037508.34) / 180;
  let y =
    Math.log(Math.tan(((90 + latitude) * Math.PI) / 360)) / (Math.PI / 180);
  y = (y * 20037508.34) / 180;
  mercator[0] = x;
  mercator[1] = y;
  return mercator;
}

/**
 * 墨卡托坐标转经纬度
 * @param longitude 墨卡托X坐标
 * @param latitude 墨卡托Y坐标
 * @returns 经纬度坐标 [x, y]
 */
export function mercator2lonlat(
  longitude: number,
  latitude: number
): [number, number] {
  const lonlat: [number, number] = [0, 0];
  const x = (longitude / 20037508.34) * 180;
  let y = (latitude / 20037508.34) * 180;
  y =
    (180 / Math.PI) *
    (2 * Math.atan(Math.exp((y * Math.PI) / 180)) - Math.PI / 2);
  lonlat[0] = x;
  lonlat[1] = y;
  return lonlat;
}

/**
 * 获取边界框
 * @param data GeoJSON数据
 * @returns 边界框对象
 */
export function getBoundingBox(
  data: Array<{ geometry: { coordinates: any[] } }>
): {
  xMin: number;
  xMax: number;
  yMin: number;
  yMax: number;
} {
  const bounds: any = {};
  let coords: any;
  bounds.xMin = 180;
  bounds.xMax = 0;
  bounds.yMin = 90;
  bounds.yMax = 0;

  for (let i = 0; i < data.length; i++) {
    const coorda = data[i].geometry.coordinates;
    for (let k = 0; k < coorda.length; k++) {
      coords = coorda[k];
      if (coords.length === 1) {
        coords = coords[0];
      }
      for (let j = 0; j < coords.length; j++) {
        const longitude = coords[j][0];
        const latitude = coords[j][1];
        const point = {
          x: longitude,
          y: latitude,
        };
        bounds.xMin = bounds.xMin < point.x ? bounds.xMin : point.x;
        bounds.xMax = bounds.xMax > point.x ? bounds.xMax : point.x;
        bounds.yMin = bounds.yMin < point.y ? bounds.yMin : point.y;
        bounds.yMax = bounds.yMax > point.y ? bounds.yMax : point.y;
      }
    }
  }
  return bounds;
}

/**
 * 坐标转点
 * @param latitude 纬度
 * @param longitude 经度
 * @param bounds 边界框
 * @param scale 缩放比例
 * @param xoffset X偏移
 * @param yoffset Y偏移
 * @returns 点坐标 {x, y}
 */
export function coordinateToPoint(
  latitude: number,
  longitude: number,
  bounds: { xMin: number; xMax: number; yMin: number; yMax: number },
  scale: number,
  xoffset: number,
  yoffset: number
): { x: number; y: number } {
  return {
    x: (longitude - bounds.xMin) * scale + xoffset,
    y: (bounds.yMax - latitude) * scale + yoffset,
  };
}

/**
 * 点转坐标
 * @param pointY 点Y坐标
 * @param pointX 点X坐标
 * @param bounds 边界框
 * @param scale 缩放比例
 * @param xoffset X偏移
 * @param yoffset Y偏移
 * @returns 坐标 {x, y}
 */
export function pointToCoordinate(
  pointY: number,
  pointX: number,
  bounds: { xMin: number; xMax: number; yMin: number; yMax: number },
  scale: number,
  xoffset: number,
  yoffset: number
): { x: number; y: number } {
  return {
    x: (pointX - xoffset) / scale + bounds.xMin,
    y: bounds.yMax - (pointY - yoffset) / scale,
  };
}

/**
 * 判断射线是否与线段相交
 * @param poi 点坐标
 * @param s_poi 线段起点
 * @param e_poi 线段终点
 * @returns 是否相交
 */
export function isRayIntersectsSegment(
  poi: number[],
  s_poi: number[],
  e_poi: number[]
): boolean {
  if (s_poi[1] === e_poi[1]) {
    return false;
  }
  if (s_poi[1] > poi[1] && e_poi[1] > poi[1]) {
    return false;
  }
  if (s_poi[1] < poi[1] && e_poi[1] < poi[1]) {
    return false;
  }
  if (s_poi[1] === poi[1] && e_poi[1] > poi[1]) {
    return false;
  }
  if (e_poi[1] === poi[1] && s_poi[1] > poi[1]) {
    return false;
  }
  if (s_poi[0] < poi[0] && e_poi[1] < poi[1]) {
    return false;
  }
  const xseg =
    e_poi[0] -
    ((e_poi[0] - s_poi[0]) * (e_poi[1] - poi[1])) / (e_poi[1] - s_poi[1]);
  if (xseg < poi[0]) {
    return false;
  } else {
    return true;
  }
}

/**
 * 判断点是否在多边形内
 * @param poi 点坐标
 * @param poly 多边形坐标数组
 * @param mercator 是否使用墨卡托投影
 * @returns 是否在多边形内
 */
export function isPoiWithinPoly(
  poi: number[],
  poly: number[][][],
  mercator: boolean
): boolean {
  let sinsc = 0;
  for (let i = 0; i < poly.length; i++) {
    let epoly = poly[i][0];
    if (poly.length === 1) {
      epoly = poly[i][0];
    }
    for (let j = 0; j < epoly.length - 1; j++) {
      let s_poi = epoly[j];
      let e_poi = epoly[j + 1];
      if (mercator) {
        s_poi = lonlat2mercator(epoly[j][0], epoly[j][1]) as any;
        e_poi = lonlat2mercator(epoly[j + 1][0], epoly[j + 1][1]) as any;
      }
      if (isRayIntersectsSegment(poi, s_poi as number[], e_poi as number[])) {
        sinsc += 1;
      }
    }
  }
  if (sinsc % 2 === 1) {
    return true;
  } else {
    return false;
  }
}
