<template>
  <div class="map-wrapper">
    <div class="mapParent" id="mapParent"
      :style="{ backgroundColor: backgroundColor, lineHeight: height }">
      <span class="maptext">
        <span v-if="textShow">请选择地图</span>
        <br>
      </span>
    </div>
    <div id="tooltip" class="tooltip">
      <div class="tooltip-header">
        <i class="el-icon-location"></i>
        <span class="tooltip-title">添加目标点</span>
      </div>
      <div id="tooltip-content" class="tooltip-content"></div>
      <div class="tooltip-actions">
        <el-button type="primary" size="small" @click="addNowPoint" class="action-btn">
          <i class="el-icon-check"></i>
          添加点位
        </el-button>
        <el-button size="small" @click="clearNowPoint" class="action-btn">
          <i class="el-icon-close"></i>
          取消添加
        </el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch, nextTick, computed } from 'vue'
import 'ol/ol.css'
import Map from 'ol/Map'
import View from 'ol/View'
import Overlay from 'ol/Overlay';
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import XYZ from 'ol/source/XYZ'
import Projection from 'ol/proj/Projection'
import GeoJSON from 'ol/format/GeoJSON'
import Feature from 'ol/Feature'
import Point from 'ol/geom/Point'
import SrcXYZ from "ol/source/XYZ";
import { fromLonLat } from 'ol/proj'
import MultiPoint from 'ol/geom/MultiPoint'
import LineString from 'ol/geom/LineString'
import { Style, Stroke, Fill, Circle, Icon, Text } from 'ol/style'
import { defaults as defaultControls } from 'ol/control'
import { defaults as defaultInteractions, DragRotateAndZoom, Draw, Modify, Snap } from 'ol/interaction'
import { easeOut, inAndOut } from 'ol/easing'
import { getTilemapDetails, getRoadMapGeoJson, getPointcloud } from '@/api/robot/map'
import { ElMessage } from 'element-plus'

// 地图文件地址url
const fileUrl = import.meta.env.VUE_APP_MAP_FILE_URL || 'http://192.168.0.102:8086'

// 计算属性：地图服务地址
const url = computed(() => {
  return fileUrl
})

const props = defineProps({
  mapName: {
    type: String,
    required: true
  },
  pointSwitchShow: {
    type: Boolean,
    default: true
  },
  pointSwitchStatus: {
    type: Boolean,
    default: false
  },
  textShow: {
    type: Boolean,
    default: true
  },
  content: {
    type: String,
    default: ""
  },
  backgroundColor: {
    type: String,
    default: "#d5d8e1"
  },
  height: {
    type: String,
    default: "365px"
  },
  width: {
    type: String,
    default: "365px"
  },
  zoom: {
    type: Number,
    default: 2
  },
  showDefaultControls: {
    type: Boolean,
    default: true
  },
  minZoom: {
    type: Number,
    default: 1
  },
  pointSwitch: {
    type: Boolean,
    default: false
  },
  baseLayerShow: {
    type: Boolean,
    default: true
  },
  pointSelectionEnabled: {
    type: Boolean,
    default: false
  },
  pointDraSelectEnabled: {
    type: Boolean,
    default: false
  },
  poseInitEnable: {
    type: Boolean,
    default: false
  },
  pointEvent: {
    type: Function,
    default: () => { }
  },
  robotPoseData: {
    type: Object,
    required: false,
    default: function () {
      return { x: 0, y: 0, angle: 0 }
    }
  },
  existPointShow: {
    type: Boolean,
    default: false
  },
  routeIndex: {
    type: Number,
    default: -1
  },
  isRobotFollow: {
    type: Boolean,
    default: false
  },
  poseCalibrationIndex: {
    type: Number,
    default: 0
  },
  isShowRobot: {
    type: Boolean,
    default: true
  },
  showPointcloud: {
    type: Boolean,
    default: false
  },
  showRoadNetwork: {
    type: Boolean,
    default: true
  }
})

const emit = defineEmits([
  'addNowPoint',
  'elementRoadInitEnd',
  'elementRoadDrawEnd',
  'removeElementResult',
  'selectShowEleResult',
  'initNavigationResult',
  'point-cloud-load-end',
  'togglePointSelection'
])

// ==================== 响应式数据 ====================
const map = ref(null)
const config_json = ref("")
const geojson_data = ref("")
const robot_src = ref(null)
const pose = ref({ x: 0, y: 0, angle: 0 })
const oldRobotCode = ref("")
const baseLayer = ref(null)
const pointAll = ref([])
const currentPlace = ref([])
const currentCoordinate = ref([])
const maxIndex = ref(0)
const icon_src = ref(null)
const roadmap_src = ref(null)
const roadmapLayer = ref(null)
const maxPointIdNum = ref(0)
const maxLineIdNum = ref(0)
const maxBowNum = ref(0)
const maxPolygonNum = ref(0)
const selectedFeatureId = ref('')
const previewFeature = ref(null)
const arrowFeature = ref(null)
const calibrationList = ref([])
const trajectorySource = ref(null)
const currentTrajectory = ref(null)
const trajectoryProgress = ref(0)
const pointcloudLayer = ref(null)
const pointcloudTimer = ref(null)
const aiAlarmList = ref([])

// Drawing tools
const draw = ref(null)
const snap = ref(null)
const modify = ref(null)

// Icons
const icon = ref({
  mark: 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(`
    <svg width="22" height="22" xmlns="http://www.w3.org/2000/svg">
      <circle cx="11" cy="11" r="10" fill="#4096BD" stroke="white" stroke-width="2"/>
    </svg>
  `),
  point: 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(`
    <svg width="20" height="20" xmlns="http://www.w3.org/2000/svg">
      <circle cx="10" cy="10" r="8" fill="#00BFFF" stroke="white" stroke-width="2"/>
    </svg>
  `),
  robot: 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(`
    <svg width="40" height="40" xmlns="http://www.w3.org/2000/svg">
      <polygon points="20,2 38,35 20,28 2,35" fill="#FF5722" stroke="#fff" stroke-width="2"/>
    </svg>
  `)
})

// ==================== 生命周期 ====================
onMounted(() => {
  nextTick(() => {
    loadMap()
  })
})

onBeforeUnmount(() => {
  stopPointcloudUpdate()
  if (map.value) {
    map.value.setTarget(null)
  }
})

// ==================== 监听器 ====================
watch(() => props.baseLayerShow, (newVal) => {
  if (newVal !== undefined && baseLayer.value) {
    console.log("newVal:", newVal);
        console.log("baseLayer:", baseLayer.value);

    baseLayer.value.setVisible(newVal)
  }
})

watch(() => props.pointSelectionEnabled, (newVal) => {
  const mapElement = document.querySelector('.tileMap')
  if (mapElement) {
    mapElement.style.cursor = newVal ? 'pointer' : 'default'
  }
})

watch(() => props.pointDraSelectEnabled, (newVal) => {
  const mapElement = document.querySelector('.tileMap')
  if (mapElement) {
    mapElement.style.cursor = newVal ? 'pointer' : 'default'
  }
})

watch(() => props.isRobotFollow, (newVal) => {
  if (newVal) {
    followRotation()
  } else if (map.value) {
    map.value.getView().setRotation(0)
  }
})

watch(() => props.robotPoseData, (newVal) => {
  if (newVal) {
    robotPoseUpdateCallback(newVal.x, newVal.y, newVal.angle)
  }
}, { deep: true })

watch(() => props.poseCalibrationIndex, (index) => {
  if (index < 0) {
    const id = Math.abs(index)
    removeCalibrationById(id)
  } else {
    const newId = calibrationList.value.length + 1
    const point = { id: newId, x: props.robotPoseData.x, y: props.robotPoseData.y }
    calibrationList.value.push(point)
    refreshCalibrationOverlays()
  }
})

watch(() => props.poseInitEnable, (newVal) => {
  const mapElement = document.querySelector('.tileMap')
  if (mapElement) {
    mapElement.style.cursor = newVal ? 'pointer' : 'default'
  }
})

watch(() => props.showPointcloud, (newVal) => {
  if (pointcloudLayer.value) {
    pointcloudLayer.value.setVisible(newVal)
    if (newVal) {
      startPointcloudUpdate()
    } else {
      stopPointcloudUpdate()
      const features = pointcloudLayer.value.getSource().getFeatures()
      if (features.length > 0) {
        features[0].setGeometry(new MultiPoint([]))
      }
    }
  }
})

watch(() => props.showRoadNetwork, (newVal) => {
  if (roadmapLayer.value) {
    roadmapLayer.value.setVisible(newVal)
  }
})

// 监听地图名称变化，重新加载地图
watch(() => props.mapName, (newMapName) => {
  if (newMapName) {
    nextTick(() => {
      loadMap()
    })
  }
})

// 监听地图尺寸变化，重新设置地图大小
watch([() => props.width, () => props.height], () => {
  nextTick(() => {
    updateMapSize()
  })
})

// ==================== 方法 ====================

// 点击添加点位的操作
function addNowPoint() {
  emit('addNowPoint', currentCoordinate.value, currentPlace.value)
  hideToop()
  addHtmlIcon(currentCoordinate.value[0], currentCoordinate.value[1], currentCoordinate.value[2], icon.value.mark, "pose")
}

// 点击取消点位的操作
function clearNowPoint() {
  hideToop()
  currentCoordinate.value = []
  currentPlace.value = []
}

// 加载地图数据
async function loadMap() {
  console.log("[OlMap] loadMap 开始, mapName:", props.mapName)

  if (!props.mapName) {
    setMapText('请选择地图')
    return
  }

  // 清理旧地图数据
  if (map.value) {
    map.value.setTarget(null)
    map.value = null
  }
  if (roadmap_src.value) {
    roadmap_src.value.clear()
    roadmap_src.value = null
  }
  roadmapLayer.value = null
  config_json.value = ""
  geojson_data.value = ""
  selectedFeatureId.value = ''
  maxPointIdNum.value = 0
  maxLineIdNum.value = 0
  maxBowNum.value = 0
  maxPolygonNum.value = 0
  calibrationList.value = []

  try {
    const configRes = await getTilemapDetails(props.mapName)
    config_json.value = configRes

    const geojsonRes = await getRoadMapGeoJson(props.mapName)
    // Handle both direct geojson and wrapped response
    geojson_data.value = geojsonRes.data || geojsonRes
    console.log("初始化");
    initMapHaveDate()
    initRoad(geojson_data.value)
  } catch (e) {
    setMapText('加载地图错误')
    console.error('加载地图失败:', e)
  }
}

// 设置中心的文字
function setMapText(str = '') {
  str = str == "" ? '加载地图错误' : str
  const obj = document.getElementById("mapParent")
  if (obj) {
    obj.innerHTML = `<span class='maptext' style='font-size: 20px;color: grey;height: 100%'>${str}</span>`
  }
}

// 初始化地图(有数据)
function initMapHaveDate() {
  
  if (!config_json.value || config_json.value == "") return

  const mapNode = document.getElementById("tileMap")
  if (mapNode) {
    document.getElementById("mapParent").removeChild(mapNode)
  }

  const parent = document.getElementById("mapParent")
  const div = document.createElement('div')
  div.id = 'tileMap'
  div.className = 'tileMap'
  parent.innerHTML = ''
  parent.appendChild(div)

  initMap(config_json.value)

  if (props.isShowRobot) {
    initRobot()
  }
}

// 初始化地图
function initMap(config) {
  if (!config || config == "") {
    console.warn("[OlMap] initMap: config 为空")
    return
  }

  // console.log("[OlMap] initMap 开始, config:", JSON.stringify(config, null, 2))

  const tile_param = {
    layer_cnt: config.layer_cnt,
    min_zoom: config.min_zoom,
    max_zoom: config.max_zoom,
    projection: config.projection
  }

  console.log("[OlMap] tile_param:", tile_param)

  let startPoint = null
  let isDrawing = false

  map.value = new Map({
    target: "tileMap",
    layers: [],
    view: null,
    interactions: defaultInteractions({
      dragRotate: false,
      dragZoom: false
    }),
    controls: props.showDefaultControls ? defaultControls() : []
  })

  // Map click event
  map.value.on('click', (evt) => {
    console.log("执行点击");
    
    // 点位选择模式
    if (props.pointSelectionEnabled) {
      let feature = map.value.forEachFeatureAtPixel(evt.pixel, (f) => f)
      let xy
      if (feature && (feature.values_.id || feature.getId()) && feature.getGeometry().getType() === 'Point') {
        xy = feature.getGeometry().getCoordinates()
      } else {
        xy = evt.coordinate
      }

      const tooltipContent = document.getElementById('tooltip-content')
      tooltipContent.innerHTML = ''
      tooltipContent.innerHTML += `<p>确认在此位置添加目标点？</p>`
      tooltipContent.innerHTML += `<p>X: ${xy[0].toFixed(3)}, Y: ${xy[1].toFixed(3)}</p>`

      const tooltip = document.getElementById('tooltip')
      tooltip.style.display = 'block'
      tooltip.style.left = (evt.pixel[0] + 70) + 'px'
      tooltip.style.top = evt.pixel[1] + 'px'

      maxIndex.value++
      currentCoordinate.value = [maxIndex.value, xy[0], xy[1], xy[2] || 0]
      currentPlace.value = evt.pixel
    }

    // 位姿初始化模式
    if (props.poseInitEnable) {
      let feature = map.value.forEachFeatureAtPixel(evt.pixel, (f) => f)
      let coord
      let nid = feature && feature.getId ? feature.getId() : null

      if (feature && feature.getGeometry().getType() === 'Point') {
        coord = feature.getGeometry().getCoordinates()
      } else {
        coord = evt.coordinate
      }

      if (!isDrawing) {
        startPoint = coord
        isDrawing = true
        ElMessage({ message: '起点已设置，请点击第二个位置确定机器人朝向（或右键取消）', type: 'info', duration: 3000 })
      } else {
        completeDrawing(startPoint, coord, nid)
        if (arrowFeature.value) {
          roadmap_src.value.removeFeature(arrowFeature.value)
          arrowFeature.value = null
        }
        if (previewFeature.value) {
          roadmap_src.value.removeFeature(previewFeature.value)
          previewFeature.value = null
        }
        isDrawing = false
        startPoint = null
      }
    }

    // 编辑页面元素选择模式
    if (props.pointDraSelectEnabled) {
      let feature = map.value.forEachFeatureAtPixel(evt.pixel, (f) => f)
      editElementSelectHandle(feature)
    }
  })

  // Mouse move for pose init preview
  map.value.on('pointermove', (evt) => {
    if (props.poseInitEnable && isDrawing && startPoint) {
      const endPoint = evt.coordinate

      if (!previewFeature.value) {
        const line = new LineString([startPoint, endPoint])
        previewFeature.value = new Feature(line)
        previewFeature.value.setStyle(new Style({
          stroke: new Stroke({ color: 'rgba(255, 50, 50, 0.8)', width: 5, lineDash: [10, 5] })
        }))
        roadmap_src.value.addFeature(previewFeature.value)

        arrowFeature.value = new Feature({ geometry: new LineString([startPoint, endPoint]) })
        arrowFeature.value.setStyle(new Style({
          renderer: (pixelCoordinates, state) => {
            const context = state.context
            const [startX, startY] = pixelCoordinates[0]
            const [endX, endY] = pixelCoordinates[1]
            const dx = endX - startX
            const dy = endY - startY
            const length = Math.sqrt(dx * dx + dy * dy)
            if (length < 10) return

            const angle = Math.atan2(dy, dx)
            const arrowLength = 25
            const arrowAngle = Math.PI / 6
            const tipX = endX, tipY = endY
            const leftX = tipX - arrowLength * Math.cos(angle - arrowAngle)
            const leftY = tipY - arrowLength * Math.sin(angle - arrowAngle)
            const rightX = tipX - arrowLength * Math.cos(angle + arrowAngle)
            const rightY = tipY - arrowLength * Math.sin(angle + arrowAngle)

            context.beginPath()
            context.moveTo(tipX, tipY)
            context.lineTo(leftX, leftY)
            context.lineTo(rightX, rightY)
            context.closePath()
            context.fillStyle = 'rgba(255, 50, 50, 0.9)'
            context.fill()
            context.strokeStyle = 'rgba(200, 0, 0, 1)'
            context.lineWidth = 2
            context.stroke()

            context.beginPath()
            context.arc(startX, startY, 6, 0, 2 * Math.PI)
            context.fillStyle = 'rgba(50, 150, 255, 0.8)'
            context.fill()
            context.strokeStyle = 'rgba(0, 100, 200, 1)'
            context.lineWidth = 2
            context.stroke()
          }
        }))
        roadmap_src.value.addFeature(arrowFeature.value)
      } else {
        previewFeature.value.getGeometry().setCoordinates([startPoint, endPoint])
        arrowFeature.value.getGeometry().setCoordinates([startPoint, endPoint])
      }
    }
  })

  // Right-click to cancel pose init
  map.value.on('contextmenu', (evt) => {
    if (props.poseInitEnable && isDrawing) {
      evt.preventDefault()
      if (previewFeature.value) {
        roadmap_src.value.removeFeature(previewFeature.value)
        previewFeature.value = null
      }
      if (arrowFeature.value) {
        roadmap_src.value.removeFeature(arrowFeature.value)
        arrowFeature.value = null
      }
      isDrawing = false
      startPoint = null
      ElMessage({ message: '位姿初始化已取消', type: 'warning', duration: 2000 })
    }
  })

  // 从配置获取地图参数
  const extent = tile_param.projection.extent
  const centerX = (extent[0] + extent[2]) / 2  // 地图X中心
  const centerY = (extent[1] + extent[3]) / 2  // 地图Y中心

  // 创建投影
  const projection = new Projection({
    extent: extent
  })

  // Set view - 居中显示整个地图
  map.value.setView(new View({
    projection: projection,
    center: [centerX, centerY],
    zoom: tile_param.min_zoom,
    minZoom: tile_param.min_zoom,
    maxZoom: tile_param.max_zoom
  }))
// 在 initMap 函数中，在创建 XYZ source 之前添加
const originalTileUrl = `/v1/tilemap/tile/${props.mapName}/{z}/{x}/{y}`
console.log('[调试] 瓦片URL模板:', originalTileUrl)


  // Create base tile layer - use proxy path to avoid CORS issues
  // URL格式符合OSM标准: {z}/{x}/{y} -> 后端接口: /v1/tilemap/tile/{mapName}/{z}/{x}/{y}
  const tileUrl = `/v1/tilemap/tile/${props.mapName}/{z}/{x}/{y}`
  // const tileUrl = `http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}`
  console.log("[OlMap] 初始化瓦片图层, URL:", tileUrl)
  console.log("[OlMap] mapName:", props.mapName)
  console.log("[OlMap] tile_param:", tile_param)
  console.log("[OlMap] extent:", extent)

  baseLayer.value = new TileLayer({
    source: new XYZ({
      url: tileUrl,
      projection: projection,
      wrapX: false,
      extent: extent,
    })
  })
// 在创建 TileLayer 后，监听 tile loadstart 事件
baseLayer.value.getSource().on('tileloadstart', function(event) {
  const coord = event.tile.tileCoord
  console.log('coord', coord)
  if (coord) {
    console.log('[瓦片请求]', {
      z: coord[0],
      x: coord[1],
      y: coord[2],
      url: event.tile.src_
    })
  }
})
  baseLayer.value.getSource().on('tileloadstart', function(event) {
    console.log('开始加载瓦片')
  })
  // 监听瓦片加载错误
  baseLayer.value.getSource().on('tileloaderror', function(event) {
    console.error("[OlMap] 瓦片加载失败:", event)
  })

  // 监听瓦片加载成功
  baseLayer.value.getSource().on('tileloadend', function(event) {
    console.log("[OlMap] 瓦片加载成功:", event.tile.coordinate)
  })

  console.log("baseLayer initialized:", baseLayer.value);
  console.log(document.getElementById('tileMap'))
  map.value.addLayer(baseLayer.value)

  // Initialize point cloud layer
  initPointcloudLayer()

  // Ensure map takes full size of parent container
  map.value.updateSize()
}

// 初始化路网
function initRoad(geojson) {
  if (!geojson || geojson === "") return

  if (roadmap_src.value && roadmap_src.value.getFeatures().length > 0) {
    console.warn('保护模式: 地图已有数据，禁止重新加载')
    return
  }

  if (roadmap_src.value) {
    roadmap_src.value.clear()
    if (roadmapLayer.value) {
      roadmapLayer.value.setVisible(props.showRoadNetwork)
    }
  } else {
    roadmap_src.value = new VectorSource()
    roadmapLayer.value = new VectorLayer({
      source: roadmap_src.value,
      style: customizedStyle,
      visible: props.showRoadNetwork
    })
    map.value.addLayer(roadmapLayer.value)
  }

  const features = new GeoJSON().readFeatures(geojson)

  features.forEach(feature => {
    const innerId = feature.values_.id
    if (!feature.getId()) {
      feature.setId(innerId)
    }
  })

  // Filter out auto-generated areas (s_auto only, not all s_*)
  features.forEach(f => {
    const id = f.getProperties().id
    // 只过滤 s_auto，不过滤其他 s_* 开头的多边形
    if (id === "s_auto") {
      const idx = features.indexOf(f)
      if (idx > -1) features.splice(idx, 1)
    }
  })

  // Process bezier curves
  for (const feature of features) {
    if (feature.getGeometry().getType() === "MultiPoint" && feature.getProperties().id?.startsWith("b_")) {
      const controlPoints = feature.getGeometry().getCoordinates()
      feature.set('bezierControlPoints', controlPoints)
      const newBezierPoints = genBezierPointsByControlPoints(controlPoints, 0.01)
      feature.setGeometry(new LineString(newBezierPoints))
    }
  }

  // Fix LineString with intermediate points
  let fixedLineCount = 0
  for (const feature of features) {
    if (feature.getGeometry().getType() === "LineString" && feature.getId()?.startsWith("l_")) {
      const coords = feature.getGeometry().getCoordinates()
      if (coords.length > 2) {
        console.warn(`检测到线段 ${feature.getId()} 包含 ${coords.length} 个点，正在修复为只包含起点和终点`)
        feature.getGeometry().setCoordinates([coords[0], coords[coords.length - 1]])
        fixedLineCount++
        console.log(`线段 ${feature.getId()} 已修复: ${coords.length} 个点 -> 2 个点`)
      }
    }
  }

  if (fixedLineCount > 0) {
    console.warn(`共修复了 ${fixedLineCount} 条包含中间点的线段`)
    console.warn(`提示: 这些线段已自动修复，请保存地图以更新服务器数据`)
  } else {
    console.log('所有 LineString 格式正确，无需修复')
  }

  roadmap_src.value.addFeatures(features)

  if (roadmapLayer.value) {
    roadmapLayer.value.setVisible(props.showRoadNetwork)
  }

  elementRoadInitEnd(features)
}

// Complete drawing for pose init
function completeDrawing(start, end, nid) {
  const rotation = Math.atan2(end[0] - start[0], end[1] - start[1])
  const yaw = Math.PI / 2.0 - rotation

  if (previewFeature.value) {
    roadmap_src.value.removeFeature(previewFeature.value)
    previewFeature.value = null
  }

  emit('initNavigationResult', start, yaw, nid)
}

// 初始化机器人图标
function initRobot() {
  const robot_feature = new Feature({
    geometry: new Point([props.robotPoseData?.x || 0, props.robotPoseData?.y || 0])
  })
  robot_feature.setStyle(new Style({
    image: new Icon({
      src: icon.value.robot,
      rotateWithView: true,
      rotation: 0
    })
  }))
  robot_feature.setId("robot")

  robot_src.value = new VectorSource({})
  robot_src.value.addFeature(robot_feature)

  map.value.addLayer(new VectorLayer({
    source: robot_src.value,
    zIndex: 100
  }))
}

// 更新机器人位姿
function robotPoseUpdateCallback(x, y, yaw) {
  try {
    const robot_feature = robot_src.value?.getFeatureById("robot")
    if (!robot_feature) return

    robot_feature.getStyle().getImage().setRotation(Math.PI - yaw)
    robot_feature.getGeometry().setCoordinates([x, y])

    if (props.isRobotFollow) {
      followRotation()
    }
  } catch (e) {
    console.error('更新机器人位姿失败:', e)
  }
}

// 跟随机器人旋转
function followRotation() {
  const robot_feature = robot_src.value?.getFeatureById("robot")
  if (!robot_feature || !map.value) return

  const direction = robot_feature.getStyle().getImage().getRotation()
  const center = robot_feature.getGeometry().getCoordinates()
  map.value.getView().setCenter(center)
  map.value.getView().animate({
    rotation: -direction,
    duration: 1000,
    easing: inAndOut
  })
}

// ==================== 点位样式 ====================
function customizedStyle(feature) {
  const type = feature.getGeometry().getType()
  switch (type) {
    case "Point":
      return styleForPoint(feature)
    case "LineString":
      return styleForLine(feature)
    case "Polygon":
      return styleForPolygon(feature)
    default:
      return null
  }
}

function styleForPoint(feature) {
  let id = feature.values_.id
  let point = pointAll.value.find(item => item.point == id?.substring(2))

  if (props.existPointShow && id?.startsWith("p_") && pointAll.value.length > 0 && !point) {
    return
  }

  let textInfo = ""
  if (props.pointSwitch && point) {
    textInfo = feature.getProperties().id?.slice(2) + "-" + point.pointName
  } else if (props.pointSwitch) {
    textInfo = feature.getProperties().id?.slice(2)
  }

  return [
    new Style({
      image: new Icon({
        src: icon.value.point,
        anchor: [0.5, 0.5]
      }),
      text: new Text({
        font: 'normal 14px 黑体',
        textAlign: 'center',
        textBaseline: 'middle',
        offsetY: -15,
        offsetX: 0,
        fill: new Fill({ color: 'rgb(12, 239, 23, 0.8)' }),
        text: [textInfo, 'bold 14px sans-serif'],
        backgroundFill: new Fill({
          color: props.pointSwitch ? 'rgb(255,101,71, 1.0)' : 'rgb(255,101,71, 0.0)'
        })
      })
    })
  ]
}

function styleForLine(feature) {
  const direct = feature.getProperties().direct - 100
  const s2e = (direct & 12) > 0
  const e2s = (direct & 3) > 0

  // Arrow icons as SVG data URIs
  const dir_forward = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(`
    <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
      <polygon points="4,12 20,12 20,4 24,12 20,20 20,12" fill="#00BFFF"/>
    </svg>
  `)
  const dir_backward = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(`
    <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
      <polygon points="20,12 4,12 4,4 0,12 4,20 4,12" fill="#00BFFF"/>
    </svg>
  `)
  const dir_two_way = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(`
    <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
      <polygon points="4,12 20,12 20,4 24,12 20,20 20,12" fill="#00BFFF"/>
      <polygon points="20,12 4,12 4,4 0,12 4,20 4,12" fill="#00BFFF"/>
    </svg>
  `)

  let img = dir_two_way
  if (s2e && !e2s) img = dir_forward
  else if (!s2e && e2s) img = dir_backward

  const coords = feature.getGeometry().getCoordinates()
  const startIdx = Math.floor(coords.length / 2) - 1
  const endIdx = Math.ceil(coords.length / 2)
  const start = coords[startIdx]
  const end = coords[endIdx]

  const dx = end[0] - start[0]
  const dy = end[1] - start[1]
  const rotation = Math.atan2(dy, dx)

  return [
    new Style({
      stroke: new Stroke({ color: "#00BFFF", width: 6 })
    }),
    new Style({
      geometry: new Point([end[0] - dx / 2, end[1] - dy / 2]),
      image: new Icon({
        src: img,
        anchor: [0.75, 0.5],
        rotateWithView: true,
        rotation: -rotation
      })
    })
  ]
}

function styleForPolygon(feature) {
  let color = feature.getProperties().color || '#7EFFFA'
  let transparency = feature.getProperties().transparent
  transparency = (transparency >= 0 && transparency <= 255) ? transparency : 128
  const transparentColor = hexToRGBA(color, transparency)

  return [
    new Style({
      fill: new Fill({ color: transparentColor }),
      text: new Text({
        text: feature.getProperties().name || '',
        font: '16px serif',
        fill: new Fill({ color: '#000' }),
        stroke: new Stroke({ color: '#fff', width: 3 })
      })
    })
  ]
}

function hexToRGBA(hex, transparency) {
  if (hex.startsWith('#')) hex = hex.slice(1)
  if (hex.length === 3) hex = hex.split('').map(c => c + c).join('')

  let r = parseInt(hex.slice(0, 2), 16)
  let g = parseInt(hex.slice(2, 4), 16)
  let b = parseInt(hex.slice(4, 6), 16)

  const alpha = transparency / 255
  return `rgba(${r}, ${g}, ${b}, ${alpha})`
}

// ==================== HTML图标 ====================
function addHtmlIcon(id, x, y, iconSrc, type = "") {
  const iconDiv = document.createElement("div")
  iconDiv.className = "map-icon"
  iconDiv.style.width = "22px"
  iconDiv.style.height = "22px"
  iconDiv.style.borderRadius = "50%"
  iconDiv.style.border = "2px solid #ffffff"
  iconDiv.style.backgroundColor = "#4096BD"
  iconDiv.style.backgroundSize = "cover"
  iconDiv.style.position = "relative"
  iconDiv.style.overflow = "hidden"

  const numberSpan = document.createElement("span")
  numberSpan.textContent = id
  numberSpan.style.color = "#ffffff"
  numberSpan.style.fontSize = "14px"
  numberSpan.style.fontWeight = "bold"
  numberSpan.style.position = "absolute"
  numberSpan.style.top = "50%"
  numberSpan.style.left = "50%"
  numberSpan.style.transform = "translate(-50%, -50%)"
  numberSpan.style.lineHeight = "22px"
  numberSpan.style.whiteSpace = "nowrap"
  iconDiv.appendChild(numberSpan)

  initIconHtml(iconDiv, x, y, id, type)
}

function initIconHtml(div, x, y, id, type) {
  const overlay = new Overlay({
    element: div,
    position: [x, y],
    positioning: "center-center",
    stopEvent: false
  })
  overlay.set("id", `calibration-${id}`)
  overlay.set("type", type)
  map.value.addOverlay(overlay)
}

function removeCalibrationById(id) {
  calibrationList.value = calibrationList.value.filter(item => item.id !== id)
  calibrationList.value.forEach((item, idx) => { item.id = idx + 1 })
  refreshCalibrationOverlays()
}

function refreshCalibrationOverlays() {
  const all = map.value.getOverlays().getArray().slice()

  const toRemove = all.filter(ov => {
    try {
      return ov && typeof ov.get === 'function' &&
        (ov.get('type') === 'calibration' ||
         (typeof ov.get('id') === 'string' && ov.get('id').startsWith('calibration-')))
    } catch (e) {
      return false
    }
  })

  toRemove.forEach(ov => map.value.removeOverlay(ov))

  calibrationList.value.forEach(item => {
    addHtmlIcon(item.id, item.x, item.y, '', 'calibration')
  })
}

function removeIconHtmlById(id) {
  const overlays = map.value.getOverlays()
  overlays.forEach((overlay) => {
    if (overlay && overlay.get && overlay.get("id") === id) {
      map.value.removeOverlay(overlay)
    }
  })
}

// ==================== 绘制工具 ====================
function drawPoint() {
  clearDraw()
  draw.value = new Draw({ source: roadmap_src.value, type: 'Point' })
  snap.value = new Snap({ source: roadmap_src.value, pixelTolerance: 15 })
  map.value.addInteraction(draw.value)
  map.value.addInteraction(snap.value)

  draw.value.on('drawend', (event) => {
    const feature = event.feature
    const featureId = 'p_' + (maxPointIdNum.value + 1)
    feature.setId(featureId)
    feature.set('id', featureId)
    console.log('绘制的点 ID:', featureId)
    console.log('绘制的点坐标:', feature.getGeometry().getCoordinates())
    roadmap_src.value.addFeature(feature)
    feature.setStyle(customizedStyle(feature))
    elementRoadDrawEnd(feature, 'p')
    map.value.removeInteraction(draw.value)
    drawPoint()
  })
}

function drawLine() {
  console.log("zeinima");
  
  clearDraw()
  draw.value = new Draw({ source: roadmap_src.value, type: 'LineString', maxPoints: 2 })
  snap.value = new Snap({ source: roadmap_src.value, pixelTolerance: 10 })
  map.value.addInteraction(draw.value)
  map.value.addInteraction(snap.value)

  draw.value.on('drawend', (event) => {
    const feature = event.feature
    const coordinates = feature.getGeometry().getCoordinates()
    console.log('绘制的线坐标:', coordinates)
    const featureId = 'l_' + (maxLineIdNum.value + 1)
    feature.setId(featureId)
    feature.set('id', featureId)

    const startCoord = ensureValidCoordinate([...coordinates[0]])
    const endCoord = ensureValidCoordinate([...coordinates[coordinates.length - 1]])

    let startPointId = getConnectedPointId(startCoord)
    if (!startPointId) startPointId = createPointAtCoordinate(startCoord)
    let endPointId = getConnectedPointId(endCoord)
    if (!endPointId) endPointId = createPointAtCoordinate(endCoord)

    if (startPointId === endPointId) {
      map.value.removeInteraction(draw.value)
      drawLine()
      return
    }

    // 检查是否已存在相同起点终点的线段
    let lineExist = false
    const startFeature = roadmap_src.value.getFeatureById(startPointId)
    const endFeature = roadmap_src.value.getFeatureById(endPointId)
    const featuresAtStart = roadmap_src.value.getFeaturesAtCoordinate(startFeature.getGeometry().getCoordinates())
    for (let i = 0; i < featuresAtStart.length; i++) {
      const existingFeature = featuresAtStart[i]
      if (existingFeature.getGeometry().getType() !== 'LineString') continue

      const props = existingFeature.getProperties()
      if (((props.startid === startPointId) && (props.endid === endPointId)) ||
          ((props.endid === startPointId) && (props.startid === endPointId))) {
        console.warn('已存在相同起点终点的线段，不创建新线段')
        lineExist = true
        break
      }
    }

    if (lineExist) {
      map.value.removeInteraction(draw.value)
      drawLine()
      return
    }

    feature.getGeometry().setCoordinates([
      startFeature.getGeometry().getCoordinates(),
      endFeature.getGeometry().getCoordinates()
    ])
    feature.set('startid', startPointId)
    feature.set('endid', endPointId)

    roadmap_src.value.addFeature(feature)
    feature.setStyle(customizedStyle(feature))
    elementRoadDrawEnd(feature, 'l')

    map.value.removeInteraction(draw.value)
    drawLine()
  })
}

function drawCurve() {
  clearDraw()
  draw.value = new Draw({ source: roadmap_src.value, type: 'LineString' })
  snap.value = new Snap({ source: roadmap_src.value, pixelTolerance: 15 })
  map.value.addInteraction(draw.value)
  map.value.addInteraction(snap.value)

  draw.value.on('drawend', (event) => {
    const feature = event.feature
    const coordinates = feature.getGeometry().getCoordinates()

    if (coordinates.length < 3) {
      console.warn('贝塞尔曲线需要至少3个点')
      return
    }

    const startCoord = ensureValidCoordinate([...coordinates[0]])
    const endCoord = ensureValidCoordinate([...coordinates[coordinates.length - 1]])

    let startPointId = getConnectedPointId(startCoord)
    let endPointId = getConnectedPointId(endCoord)
    if (!startPointId) startPointId = createPointAtCoordinate(startCoord)
    if (!endPointId) endPointId = createPointAtCoordinate(endCoord)

    if (startPointId === endPointId) return

    const startFeature = roadmap_src.value.getFeatureById(startPointId)
    const endFeature = roadmap_src.value.getFeatureById(endPointId)

    const controlPoints = [...coordinates]
    controlPoints[0] = startFeature.getGeometry().getCoordinates()
    controlPoints[controlPoints.length - 1] = endFeature.getGeometry().getCoordinates()

    feature.set('startid', startPointId)
    feature.set('endid', endPointId)
    feature.set('bezierControlPoints', controlPoints)

    const newBezierPoints = genBezierPointsByControlPoints(controlPoints, 0.01)
    feature.setGeometry(new LineString(newBezierPoints))

    const featureId = 'b_' + (maxBowNum.value + 1)
    feature.setId(featureId)
    feature.set('id', featureId)

    roadmap_src.value.addFeature(feature)
    feature.setStyle(customizedStyle(feature))
    elementRoadDrawEnd(feature, 'b')

    map.value.removeInteraction(draw.value)
    drawCurve()
  })
}

function drawPolygon() {
  clearDraw()
  draw.value = new Draw({ source: roadmap_src.value, type: 'Polygon' })
  snap.value = new Snap({ source: roadmap_src.value, pixelTolerance: 15 })
  map.value.addInteraction(draw.value)
  map.value.addInteraction(snap.value)

  draw.value.on('drawend', (event) => {
    const feature = event.feature
    const featureId = 's_' + (maxPolygonNum.value + 1)
    feature.setId(featureId)
    feature.set('id', featureId)
    console.log('绘制的面 ID:', featureId)
    console.log('绘制的面坐标:', feature.getGeometry().getCoordinates())
    roadmap_src.value.addFeature(feature)
    feature.setStyle(customizedStyle(feature))
    elementRoadDrawEnd(feature, 's')
    map.value.removeInteraction(draw.value)
    drawPolygon()
  })
}

function clearDraw() {
  if (draw.value) {
    map.value.removeInteraction(draw.value)
    draw.value = null
  }
  if (snap.value) {
    map.value.removeInteraction(snap.value)
    snap.value = null
  }
}

function createPointAtCoordinate(targetCoord, data = []) {
  const features = roadmap_src.value.getFeatures()
  for (const feature of features) {
    const geometry = feature.getGeometry()
    if (geometry && geometry.getType() === 'Point') {
      const coord = geometry.getCoordinates()
      if (coord[0] === targetCoord[0] && coord[1] === targetCoord[1]) {
        ElMessage({ message: '目标绘制点已存在点位', type: 'warning' })
        console.log('目标绘制点已存在点位')
        return null
      }
    }
  }

  const pointFeature = new Feature({ geometry: new Point(targetCoord) })
  const pointId = 'p_' + (maxPointIdNum.value + 1)
  pointFeature.set('id', pointId)
  pointFeature.setId(pointId)

  if (Array.isArray(data) && data.length > 0) {
    data.forEach(item => {
      Object.entries(item).forEach(([key, value]) => {
        pointFeature.set(key, value)
      })
    })
  }

  roadmap_src.value.addFeature(pointFeature)
  pointFeature.setStyle(customizedStyle(pointFeature))
  elementRoadDrawEnd(pointFeature, 'p')
  console.log(`成功创建点位: ${pointId}`, targetCoord)

  return pointId
}

function getConnectedPointId(coord) {
  const tolerance = 0.01
  let closestPointId = ''
  roadmap_src.value.forEachFeature((feature) => {
    if (feature.getGeometry().getType() === 'Point') {
      const pointCoord = feature.getGeometry().getCoordinates()
      if (isCoordsClose(pointCoord, coord, tolerance)) {
        closestPointId = feature.getId()
      }
    }
  })
  return closestPointId
}

function isCoordsClose(coord1, coord2, tolerance) {
  const dx = Math.abs(coord1[0] - coord2[0])
  const dy = Math.abs(coord1[1] - coord2[1])
  return dx <= tolerance && dy <= tolerance
}

function ensureValidCoordinate(coord) {
  if (!coord || coord.length < 2) return coord
  if (coord[0] === null || coord[0] === undefined) coord[0] = 0
  if (coord[1] === null || coord[1] === undefined) coord[1] = 0
  if (coord.length < 3) coord.push(0)
  else if (coord[2] === null || coord[2] === undefined) coord[2] = 0
  return coord
}

// 贝塞尔曲线
function genBezierPointsByControlPoints(controlPoints, step = 0.05) {
  const bezierPoints = []
  const n = controlPoints.length - 1
  for (let i = 0; i < 1; i += step) {
    let x = 0, y = 0
    for (let idx = 0; idx < controlPoints.length; idx++) {
      const coord = controlPoints[idx]
      if (!idx) {
        x += coord[0] * Math.pow(1 - i, n - idx) * Math.pow(i, idx)
        y += coord[1] * Math.pow(1 - i, n - idx) * Math.pow(i, idx)
      } else {
        x += (factorial(n) / factorial(idx) / factorial(n - idx)) * coord[0] * Math.pow(1 - i, n - idx) * Math.pow(i, idx)
        y += (factorial(n) / factorial(idx) / factorial(n - idx)) * coord[1] * Math.pow(1 - i, n - idx) * Math.pow(i, idx)
      }
    }
    bezierPoints.push([x, y])
  }
  bezierPoints.push(controlPoints[n])
  return bezierPoints
}

function factorial(num) {
  return num <= 1 ? 1 : num * factorial(num - 1)
}

// 模式切换逻辑
function togglePointSelection() {
  // This would toggle a ref, but since it's a prop we emit an event
  emit('togglePointSelection')
}

// 计算航向角
function calculateBearing(start, end) {
  const dx = end[0] - start[0]
  const dy = end[1] - start[1]
  const angle = Math.atan2(dy, dx) * (180 / Math.PI)
  return angle < 0 ? angle + 360 : angle
}

// 修改多边形的颜色和透明度
function editSnapeColor(id) {
  if (!roadmap_src.value) {
    console.log("请先初始化画布!")
    return
  }
  const snapeFeature = roadmap_src.value.getFeatureById(id)
  if (!snapeFeature) {
    console.log(`未找到ID为 ${id} 的多边形元素!`)
    return
  }
  snapeFeature.setStyle(customizedStyle(snapeFeature))
}

// ==================== 元素操作 ====================
function elementRoadInitEnd(features) {
  let data = features.reduce((acc, item) => {
    const id = item.values_.id || item.getId()
    if (!id) return acc
    const [prefix, number] = id.split("_")
    const num = parseInt(number, 10)
    if (!acc[prefix] || acc[prefix] < num) {
      acc[prefix] = num
    }
    return acc
  }, {})

  if (data.p) maxPointIdNum.value = data.p
  if (data.l) maxLineIdNum.value = data.l
  if (data.b) maxBowNum.value = data.b
  if (data.s) maxPolygonNum.value = data.s

  emit('elementRoadInitEnd', features)
}

function elementRoadDrawEnd(feature, type) {
  const typeMapping = { p: 'maxPointIdNum', l: 'maxLineIdNum', b: 'maxBowNum', s: 'maxPolygonNum' }
  if (typeMapping[type]) {
    switch (type) {
      case 'p': maxPointIdNum.value++; break
      case 'l': maxLineIdNum.value++; break
      case 'b': maxBowNum.value++; break
      case 's': maxPolygonNum.value++; break
    }
  }
  emit('elementRoadDrawEnd', feature)
}

function removeElement(id) {
  if (!roadmap_src.value) {
    emit('removeElementResult', '')
    return
  }
  const feature = roadmap_src.value.getFeatureById(id)
  if (feature) {
    roadmap_src.value.removeFeature(feature)
    emit('removeElementResult', id)
    if (selectedFeatureId.value === id) {
      selectedFeatureId.value = ''
    }
  } else {
    emit('removeElementResult', '')
  }
}

function selectShowEle(id) {
  if (!id || !roadmap_src.value) return

  let feature = roadmap_src.value.getFeatureById(id)
  if (!feature) return

  let position = feature.getGeometry().getCoordinates()
  if (id.startsWith('l')) {
    position = calculateCenterCoordinate(position[0], position[1], 0.4)
  } else if (id.startsWith('b')) {
    const coords = position
    position = coords[Math.ceil(coords.length / 2)]
  } else if (id.startsWith('s')) {
    position = calculateCentroid(position)
  }

  // Centering the map view on the selected element
  if (map.value) {
    const view = map.value.getView()
    const currentZoom = view.getZoom()
    const targetZoom = Math.max(currentZoom, 15)
    view.animate({
      center: position,
      zoom: targetZoom,
      duration: 500
    })
  }

  if (!icon_src.value) {
    // For points, show icon at exact position (not offset)
    // For other elements, show icon at calculated position
    const iconX = id.startsWith('p') ? position[0] : position[0]
    const iconY = id.startsWith('p') ? position[1] : position[1] + 0.8
    initIcon(1, iconX, iconY, icon.value.mark, 'selectEle', 0.15, 100)
    selectedFeatureId.value = id
  } else {
    let oldFeature = icon_src.value.getFeatureById('selectEle-' + 1)
    if (!oldFeature) {
      const iconX = id.startsWith('p') ? position[0] : position[0]
      const iconY = id.startsWith('p') ? position[1] : position[1] + 0.8
      initIcon(1, iconX, iconY, icon.value.mark, 'selectEle', 0.15, 100)
      selectedFeatureId.value = id
    } else {
      if (id === selectedFeatureId.value) {
        // Toggle off - don't remove, just update position
        icon_src.value.removeFeature(oldFeature)
        selectedFeatureId.value = ''
      } else {
        // For points, show icon at exact position
        const iconX = id.startsWith('p') ? position[0] : position[0]
        const iconY = id.startsWith('p') ? position[1] : position[1] + 0.8
        oldFeature.getGeometry().setCoordinates([iconX, iconY])
        selectedFeatureId.value = id
      }
    }
  }

  emit('selectShowEleResult', feature)
}

function initIcon(id, x, y, iconSrc, type = "", scale = 0.15, zIndex) {
  const icon_feature = new Feature({ geometry: new Point([x, y]) })
  icon_feature.setStyle(new Style({
    image: new Icon({ src: iconSrc, rotateWithView: true, rotation: 0, scale })
  }))
  icon_feature.setId(type + "-" + id)

  icon_src.value = new VectorSource({})
  icon_src.value.addFeature(icon_feature)

  const icon_layer = new VectorLayer({ source: icon_src.value })
  if (zIndex !== undefined) icon_layer.setZIndex(zIndex)
  map.value.addLayer(icon_layer)
}

function calculateCenterCoordinate(coord1, coord2, ratio = 0.5) {
  const x1 = coord1[0], y1 = coord1[1]
  const x2 = coord2[0], y2 = coord2[1]
  return [x1 + ratio * (x2 - x1), y1 + ratio * (y2 - y1)]
}

function calculateCentroid(coords) {
  if (Array.isArray(coords[0]) && Array.isArray(coords[0][0])) {
    coords = coords[0]
  }
  let n = coords.length
  let area = 0, cx = 0, cy = 0
  for (let i = 0; i < n; i++) {
    let j = (i + 1) % n
    let x1 = coords[i][0], y1 = coords[i][1]
    let x2 = coords[j][0], y2 = coords[j][1]
    let crossProduct = x1 * y2 - x2 * y1
    area += crossProduct
    cx += (x1 + x2) * crossProduct
    cy += (y1 + y2) * crossProduct
  }
  area = area / 2
  cx = cx / (6 * area)
  cy = cy / (6 * area)
  return [cx, cy]
}

function editElementSelectHandle(feature) {
  if (feature) {
    selectShowEle(feature.getId())
  }
}

function hideToop() {
  const tooltip = document.getElementById('tooltip')
  if (tooltip) tooltip.style.display = 'none'
}

function restIdNum() {
  maxIndex.value = 0
}

// ==================== 轨迹相关 ====================
function initTrajectoryLayer() {
  if (!trajectorySource.value) {
    trajectorySource.value = new VectorSource()
    map.value.addLayer(new VectorLayer({
      source: trajectorySource.value,
      zIndex: 5
    }))
  }
}

function drawTrajectory(trajectory, options = {}) {
  console.log("开始绘制轨迹:", trajectory, options)

  if (!trajectory || trajectory.length === 0) {
    console.warn("轨迹数据为空")
    return
  }

  initTrajectoryLayer()
  clearTrajectory()
  currentTrajectory.value = trajectory
  trajectoryProgress.value = options.currentProgress || 0

  const robotPos = options.robotPosition || [0, 0]
  const projectionInfo = findRobotProjectionOnTrajectory(trajectory, robotPos)

  if (projectionInfo && projectionInfo.segmentIndex >= 0) {
    drawRealtimeTrajectoryFromRobotPosition(trajectory, robotPos, projectionInfo)
  } else {
    drawTrajectoryByProgress(trajectory)
  }

  if (trajectory.length > 0) {
    addTrajectoryMarker(trajectory[0], { text: '起点', color: '#ffffff', backgroundColor: 'rgba(0, 255, 0, 0.8)' })
  }
  if (trajectory.length > 1) {
    addTrajectoryMarker(trajectory[trajectory.length - 1], { text: '终点', color: '#ffffff', backgroundColor: 'rgba(255, 0, 0, 0.8)' })
  }

  console.log("轨迹绘制完成，总点数:", trajectory.length, "当前进度:", trajectoryProgress.value)
}

function findRobotProjectionOnTrajectory(trajectory, robotPos) {
  if (!trajectory || trajectory.length < 2) return null

  let minDistance = Infinity, bestProjection = null

  for (let i = 0; i < trajectory.length - 1; i++) {
    const projection = projectPointToLineSegment(robotPos, trajectory[i], trajectory[i + 1])
    if (projection.distance < minDistance) {
      minDistance = projection.distance
      bestProjection = {
        point: projection.point,
        distance: projection.distance,
        segmentIndex: i,
        parameter: getParameterOnSegment(projection.point, trajectory[i], trajectory[i + 1])
      }
    }
  }

  // 放宽距离限制，提高轨迹绘制的实时性
  if (bestProjection && bestProjection.distance < 10.0) {
    console.log(`找到机器人投影点: 线段${bestProjection.segmentIndex}, 距离${bestProjection.distance.toFixed(2)}m`)
    return bestProjection
  }

  console.log(`机器人距离轨迹太远: ${bestProjection ? bestProjection.distance.toFixed(2) : 'N/A'}m, 使用回退绘制方式`)
  return null
}

function projectPointToLineSegment(point, lineStart, lineEnd) {
  const [px, py] = point
  const [x1, y1] = lineStart
  const [x2, y2] = lineEnd
  const A = px - x1, B = py - y1, C = x2 - x1, D = y2 - y1
  const dot = A * C + B * D
  const lenSq = C * C + D * D
  if (lenSq === 0) return { point: [x1, y1], distance: Math.sqrt(A * A + B * B) }

  let param = Math.max(0, Math.min(1, dot / lenSq))
  return {
    point: [x1 + param * C, y1 + param * D],
    distance: Math.sqrt(Math.pow(px - (x1 + param * C), 2) + Math.pow(py - (y1 + param * D), 2))
  }
}

// 获取投影点在线段上的参数(0-1)
function getParameterOnSegment(projectionPoint, segmentStart, segmentEnd) {
  const [px, py] = projectionPoint
  const [x1, y1] = segmentStart
  const [x2, y2] = segmentEnd

  if (Math.abs(x2 - x1) > Math.abs(y2 - y1)) {
    return (px - x1) / (x2 - x1)
  } else {
    return (py - y1) / (y2 - y1)
  }
}

function drawRealtimeTrajectoryFromRobotPosition(trajectory, robotPos, projectionInfo) {
  console.log(`实时轨迹绘制: 机器人位置(${robotPos[0].toFixed(2)}, ${robotPos[1].toFixed(2)}), 投影在线段${projectionInfo.segmentIndex}`)

  const completedPoints = []
  for (let i = 0; i <= projectionInfo.segmentIndex; i++) completedPoints.push(trajectory[i])
  completedPoints.push(projectionInfo.point)

  if (completedPoints.length >= 2) {
    console.log(`绘制实时已走过轨迹: 起点到机器人投影位置, ${completedPoints.length}个点`)
    drawTrajectorySegment(completedPoints, { color: '#00ff00', width: 4, lineDash: [10, 5], type: 'completed' })
  }

  const remainingPoints = [projectionInfo.point]
  if (projectionInfo.segmentIndex < trajectory.length - 1) remainingPoints.push(trajectory[projectionInfo.segmentIndex + 1])
  for (let i = projectionInfo.segmentIndex + 2; i < trajectory.length; i++) remainingPoints.push(trajectory[i])

  if (remainingPoints.length >= 2) {
    console.log(`绘制实时未走过轨迹: 机器人投影位置到终点, ${remainingPoints.length}个点`)
    drawTrajectorySegment(remainingPoints, { color: '#ff0000', width: 4, lineDash: [10, 5], type: 'remaining' })
  }

  addRealtimeRobotMarker(robotPos, projectionInfo.point)
}

function drawTrajectoryByProgress(trajectory) {
  if (trajectoryProgress.value > 0) {
    const completed = trajectory.slice(0, trajectoryProgress.value + 1)
    if (completed.length >= 2) drawTrajectorySegment(completed, { color: '#00ff00', width: 4, lineDash: [10, 5], type: 'completed' })
  }
  if (trajectoryProgress.value < trajectory.length - 1) {
    const remaining = trajectory.slice(trajectoryProgress.value)
    if (remaining.length >= 2) drawTrajectorySegment(remaining, { color: '#ff0000', width: 4, lineDash: [10, 5], type: 'remaining' })
  }
}

function drawTrajectorySegment(trajectorySegment, style) {
  if (!trajectorySegment || trajectorySegment.length < 2) return
  const feature = new Feature({ geometry: new LineString(trajectorySegment) })
  feature.setStyle(new Style({ stroke: new Stroke({ color: style.color, width: style.width, lineDash: style.lineDash }) }))
  feature.setId(`trajectory-${style.type}-${Date.now()}`)
  trajectorySource.value.addFeature(feature)
}

function addTrajectoryMarker(position, options) {
  const marker = new Feature({ geometry: new Point(position) })
  marker.setStyle(new Style({
    text: new Text({
      text: options.text, font: 'bold 12px Arial',
      fill: new Fill({ color: options.color }),
      backgroundFill: new Fill({ color: options.backgroundColor }),
      padding: [3, 6, 3, 6], offsetY: -20
    }),
    image: new Icon({
      src: 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(`<svg width="12" height="12" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" r="5" fill="${options.color}" stroke="white" stroke-width="1"/></svg>`),
      scale: 1
    })
  }))
  marker.setId(`trajectory-marker-${options.text}-${Date.now()}`)
  trajectorySource.value.addFeature(marker)
}

function addRealtimeRobotMarker(robotActualPos, robotProjectionPos) {
  const marker = new Feature({ geometry: new Point(robotProjectionPos) })
  marker.setStyle(new Style({
    image: new Icon({
      src: 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(`
        <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
          <circle cx="8" cy="8" r="6" fill="#ffff00" stroke="#ff6600" stroke-width="2"/>
          <circle cx="8" cy="8" r="2" fill="#ff6600"/>
        </svg>
      `), scale: 1
    }),
    text: new Text({
      text: '当前', font: 'bold 10px Arial',
      fill: new Fill({ color: '#333' }),
      backgroundFill: new Fill({ color: 'rgba(255,255,255,0.8)' }),
      padding: [2, 4, 2, 4], offsetY: -25
    })
  }))
  marker.setId(`trajectory-current-position-${Date.now()}`)
  trajectorySource.value.addFeature(marker)
}

function clearTrajectory() {
  if (trajectorySource.value) trajectorySource.value.clear()
  currentTrajectory.value = null
  trajectoryProgress.value = 0
}

function updateTrajectoryProgress(newProgress, robotPosition = null) {
  if (!currentTrajectory.value) return
  trajectoryProgress.value = newProgress
  if (trajectorySource.value) trajectorySource.value.clear()
  const robotPos = robotPosition || [props.robotPoseData?.x || 0, props.robotPoseData?.y || 0]
  drawTrajectory(currentTrajectory.value, { currentProgress: newProgress, robotPosition: robotPos })
}

function updateRealtimeTrajectory(robotPosition) {
  if (!currentTrajectory.value || !trajectorySource.value) return
  const features = trajectorySource.value.getFeatures()
  features.forEach(feature => {
    const id = feature.getId()
    if (id && (id.startsWith('trajectory-completed-') || id.startsWith('trajectory-remaining-') || id.startsWith('trajectory-current-position-'))) {
      trajectorySource.value.removeFeature(feature)
    }
  })
  const projectionInfo = findRobotProjectionOnTrajectory(currentTrajectory.value, robotPosition)
  if (projectionInfo && projectionInfo.segmentIndex >= 0) {
    drawRealtimeTrajectoryFromRobotPosition(currentTrajectory.value, robotPosition, projectionInfo)
  }
}

// ==================== 点云相关 ====================
function initPointcloudLayer() {
  pointcloudLayer.value = new VectorLayer({
    source: new VectorSource({
      features: [new Feature({ geometry: new MultiPoint([]), name: 'PointCloud' })]
    }),
    style: new Style({
      image: new Circle({ radius: 1.8, fill: new Fill({ color: '#FF0000' }) })
    }),
    visible: props.showPointcloud,
    zIndex: 10
  })
  map.value.addLayer(pointcloudLayer.value)

  if (props.showPointcloud) {
    startPointcloudUpdate()
  }
}

function startPointcloudUpdate() {
  stopPointcloudUpdate()
  pointcloudTimer.value = setInterval(() => {
    if (!pointcloudLayer.value || !pointcloudLayer.value.getVisible()) return
    updatePointcloud()
  }, 800)
}

function stopPointcloudUpdate() {
  if (pointcloudTimer.value) {
    clearInterval(pointcloudTimer.value)
    pointcloudTimer.value = null
  }
}

async function updatePointcloud() {
  try {
    const response = await getPointcloud()
    if (!pointcloudLayer.value || !response) return

    const pointcloud = response
    const pointsCount = Math.floor(pointcloud.byteLength / 12)
    if (pointsCount === 0) return

    const float32View = new Float32Array(pointcloud, 0)
    const coordinates = []

    for (let i = 0; i < pointsCount; i++) {
      const x = float32View[3 * i]
      const y = float32View[3 * i + 1]
      coordinates.push([x, y])
    }

    const features = pointcloudLayer.value.getSource().getFeatures()
    if (features.length > 0) {
      features[0].setGeometry(new MultiPoint(coordinates))
    }

    emit('point-cloud-load-end', pointsCount)
  } catch (e) {
    // Silent fail to avoid console spam
  }
}

// ==================== 路网导入导出 ====================
function clearAllElements() {
  if (!roadmap_src.value) return false
  roadmap_src.value.clear()
  selectedFeatureId.value = ''
  if (icon_src.value) icon_src.value.clear()
  return true
}

function importGeoJsonFeatures(geoJsonData) {
  if (!roadmap_src.value) {
    throw new Error("请先初始化画布!")
  }

  if (!geoJsonData || !geoJsonData.features) {
    throw new Error("无效的GeoJSON数据")
  }

  const features = new GeoJSON().readFeatures(geoJsonData)

  features.forEach(feature => {
    if (!feature.getId() && feature.get('id')) {
      feature.setId(feature.get('id'))
    }
  })

  roadmap_src.value.addFeatures(features)

  if (features.length > 0) {
    emit('elementRoadInitEnd', features)
  }

  console.log(`成功导入${features.length}个地图元素`)
  return features
}

function createPointAtCoordinateForImport(coordinates, name = '', extraData = []) {
  if (!roadmap_src.value) return

  ensureValidCoordinate(coordinates)

  const existingPoints = roadmap_src.value.getFeatures().filter(f => f.getId() && f.getId().startsWith('p_'))
  const maxId = existingPoints.length > 0 ? Math.max(...existingPoints.map(f => parseInt(f.getId().split('_')[1]) || 0)) : 0
  const newId = `p_${maxId + 1}`

  const pointFeature = new Feature({
    geometry: new Point(coordinates),
    id: newId,
    name: name || `点位${maxId + 1}`
  })
  pointFeature.setId(newId)

  if (extraData && extraData.length > 0) {
    extraData.forEach(data => {
      Object.keys(data).forEach(key => pointFeature.set(key, data[key]))
    })
  }

  roadmap_src.value.addFeature(pointFeature)
  emit('elementRoadDrawEnd', pointFeature)

  return pointFeature
}

function refresh() {
  if (map.value) {
    map.value.render()
    map.value.updateSize()
  }
}

function updateMapSize() {
  if (map.value) {
    // 确保地图容器有正确的尺寸
    const mapNode = document.getElementById("tileMap")
    if (mapNode) {
      // 强制触发浏览器重绘
      mapNode.style.width = '1px'
      mapNode.style.width = props.width || '100%'
      mapNode.style.height = props.height || '100%'
    }
    map.value.updateSize()
  }
}

function setRoadNetworkVisible(visible) {
  if (roadmapLayer.value) {
    roadmapLayer.value.setVisible(visible)
  }
}

// ==================== 点位移动 ====================
function pointPositionUpdate(id, position) {
  if (!roadmap_src.value) return

  const feature = roadmap_src.value.getFeatureById(id)
  if (!feature) return

  const geometry = feature.getGeometry()
  const coordinates = geometry.getCoordinates()
  coordinates[0] = position[0]
  coordinates[1] = position[1]
  geometry.setCoordinates(coordinates)

  // Update selection icon position - for points, show at exact position (no offset)
  if (icon_src.value) {
    const iconFeature = icon_src.value.getFeatureById('selectEle-' + 1)
    if (iconFeature) {
      const iconY = id.startsWith('p') ? position[1] : position[1] + 0.8
      iconFeature.getGeometry().setCoordinates([position[0], iconY])
    }
  }

  // Update connected lines
  roadmap_src.value.getFeatures().forEach(lineFeature => {
    const startId = lineFeature.get('startid')
    const endId = lineFeature.get('endid')

    if (lineFeature.getId()?.startsWith('l')) {
      if (startId === id || endId === id) {
        const startFeature = roadmap_src.value.getFeatureById(startId)
        const endFeature = roadmap_src.value.getFeatureById(endId)
        if (startFeature && endFeature) {
          lineFeature.getGeometry().setCoordinates([
            startFeature.getGeometry().getCoordinates(),
            endFeature.getGeometry().getCoordinates()
          ])
          lineFeature.setStyle(customizedStyle(lineFeature))
        }
      }
    } else if (lineFeature.getId()?.startsWith('b')) {
      if (startId === id || endId === id) {
        const controlPoints = lineFeature.getGeometry().getCoordinates()
        const updatedControlPoints = controlPoints.map(p => [...p])
        if (startId === id) updatedControlPoints[0] = position
        if (endId === id) updatedControlPoints[updatedControlPoints.length - 1] = position
        const newBezierPoints = genBezierPointsByControlPoints(updatedControlPoints, 0.01)
        lineFeature.getGeometry().setCoordinates(newBezierPoints)
        lineFeature.setStyle(customizedStyle(lineFeature))
      }
    }
  })
}

// ==================== 暴露方法 ====================
defineExpose({
  map,
  roadmap_src,
  loadMap,
  loadRoadmap: initRoad,
  loadPointCloud: updatePointcloud,
  importGeoJsonFeatures,
  removeElement,
  setCenter: (coords) => map.value?.getView().animate({ center: coords, duration: 500 }),
  drawPoint,
  drawLine,
  drawCurve,
  drawPolygon,
  clearDraw,
  selectShowEle,
  removeIconHtmlById,
  clearAllElements,
  clearTrajectory,
  drawTrajectory,
  updateTrajectoryProgress,
  updateRealtimeTrajectory,
  initTrajectoryLayer,
  pointPositionUpdate,
  createPointAtCoordinate,
  createPointAtCoordinateForImport,
  refresh,
  updateMapSize,
  setRoadNetworkVisible,
  followRotation,
  initRobot,
  robotPoseUpdateCallback
})
</script>

<style scoped>
.map-wrapper {
  width: 100%;
  height: 100%;
  position: relative;
}

.mapParent {
  width: 100%;
  height: 100%;
  min-height: 300px;
  background-color: #d5d8e1;
  text-align: center !important;
  border-radius: 5px;
  position: relative;
  box-sizing: border-box;
}

.maptext {
  font-size: 20px;
  color: rgb(156, 156, 156);
  height: 100%;
}

.tooltip {
  position: absolute;
  background: white;
  border-radius: 12px;
  display: none;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
  width: 240px;
  overflow: hidden;
  border: 1px solid #e2e8f0;
  z-index: 1000;
}

.tooltip-header {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.tooltip-title {
  font-size: 14px;
  font-weight: 600;
  margin: 0;
}

.tooltip-content {
  padding: 16px;
  background: #f8fafc;
}

.tooltip-content p {
  margin: 0;
  padding: 8px 12px;
  background: white;
  border-radius: 6px;
  border: 1px solid #e2e8f0;
  text-align: center;
}

.tooltip-content p:first-child {
  font-size: 13px;
  color: #4a5568;
  margin-bottom: 8px;
}

.tooltip-content p:last-child {
  font-family: 'Courier New', monospace;
  color: #e53e3e;
  font-weight: 600;
  font-size: 14px;
  background: #fff5f5;
  border-color: #fed7d7;
}

.tooltip-actions {
  padding: 12px 16px;
  background: white;
  display: flex;
  gap: 8px;
  border-top: 1px solid #e2e8f0;
}

.action-btn {
  flex: 1;
  border-radius: 6px;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
}

:deep(.action-btn.el-button--primary) {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border: none;
}

:deep(.action-btn:not(.el-button--primary)) {
  background: #f7fafc;
  border: 1px solid #e2e8f0;
  color: #4a5568;
}

:deep(.tileMap) {
  width: 100%;
  height: 100%;
}
</style>
