// 高德地图key
export const GAODE_MAP_KEY = import.meta.env.VITE_AMAP_KEY

// 获取地图实例
export function getMapContext(mapid: string, instance: any) {
  return uni.createMapContext(mapid, {
    this: instance.proxy,
  })
}

// 获取当前定位
export function getLoalcation({
  mapContext,
  success = null,
  fail = null,
  moveCenter = false,
}) {
  uni.getLocation({
    type: 'gcj02',
    geocode: true,
    success(res) {
      console.log('定位成功', res)
      const { latitude, longitude } = res
      if (moveCenter && mapContext) {
        moveToLocation(mapContext, longitude, latitude)
      }
      success && success({ latitude, longitude })
    },
    fail(err) {
      console.error('uni.getLocation-------', err)
      fail && fail(err)
    },
  })
}

// 移至中心点
export function moveToLocation(mapContext: any, longitude: number, latitude: number) {
  const point = {
    latitude,
    longitude,
  }
  mapContext.moveToLocation(point)
}

/**
 * 添加线
 * @param sColor 线颜色
 * @param arrPoint 线坐标
 * @param width 线宽度
 * @param arrowLine 是否有箭头
 */
export function addLine({
  sColor,
  arrPoint,
  width = 4,
  arrowLine = false,
}: {
  sColor: string
  arrPoint: any[]
  width?: number
  arrowLine?: boolean
}) {
  return {
    points: arrPoint,
    color: sColor,
    width,
    arrowLine,
  }
}

/**
 * 获取路径规划
 * @param mapsdk 高德地图sdk实例
 * @param slng 起点经度
 * @param slat 起点纬度
 * @param elng 终点经度
 * @param elat 终点纬度
 * @param success 成功回调
 * @param fail 失败回调
 */
export function getRoutePlan({
  mapsdk,
  slng,
  slat,
  elng,
  elat,
  success,
  fail,
}: {
  mapsdk: any
  slng: number
  slat: number
  elng: number
  elat: number
  success: (res: any) => void
  fail: (err: any) => void
}) {
  // 检测 mapsdk 实例是否存在
  if (!mapsdk) {
    fail && fail('mapsdk实例不存在')
    console.error('mapsdk实例不存在')
    return
  }
  // 判断经纬度是否齐全
  if (!slng || !slat || !elng || !elat) {
    fail && fail('经纬度参数不完整')
    console.error('经纬度参数不完整')
    return
  }

  const options = {
    origin: `${slng},${slat}`,
    destination: `${elng},${elat}`,
    success: (res: any) => {
      const points = []
      let distance = 0
      if (res?.paths[0]?.steps) {
        const steps = res.paths[0].steps
        distance = res.paths[0].distance

        for (let i = 0; i < steps.length; i++) {
          const poLen = steps[i].polyline.split(';')
          for (let j = 0; j < poLen.length; j++) {
            points.push({
              longitude: Number.parseFloat(poLen[j].split(',')[0]),
              latitude: Number.parseFloat(poLen[j].split(',')[1]),
            })
          }
        }
      }

      const cnt = (distance / 1000).toFixed(2)
      let sdistance = `${distance}m`

      if (Number.parseFloat(cnt) >= 1) {
        sdistance = `${cnt} km`
      }
      const data = {
        arrPoint: points,
        distance: sdistance,
      }
      if (success)
        success(data)
    },
    fail: (error: any) => {
      fail && fail(error)
    },
  }

  mapsdk.getDrivingRoute(options)
}

/**
 * 逆解析地址
 * @param {object} options
 * @param {object} options.mapsdk - 地图对象
 * @param {number} options.longitude - 经度
 * @param {number} options.latitude - 纬度
 * @param {Function} options.success - 成功回调
 * @param {Function} options.fail - 失败回调
 */

export function reverseGeocoder({
  mapsdk,
  longitude,
  latitude,
  success,
  fail,
}: {
  mapsdk: any
  longitude: number
  latitude: number
  success: (data: any) => void
  fail: (error: any) => void
}) {
  if (!mapsdk) {
    console.error('请传入地图sdk')
    fail && fail('请传入地图sdk')
    return
  }

  if (!longitude || !latitude) {
    console.error('请传入经纬度')
    fail && fail('请传入经纬度')
    return
  }
  mapsdk.getRegeo({
    location: `${longitude},${latitude}`,
    success(res: any) {
      console.log(res)
      const { desc, regeocodeData, latitude, longitude } = res[0]
      success && success({
        desc,
        regeocodeData,
        latitude,
        longitude,
      })
    },
    fail(err: any) {
      console.log(err, '地理位置信息失败')
      fail && fail(err)
    },
  })
}

/**
 *绘制区域
 * @param {object} options
 * @param {Array} options.point - 区域点
 * @param {boolean} options.isFormat - 是否格式化(处理经纬度)
 * @param {Function} options.success - 成功回调函数
 * @param {Function} options.fail - 失败回调函数
 * @param {any} options.option - 配置
 */
export function drawRegion({
  point,
  isFormat = false,
  success,
  fail,
  option = {
    strokeWidth: 2,
    strokeColor: '#4595f8',
    fillColor: '#b7dff299',
    level: 'abovelabels', // abovelabels 显示在所有 POI 之上 abovebuildings 显示在楼块之上 POI 之下
  },
}: {
  point: any
  isFormat?: boolean
  option?: any
  success: (data?: any) => void
  fail: (err?: any) => void
}) {
  let obj = {
    point: [],
  }

  if (!point) {
    fail && fail('point参数不能为空')
    return
  }

  // 格式化数据(判断数据是不是二维数组)
  if (isFormat) {
    if (Array.isArray(point) && point.length > 0 && point.every(item => Array.isArray(item))) {
      const points = point.map((item: any) => ({
        latitude: item[1],
        longitude: item[0],
      }))
      obj = {
        points,
        ...option,
      }
    }
  }
  else {
    obj = {
      points: point,
      ...option,
    }
  }

  success && success(obj)
}

/**
 *绘制点位
 * @param {object} param
 * @param {Array} param.point
 * @param {object} param.option
 * @param {boolean} param.isSoc
 * @param {Function} param.success
 * @param {Function} param.fail
 *
 */
//  iconPath: '/static/images/carImage.png',
//  iconPath: '/static/images/markerH.png',
export function drawPoint({
  point,
  type = 'none',
  option = {
    width: 35,
    height: 35,
    iconPath: '/static/images/markerG.png',
  },
  success,
  fail,
}: {
  type?: 'none' | 'charge' | 'dispatch' | 'polling' | 'maintain'
  // 工具的类型
  point: {
    id?: number
    bikeCode?: string
    latitude: number
    longitude: number
    soc?: number
    online?: boolean
    bikeInfo?: any
  }
  option?: any
  success: (res: any) => void
  fail: (res: any) => void
}) {
  // console.log(point, '------------>point')
  // console.log(type, '------------>type')

  let obj = {}

  if (!point) {
    fail && fail('point参数不能为空')
    return
  }

  switch (type) {
    case 'charge': {
      obj = setChargePoint(point, option)
      break
    }
    case 'dispatch': {
      obj = setDispatchPoint(point, option)
      break
    }
    default: {
      obj = commonPoint(point, option)
      break
    }
  }
  success && success(obj)
}

// 换电点位设置
function setChargePoint(point: any, option: any) {
  const { soc, online } = point
  const obj = {
    id: Number(point.bikeCode),
    latitude: point.latitude,
    longitude: point.longitude,
    width: 40,
    height: 40,
    label: {
      anchorY: -32,
      anchorX: -11,
      fontSize: 10,
      color: '#0dc31b',
    },
  }

  if (!online) {
    return {
      ...obj,
      iconPath: '/static/images/markerL.png',
      label: {
        ...obj.label,
        content: '离线',
        color: '#d81e06',
      },
    }
  }
  if (soc >= 0 && soc < 20) {
    return {
      ...obj,
      iconPath: '/static/images/markerL.png',
      label: {
        ...obj.label,
        content: `${point.soc}%`,
        color: '#d81e06',
      },
    }
  }
  if (soc >= 20 && soc < 70) {
    return {
      ...obj,
      iconPath: '/static/images/markerM.png',
      label: {
        ...obj.label,
        content: `${point.soc}%`,
        color: '#e16530',
      },
    }
  }
  if (soc >= 70 && soc <= 100) {
    return {
      ...obj,
      iconPath: '/static/images/markerH.png',
      label: {
        ...obj.label,
        content: `${point.soc}%`,
        color: '#0dc31a',
      },
    }
  }
}

// 调度点位设置
export function setDispatchPoint(point: any, option: any) {
  const { bikeInfo } = point
  console.log(bikeInfo)

  const obj = {
    id: Number(point.bikeCode),
    latitude: point.latitude,
    longitude: point.longitude,
    width: 43,
    height: 43,
    iconPath: '/static/images/markerG.png',
    label: {
      content: bikeInfo.content,
      anchorY: -32,
      anchorX: -12,
      fontSize: 9,
      color: '#0e82ff',
    },
  }

  return obj
}

// 通用点位设置
export function commonPoint(point: any, option: any) {
  return {
    id: point.id,
    latitude: point.latitude,
    longitude: point.longitude,
    ...option,
  }
}

/**
 * 判断点是否在多边形内
 * @param point 当前点
 * @param polygon 多边形
 * @returns {boolean}
 */
export function isPointInPolygon(
  point: { latitude: number, longitude: number },
  polygon: Array<{ latitude: number, longitude: number }>,
) {
  if (!point || !polygon || polygon.length < 3)
    return false

  const { latitude: y, longitude: x } = point
  let inside = false

  for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
    const xi = polygon[i].longitude
    const yi = polygon[i].latitude
    const xj = polygon[j].longitude
    const yj = polygon[j].latitude

    // 判断点是否在线段上下方（y方向）
    const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi)

    if (intersect)
      inside = !inside
  }

  return inside
}

/**
 * 判断多边形是否自相交
 * @param {Array<{latitude: number, longitude: number}>} points - 点数组（无需闭合）
 * @returns {boolean}
 */
export function isPolygonSelfIntersecting(points) {
  if (points.length < 4)
    return false // 至少4个点才可能自交

  // 转换为 [lng, lat] 格式，并闭合
  const coords = points.map(p => [p.longitude, p.latitude])
  coords.push(coords[0]) // 闭合多边形

  const n = coords.length - 1 // 实际边数（最后一点是重复的）

  for (let i = 0; i < n; i++) {
    for (let j = i + 1; j < n; j++) {
      // 跳过相邻边（共享顶点）
      if (j === i + 1)
        continue
      // 跳过首尾相连的边（第一个和最后一个边）
      if (i === 0 && j === n - 1)
        continue

      const a1 = coords[i]
      const a2 = coords[i + 1]
      const b1 = coords[j]
      const b2 = coords[j + 1]

      if (lineSegmentsIntersect(a1, a2, b1, b2)) {
        return true
      }
    }
  }
  return false
}

/**
 * 判断两条线段是否相交（含端点相交）
 */
function lineSegmentsIntersect(p1, p2, p3, p4) {
  const d1 = direction(p3, p4, p1)
  const d2 = direction(p3, p4, p2)
  const d3 = direction(p1, p2, p3)
  const d4 = direction(p1, p2, p4)

  // 一般相交情况
  if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0))
    && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) {
    return true
  }

  // 处理共线且重叠的情况（可选，通常可忽略）
  if (d1 === 0 && onSegment(p3, p4, p1))
    return true
  if (d2 === 0 && onSegment(p3, p4, p2))
    return true
  if (d3 === 0 && onSegment(p1, p2, p3))
    return true
  if (d4 === 0 && onSegment(p1, p2, p4))
    return true

  return false
}

function direction(a, b, c) {
  return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])
}

function onSegment(a, b, c) {
  return Math.min(a[0], b[0]) <= c[0] && c[0] <= Math.max(a[0], b[0])
    && Math.min(a[1], b[1]) <= c[1] && c[1] <= Math.max(a[1], b[1])
}
