<template>
  <div>
    <div class="home-header">
      <img @click="drawStartPoint" src="@/assets/image/start.png" />
      <img @click="drawEndPoint" src="@/assets/image/end.png" />
      <img @click="drawViaPoint" src="@/assets/image/add.png" />
      <img @click="drawAvoidPoint" src="@/assets/image/avoidP.png" />
      <img @click="drawAvoidArea" src="@/assets/image/updown.png" />
      <div @click="calculateShortestPath" class="sure">确定</div>
      <!-- <div class="control-panel">
        <button @click="drawStartPoint">绘制起点</button>
        <button @click="drawEndPoint">绘制终点</button>
        <button @click="drawViaPoint">绘制途径点</button>
        <button @click="drawAvoidPoint">绘制避让点</button>
        <button @click="drawAvoidArea">绘制避让区域</button>
        <button @click="calculateShortestPath">计算最短路径</button>
        <button @click="clear">清除所有</button>
      </div> -->
    </div>
    <div class="home">
      <div class="main-container">
        <div class="control-panel">
          <div class="title">参数</div>
          <el-form
            @submit.native.prevent="calculateShortestPath"
            label-width="80px"
            label-position="left"
            size="small"
          >
            <el-form-item label="起点">
              <el-input v-model="form.startPoint"></el-input>
            </el-form-item>
            <el-form-item label="终点">
              <el-input v-model="form.endPoint"></el-input>
            </el-form-item>
            <el-form-item label="途径点">
              <el-input v-model="form.viaPoints" placeholder=""></el-input>
            </el-form-item>
            <el-form-item label="避让点">
              <el-input v-model="form.avoidPoints" placeholder=""></el-input>
            </el-form-item>
            <el-form-item label="避让区域">
              <el-input
                type="textarea"
                v-model="form.avoidAreas"
                :rows="4"
                placeholder=""
              ></el-input>
            </el-form-item>
            <!-- <el-form-item>
              <el-button type="primary" @click="calculateShortestPath">计算最短路径</el-button>
              <el-button @click="clear">清除所有</el-button>
            </el-form-item> -->
          </el-form>
          <div class="importJson">导入json文件</div>
        </div>
        <div class="control-panel">
          <div class="title">机动属性</div>
          <el-form
            @submit.native.prevent="calculateShortestPath"
            label-width="80px"
            label-position="left"
            size="small"
          >
            <el-form-item label="起点">
              <el-input v-model="form.startPoint"></el-input>
            </el-form-item>
            <el-form-item label="终点">
              <el-input v-model="form.endPoint"></el-input>
            </el-form-item>
            <el-form-item label="途径点">
              <el-input v-model="form.viaPoints" placeholder=""></el-input>
            </el-form-item>
            <el-form-item label="避让点">
              <el-input v-model="form.avoidPoints" placeholder=""></el-input>
            </el-form-item>
            <el-form-item label="避让区域">
              <el-input
                type="textarea"
                v-model="form.avoidAreas"
                :rows="4"
                placeholder=""
              ></el-input>
            </el-form-item>
            <!-- <el-form-item>
              <el-button type="primary" @click="calculateShortestPath">计算最短路径</el-button>
              <el-button @click="clear">清除所有</el-button>
            </el-form-item> -->
          </el-form>
          <div class="importJson">导入json文件</div>
        </div>
      </div>
      <!-- <div id="map"></div> -->
      <div id="mapbox"></div>
      <div class="main-container">
        <div class="control-panel"></div>
      </div>
    </div>
  </div>
</template>

<script>
import Header from './header/index.vue'
export default {
  name: '',
  components: {
    Header,
  },
  data() {
    return {
      form: {},
      viewer: null,
      graphicLayer: null,
      polygonZAM: null,
      pointQD: null,
      pointZD: null,
      shortestPathLayer: null,
      roadNetworkLayer: null,
      roadNetworkGeoJSON: null,
      mapOptions: null,
      viaPoints: [], // 途径点
      avoidPoints: [], // 避让点
      avoidAreas: [], // 避让区域
      roadNetworkGeoJSONBuild: null,
    }
  },
  async mounted() {
    await this.getMapOption()
    this.initMap()
  },
  methods: {
    async getMapOption() {
      await fetch('./config/map.json')
        .then((response) => {
          return response.json()
        })
        .then((data) => {
          this.mapOptions = data.map3d
        })
        .catch((error) => {})
    },
    async initMap() {
      this.viewer = new window.mars3d.Map('map', this.mapOptions || {})
      this.graphicLayer = new window.mars3d.layer.GraphicLayer()
      this.viewer.addLayer(this.graphicLayer)

      this.shortestPathLayer = new window.mars3d.layer.GraphicLayer()
      this.viewer.addLayer(this.shortestPathLayer)
      this.loadShapefile()
      // 添加地图点击事件监听，用于结束绘制
      this.viewer.on(mars3d.EventType.dblClick, (event) => {
        // 如果正在绘制，点击地图可以结束绘制（除了绘制点）
        this.graphicLayer.stopDraw()
      })
    },
    clear() {
      // 清除障碍面
      if (this.polygonZAM) {
        this.polygonZAM.remove()
        this.polygonZAM = null
      }

      // 清除起点
      if (this.pointQD) {
        this.pointQD.remove()
        this.pointQD = null
      }

      // 清除终点
      if (this.pointZD) {
        this.pointZD.remove()
        this.pointZD = null
      }

      // 清除途径点
      this.viaPoints.forEach((point) => {
        point.remove()
      })
      this.viaPoints = []

      // 清除避让点
      this.avoidPoints.forEach((point) => {
        point.remove()
      })
      this.avoidPoints = []

      // 清除避让区域
      this.avoidAreas.forEach((area) => {
        area.remove()
      })
      this.avoidAreas = []

      // 清除最短路径图层
      this.shortestPathLayer.clear()

      // 清除路网数据图层
      // this.graphicLayer.clear();
    },
    async loadShapefile() {
      try {
        // 1. 读取本地 SHP（浏览器）
        // const shpBuffer = await fetch('./config/map/data/dlfs_lines.zip').then(r => r.arrayBuffer());
        // const shpJson = await shp(shpBuffer);   // {features: [...]}

        // 1. 读取本地 jeojson
        const shpBuffer = await fetch('./config/map/data/dao.geojson')
          .then((response) => {
            return response.json()
          })
          .then((data) => {
            return data
          })
          .catch((error) => {})

        // 2. 处理 GeoJSON 数据
        this.roadNetworkGeoJSON = shpBuffer

        /// 3. 将 GeoJSON 数据添加到 graphicLayer
        this.roadNetworkGeoJSON.features.forEach((feature) => {
          const positions = feature.geometry.coordinates[0]
          const graphic = new window.mars3d.graphic.PolylineEntity({
            positions: positions,
            style: {
              color: '#FF0000',
              width: 2,
              outline: false,
            },
          })
          this.graphicLayer.addGraphic(graphic)
        })
        this.roadNetworkGeoJSONBuild = this.buildGraph(this.roadNetworkGeoJSON)
      } catch (error) {
        console.error('加载 Shapefile 数据失败:', error)
      }
    },
    async drawPolygon() {
      if (this.polygonZAM) {
        this.polygonZAM.remove()
        this.polygonZAM = null
      }
      this.polygonZAM = await this.graphicLayer.startDraw({
        type: 'polygon',
        style: {
          color: '#00ffff',
          opacity: 0.4,
          clampToGround: true,
          outline: true,
          outlineWidth: 1,
          outlineColor: '#ffffff',
        },
      })
    },
    drawStartPoint() {
      if (this.pointQD) {
        this.pointQD.remove()
        this.pointQD = null
      }
      this.graphicLayer.startDraw({
        type: 'point',
        style: {
          pixelSize: 10,
          color: 'red',
          label: {
            text: '起点',
            font_size: 20,
            color: '#ffffff',
            outline: true,
            outlineColor: '#000000',
            pixelOffsetY: -20,
          },
        },
        success: (graphic) => {
          this.pointQD = graphic
          this.graphicLayer.stopDraw()
        },
      })
    },
    drawEndPoint() {
      if (this.pointZD) {
        this.pointZD.remove()
        this.pointZD = null
      }
      this.graphicLayer.startDraw({
        type: 'point',
        style: {
          pixelSize: 10,
          color: 'red',
          label: {
            text: '终点',
            font_size: 20,
            color: '#ffffff',
            outline: true,
            outlineColor: '#000000',
            pixelOffsetY: -20,
          },
        },
        success: (graphic) => {
          this.pointZD = graphic
          this.graphicLayer.stopDraw()
        },
      })
    },
    // 途径点
    drawViaPoint() {
      this.graphicLayer.startDraw({
        type: 'point',
        style: {
          pixelSize: 10,
          color: 'blue',
          label: {
            text: '途径点',
            font_size: 20,
            color: '#ffffff',
            outline: true,
            outlineColor: '#000000',
            pixelOffsetY: -20,
          },
        },
        success: (graphic) => {
          this.viaPoints.push(graphic)
          this.graphicLayer.stopDraw()
        },
      })
    },
    // 避让点
    drawAvoidPoint() {
      this.graphicLayer.startDraw({
        type: 'point',
        style: {
          pixelSize: 10,
          color: 'orange',
          label: {
            text: '避让点',
            font_size: 20,
            color: '#ffffff',
            outline: true,
            outlineColor: '#000000',
            pixelOffsetY: -20,
          },
        },
        success: (graphic) => {
          this.avoidPoints.push(graphic)
          this.graphicLayer.stopDraw()
        },
      })
    },
    // 避让区域
    drawAvoidArea() {
      this.graphicLayer.startDraw({
        type: 'polygon',
        drawEndEventType: window.mars3d.EventType.dblClick,
        style: {
          color: '#ff0000',
          opacity: 0.4,
          clampToGround: true,
          outline: true,
          outlineWidth: 1,
          outlineColor: '#ffffff',
        },
        success: (graphic) => {
          this.avoidAreas.push(graphic)
          this.graphicLayer.stopDraw()
        },
      })
    },
    // 1. 构建路网拓扑图（经纬度坐标直接处理
    buildGraph(geojson) {
      const graph = {}
      const nodeCoords = {} // 存储节点经纬度

      geojson.features.forEach((road) => {
        const startNode = road.properties.FNODE_
        const endNode = road.properties.TNODE_
        const coords = road.geometry.coordinates

        // 记录节点经纬度（取首尾点）
        if (!nodeCoords[startNode]) {
          nodeCoords[startNode] = coords[0][0]
        }
        if (!nodeCoords[endNode]) {
          nodeCoords[endNode] = coords[coords.length - 1][0]
        }
        // 计算边权重（距离，单位：米）
        const distance =
          turf.distance(
            turf.point(coords[0][0]),
            turf.point(coords[coords.length - 1][0]),
            {units: 'kilometers'}
          ) * 1000

        // 构建邻接表（双向图）
        graph[startNode] = graph[startNode] || {}
        graph[startNode][endNode] = distance

        graph[endNode] = graph[endNode] || {}
        graph[endNode][startNode] = distance
      })

      return {graph, nodeCoords}
    },
    // 2. 匹配最近路网节点（经纬度坐标）
    findNearestNode(pointCoord, nodeCoords) {
      let nearestNode = null
      let minDist = 10000

      for (const [node, coord] of Object.entries(nodeCoords)) {
        const dist = turf.distance(turf.point(pointCoord), turf.point(coord), {
          units: 'meters',
        })

        if (dist < minDist) {
          minDist = dist
          nearestNode = node
        }
      }
      return nearestNode
    },
    // 3. 路径规划主函数（经纬度坐标输入） - 支持途径点 + 避让点/区域
    async planRoute(
      startCoord,
      endCoord,
      viaPoints = [],
      avoidObstacles = null
    ) {
      const {graph, nodeCoords} = this.roadNetworkGeoJSONBuild

      // 按顺序组合点：起点 -> 途径点 -> 终点
      const points =
        viaPoints && viaPoints.length > 0
          ? [startCoord, viaPoints[0].geometry.coordinates, endCoord]
          : [startCoord, endCoord]
      const fullPath = []

      for (let i = 0; i < points.length - 1; i++) {
        const segmentStart = points[i]
        const segmentEnd = points[i + 1]

        // 匹配最近节点
        const startNode = this.findNearestNode(segmentStart, nodeCoords)
        const endNode = this.findNearestNode(segmentEnd, nodeCoords)

        if (!startNode || !endNode) {
          console.log('无法匹配到路网节点，请检查坐标是否在路网范围内')
          continue
        }
        // 构建临时 graph
        const tempGraph = JSON.parse(JSON.stringify(graph))

        // 删除避让点节点
        if (avoidObstacles) {
          const obstacleNodes = []
          for (const [node, coord] of Object.entries(nodeCoords)) {
            const pt = turf.point(coord)
            avoidObstacles.features.forEach((ob) => {
              if (turf.booleanPointInPolygon(pt.geometry, ob.geometry))
                obstacleNodes.push(node)
            })
          }
          obstacleNodes.forEach((node) => delete tempGraph[node])

          // 删除与避让区域相交的边
          for (const [node, edges] of Object.entries(tempGraph)) {
            for (const targetNode of Object.keys(edges)) {
              if (!tempGraph[targetNode]) {
                // 避让点节点已经删除
                delete tempGraph[node][targetNode]
                continue
              }
              const line = turf.lineString([
                nodeCoords[node],
                nodeCoords[targetNode],
              ])
              avoidObstacles.features.forEach((area) => {
                if (turf.booleanCrosses(line, area)) {
                  delete tempGraph[node][targetNode]
                }
              })
            }
          }
        }

        // Dijkstra 计算最短路径
        const pathNodes = dijkstra.find_path(tempGraph, startNode, endNode)
        if (!pathNodes || pathNodes.length === 0) {
          console.log('未找到可行路径段:', i)
          continue
        }

        // 生成路径几何
        for (let j = 0; j < pathNodes.length - 1; j++) {
          const currentNode = pathNodes[j]
          const nextNode = pathNodes[j + 1]
          const segment = this.roadNetworkGeoJSON.features.find(
            (f) =>
              (f.properties.FNODE_ == currentNode &&
                f.properties.TNODE_ == nextNode) ||
              (f.properties.FNODE_ == nextNode &&
                f.properties.TNODE_ == currentNode)
          )
          if (segment) {
            fullPath.push(...segment.geometry.coordinates[0])
          }
        }
      }

      return fullPath
    },
    async calculateShortestPath() {
      if (!this.pointQD || !this.pointZD || !this.roadNetworkGeoJSON) {
        alert('请先加载路网数据并绘制障碍面、起点和终点！')
        return
      }
      this.shortestPathLayer.clear()
      const startPoint = turf.point(
        this.pointQD.toGeoJSON().geometry.coordinates
      ).geometry.coordinates // 起点
      const endPoint = turf.point(this.pointZD.toGeoJSON().geometry.coordinates)
        .geometry.coordinates // 终点
      // 途径点
      const viaPointsGeoJSON =
        this.viaPoints.map((point) => point.toGeoJSON()) || []
      const viaPointsTurf = viaPointsGeoJSON.map((p) =>
        turf.point(p.geometry.coordinates)
      )
      // 避让点
      const avoidPointsGeoJSON =
        this.avoidPoints.map((point) => point.toGeoJSON()) || []
      const avoidPointsPolygons = avoidPointsGeoJSON.map((point) => {
        return turf.circle(
          turf.point(point.geometry.coordinates),
          10, // 半径10米（根据需求调整）
          {steps: 32, units: 'meters'} // 显式指定单位
        )
      })
      // 避让区域
      const avoidAreasGeoJSON =
        this.avoidAreas.map((area) => area.toGeoJSON({closure: true})) || []
      const obstaclesGeoJSON = turf.featureCollection([
        ...avoidPointsPolygons,
        ...avoidAreasGeoJSON,
      ])
      const route = await this.planRoute(
        startPoint,
        endPoint,
        viaPointsTurf,
        obstaclesGeoJSON
      )
      this.drawPath(route)
    },

    // 单独的路径绘制方法
    drawPath(path) {
      const positions = path
      const polyline = new window.mars3d.graphic.PolylinePrimitive({
        positions: positions,
        style: {
          clampToGround: true,
          color: '#55ff33',
          width: 8,
        },
      })
      this.shortestPathLayer.addGraphic(polyline)
    },
  },
}
</script>

<style scoped>
.home-header {
  height: 60px;
  line-height: 60px;
  display: flex;
  align-items: center;
  padding-left: 34px;
  box-sizing: border-box;
  background: #abc6bc;
}
.home-header img {
  height: 24px;
  width: 24px;
  margin-right: 12px;
}
.sure {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  /* padding: 4px 12px; */
  gap: 10px;
  background: #176363;
  border-radius: 4px;
  width: 54px;
  height: 24px;
  color: #ffffff;
  font-weight: 400;
  font-size: 14px;
  position: absolute;
  right: 30px;
}
.home {
  display: flex;
  height: calc(100% - 60px);
  background: #abc6bc;
}
.main-container {
  width: 100%;
  height: 100%;
}

.control-panel {
  width: 340px;
  padding: 20px 26px;
  margin-left: 4px;
  background-size: cover;
  background: #d4e5db;
}

.control-panel .title {
  /* text-align: center; */
  margin-bottom: 10px;
  color: #1c1c1c;
}
.importJson {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  background: #2f705f;
  border-radius: 4px;
  color: #fff;
  width: 260px;
  height: 24px;
  font-size: 14px;
  text-align: center;
  margin-left: 40px;
}

.form-group {
  margin-bottom: 10px;
}

.form-group input,
.form-group textarea {
  width: 100%;
  padding: 5px;
  border-radius: 3px;
  border: none;
}

.form-actions {
  display: flex;
  justify-content: space-between;
}

#map,
#mapbox,
.el-main {
  flex: 1;
  width: 100%;
  height: 100%;
  border: 1px solid #333;
}
</style>