<template>
  <view style="height:100vh;">
    <view id="map"></view>

    <view class="info-box">
      <text>{{currentStep}}</text>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      map: null,
      routeLatLngs: [],
      marker: null,
      watchId: null,
      currentStep: "正在规划路线...",
      instructions: [],
      instrIndex: 0,
      start: [39.916527, 116.397128],
      end: [39.904211, 116.407395]
    };
  },

  onReady() {
    this.initMap();
    this.calcRoute();
    this.startGPS();
  },

  methods: {
    /** 1. 初始化地图 */
    initMap() {
      this.map = L.map("map").setView(this.start, 15);

      L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
        maxZoom: 19,
      }).addTo(this.map);
    },

    /** 2. GraphHopper 路线规划 */
    calcRoute() {
      const url =
        `https://graphhopper.com/api/1/route?` +
        `point=${this.start[0]},${this.start[1]}` +
        `&point=${this.end[0]},${this.end[1]}` +
        `&vehicle=car&instructions=true&locale=cn&key=fb959050-3a0c-4c6b-b722-5c322b2085c9`;

      uni.request({
        url,
        success: (res) => {
          const path = res.data.paths[0];
          this.instructions = path.instructions;

          const coords = path.points.coordinates;
          this.routeLatLngs = coords.map(c => [c[1], c[0]]);

          // 绘路线
          L.polyline(this.routeLatLngs, { color: "blue", weight: 5 }).addTo(this.map);
          this.map.fitBounds(this.routeLatLngs);

          // 设置起点终点 Marker
          L.marker(this.start).addTo(this.map).bindPopup("起点");
          L.marker(this.end).addTo(this.map).bindPopup("终点");

          this.currentStep = "路线规划完成，开始导航...";
        }
      });
    },

    /** 3. 开始实时 GPS 监听 */
    startGPS() {
      const _this = this;

      this.watchId = navigator.geolocation.watchPosition(
        (pos) => {
          const lat = pos.coords.latitude;
          const lng = pos.coords.longitude;

          _this.updatePosition(lat, lng);
          _this.checkNextInstruction(lat, lng);
        },
        (err) => { console.log("GPS error:", err); },
        { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 }
      );
    },

    /** 4. 更新用户位置 + 地图跟随 */
    updatePosition(lat, lng) {
      if (!this.marker) {
        this.marker = L.marker([lat, lng]).addTo(this.map);
      } else {
        this.marker.setLatLng([lat, lng]);
      }

      // 地图跟随
      this.map.panTo([lat, lng]);
    },

    /** 5. 判断导航步骤 */
    checkNextInstruction(lat, lng) {
      if (!this.instructions.length) return;

      const step = this.instructions[this.instrIndex];
      const [fromIdx, toIdx] = step.interval;

      const stepCoords = this.routeLatLngs[fromIdx];

      const dist = this.getDistance(lat, lng, stepCoords[0], stepCoords[1]);

      if (dist < 20) { // 距离下一个步骤 < 20 米时触发
        this.currentStep = step.text;

        // 进入下一步
        if (this.instrIndex < this.instructions.length - 1) {
          this.instrIndex++;
        }
      }
    },

    /** 工具：两点间距离 */
    getDistance(lat1, lon1, lat2, lon2) {
      const R = 6378137;
      const dLat = (lat2 - lat1) * Math.PI / 180;
      const dLon = (lon2 - lon1) * Math.PI / 180;
      const a =
        Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.cos(lat1 * Math.PI/180) *
        Math.cos(lat2 * Math.PI/180) *
        Math.sin(dLon/2) * Math.sin(dLon/2);
      return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    }
  },

  onUnload() {
    if (this.watchId) {
      navigator.geolocation.clearWatch(this.watchId);
    }
  }
};
</script>

<style>
#map { width: 100%; height: 75vh; }
.info-box {
  padding: 20rpx;
  font-size: 32rpx;
}
</style>

<!-- Leaflet -->
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css">
