import proj4 from 'proj4'
export interface GPS {
  lng: number
  lat: number
}

export interface PlaneXY {
  x: number
  y: number
}

export interface ThreeParams {
  dx: number
  dy: number
  dz: number
}

export interface SevenParams extends ThreeParams {
  rx: number // 秒
  ry: number
  rz: number
  scale: number // ppm
}

/**
 * 自动获取中央经线（三度带）
 */
function getDefaultCentralMeridian(lng: number, zoneWidth = 3): number {
  const zone = Math.floor(lng / zoneWidth) + 1
  return zone * zoneWidth
}

/**
 * 构建 proj4 投影字符串
 */
function buildProjString(
  coordSystem: 'CGCS2000' | '北京54',
  centralMeridian: number,
  towgs84: string
): string {
  const parts = [
    '+proj=tmerc',
    '+lat_0=0',
    `+lon_0=${centralMeridian}`,
    '+k=1.0',
    '+x_0=500000',
    '+y_0=0',
    coordSystem === 'CGCS2000' ? '+ellps=GRS80' : '+a=6378245.0',
    coordSystem === '北京54' ? '+b=6356863.0188' : '',
    `+towgs84=${towgs84}`,
    '+units=m',
    '+no_defs'
  ]
  return parts.filter(Boolean).join(' ')
}

/**
 * GPS → 平面（3参数）
 */
export function gpsToPlaneBy3Params(
  coordSystem: 'CGCS2000' | '北京54',
  params: ThreeParams,
  gps: GPS,
  centralMeridian?: number
): PlaneXY {
  const cm = centralMeridian ?? getDefaultCentralMeridian(gps.lng)
  const towgs84 = `${params.dx},${params.dy},${params.dz}`
  const projDef = buildProjString(coordSystem, cm, towgs84)
  const [x, y] = proj4('EPSG:4326', projDef, [gps.lng, gps.lat])
  return { x: parseFloat(x.toFixed(3)), y: parseFloat(y.toFixed(3)) }
}

/**
 * GPS → 平面（7参数）
 */
export function gpsToPlaneBy7Params(
  coordSystem: 'CGCS2000' | '北京54',
  params: SevenParams,
  gps: GPS,
  centralMeridian?: number
): PlaneXY {
  const cm = centralMeridian ?? getDefaultCentralMeridian(gps.lng)
  const { dx, dy, dz, rx, ry, rz, scale } = params
  const towgs84 = `${dx},${dy},${dz},${rx},${ry},${rz},${scale}`
  const projDef = buildProjString(coordSystem, cm, towgs84)
  const [x, y] = proj4('EPSG:4326', projDef, [gps.lng, gps.lat])
  return { x: parseFloat(x.toFixed(3)), y: parseFloat(y.toFixed(3)) }
}

/**
 * 平面 → GPS 坐标（反向投影）
 */
export function planeToGps(
  coordSystem: 'CGCS2000' | '北京54',
  params: ThreeParams | SevenParams,
  xy: PlaneXY,
  centralMeridian: number,
  isSevenParam = false
): GPS {
  const towgs84 = isSevenParam
    ? `${params.dx},${params.dy},${params.dz},${(params as SevenParams).rx},${
        (params as SevenParams).ry
      },${(params as SevenParams).rz},${(params as SevenParams).scale}`
    : `${params.dx},${params.dy},${params.dz}`

  const projDef = buildProjString(coordSystem, centralMeridian, towgs84)
  const [lng, lat] = proj4(projDef, 'EPSG:4326', [xy.x, xy.y])
  return { lng: parseFloat(lng.toFixed(8)), lat: parseFloat(lat.toFixed(8)) }
}
