<template>
  <div class="h-100">
    <!-- 地图组件 -->
    <map-box ref="mapbox" v-if="swarmReady" :enableShowNofly="true" :enableGuided="true"
      :enblueScale="!$store.state.app.isWideScreen" @longPress="handleLongPress" @map-ready="onMapReady">
      <template #content>
        <div v-show="mapReady">
          <SwarmControllerTabs :planes="planeList" />
        </div>
      </template>
    </map-box>
    <!-- 弹出框 -->
    <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="320px" top="30vh" @close="closeCallback"
      @open="openCallback">
      <!-- 点飞设置弹出框 -->
      <template v-if="dialogItem == 'guidedBox'">
        <el-form label-position="left">
          <el-form-item label="中心纬度" label-width="80px">
            <el-input v-model="guidedLonLat.lat" placeholder="请输维度" label="纬度"></el-input>
          </el-form-item>
          <el-form-item label="中心经度" label-width="80px">
            <el-input v-model="guidedLonLat.lon" placeholder="请输经度" label="经度"></el-input>
          </el-form-item>
          <el-form-item label="中心高度" label-width="80px">
            <el-input-number v-model="guidedAlt" label="高度设置"></el-input-number>
            <font class="m-l-5">米</font>
          </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
          <el-button size="medium" @click="dialogVisible = false">关闭</el-button>
          <el-button size="medium" type="primary" @click="onSwarmFlyTo">飞至</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import MapBox from '@/components/MapBox'
import SwarmControllerTabs from '@/components/SwarmControllerTabs.vue'
import { waitForMapCanvasReady, getBoundingCenter } from '@/utils'
import mqtt from '@/utils/mqtt'

export default {
  name: 'Swarm',
  data () {
    return {
      dialogTitle: '', // 弹出框 标题
      dialogItem: '', // 弹出框 项目类型判断
      dialogVisible: false, // 弹出框 显隐
      guidedLonLat: {}, // 点飞 的经纬度
      guidedAlt: '', // 点飞的高度
      isReserveGuidedMaker: false, // 关闭指点飞行操作窗口时 标记是否删除图标
      mapReady: false, // 地图加载完成后 回调时 设置此值  让地图组件插槽内容 滞后显示
      swarmReady: false// 判断有没有选中两架以上集群 用于控制地图组件渲染
    }
  },
  components: {
    MapBox,
    SwarmControllerTabs
  },
  computed: {
    // 选中的集群控制飞机s
    planeList () {
      const allPlanes = this.$store.state.airList
      const idArr = this.$store.state.app.swarmIdArr
      return allPlanes.filter(plane => idArr.includes(plane.id))
    },
    // 过滤出所有飞机状态列表s
    planeStatus () {
      return this.planeList.map(plane => plane.planeState)
    },
    /**
   * @description: 所有飞机的历史定位数组集合，每个元素是一架飞机的 position 数组
   */
    planePositions () {
      return this.planeList.map(plane => {
        const posArr = plane.planeState?.position
        return Array.isArray(posArr) ? posArr : []
      })
    },
    /**
     * @description: 派生出与“图标选择”强相关的轻量状态，供独立 watcher 监控
     * offline: 是否离线；run: 载重是否超过阈值（>300）
     */
    planeIconStates () {
      return this.planeList.map(plane => {
        const s = plane.planeState || {}
        const n = Number(s.loadweight)
        return {
          offline: s.online === false,
          run: Number.isFinite(n) && n > 300
        }
      })
    },
    /**
     * @description: 侧边栏显隐
     */
    isCollapse () {
      return this.$store.state.app.isCollapse
    }
  },
  created () {
    // 集群控制至少需要2架飞机
    if (this.$store.state.app.swarmIdArr.length < 2) {
      this.$router.replace('/register/index')// 如果集群控制飞机数量小于2架 则跳转列表页
    } else {
      this.swarmReady = true // 只有当数据条件满足才渲染 <map-box>
    }

    // // 测试单元
    // setInterval(() => {
    //   const centerLng = 116.397 // 中心经度（北京）
    //   const centerLat = 39.908 // 中心纬度
    //   const maxOffset = 0.0002 // 经纬度最大偏移 ≈ ±200 米

    //   this.$store.state.airList.forEach((plane) => {
    //     if (!plane.planeState) {
    //       plane.planeState = {}
    //     }

    //     // 经纬度偏移
    //     const offsetLng = (Math.random() - 0.5) * 2 * maxOffset
    //     const offsetLat = (Math.random() - 0.5) * 2 * maxOffset
    //     const randomLng = Number((centerLng + offsetLng).toFixed(7))
    //     const randomLat = Number((centerLat + offsetLat).toFixed(7))

    //     // ✅ 随机高度：40～60 米之间
    //     const randomAlt = Number((40 + Math.random() * 20).toFixed(2))

    //     // 设置随机位置
    //     this.$store.commit('updatePlanePosition', {
    //       planeId: plane.id,
    //       position: [[randomLng, randomLat, randomAlt]]
    //     })
    //   })
    // }, 15000)
  },
  methods: {
    /** 弹出框 关闭事件回调 */
    closeCallback () {
      if (this.dialogItem === 'guidedBox' && this.isReserveGuidedMaker === false) { // 关闭点飞窗口时
        this.$refs.mapbox.delGuidedMarker()// 删除所有点飞的地图标记
        this.$refs.mapbox.clearMapElements(['guided-lines-layer', 'guided-center-point-layer'], ['guided-lines-source'])// 删除引导线
      }
      this.dialogVisible = false
      this.dialogItem = ''
    },
    /** 弹出框 打开事件回调 */
    openCallback () {
    },
    /**
 * @abstract 地图长按事件处理
 * @param {Object} lonLat - 点击地图终点经纬度，如 { lng: number, lat: number }
 */
    handleLongPress (lonLat) {
      this.isReserveGuidedMaker = false
      this.dialogTitle = '集群指点'
      this.dialogVisible = true
      this.dialogItem = 'guidedBox'
      this.guidedLonLat = lonLat

      // ① 获取所有飞机位置 [[lng, lat, alt], ...]
      const allPlaneCoords = this.planeList.map(p => {
        const pos = p?.planeState?.position
        const last = Array.isArray(pos) && pos.length > 0 ? pos[pos.length - 1] : null
        return Array.isArray(last) ? [last[0], last[1], last[2] || 0] : null
      }).filter(Boolean)

      // ② 计算平均高度并更新引导高度
      if (allPlaneCoords.length > 0) {
        const totalAlt = allPlaneCoords.reduce((sum, item) => sum + (item[2] || 0), 0)
        this.guidedAlt = Number((totalAlt / allPlaneCoords.length).toFixed(1))
      } else {
        this.guidedAlt = 0
      }

      // ③ 获取飞机重心点（使用工具函数 getBoundingCenter）
      const center = getBoundingCenter(allPlaneCoords) // 返回 { lng, lat }

      // ④ 绘制引导线与中心点
      this.$refs.mapbox.drawGuidedLines({
        centerPoint: { lng: center.lon, lat: center.lat },
        endPoint: { lng: lonLat.lon, lat: lonLat.lat },
        planeCoords: allPlaneCoords.map(([lng, lat]) => [lng, lat]) // 可选：去掉alt
      })
    },
    // 集群指点飞行  保持所有飞机拓扑关系飞到指定位置
    onSwarmFlyTo () {
      const targetLon = Number(this.guidedLonLat.lon)
      const targetLat = Number(this.guidedLonLat.lat)
      const targetAlt = Number(this.guidedAlt)

      if (
        isNaN(targetLon) || isNaN(targetLat) || isNaN(targetAlt) ||
        targetLon < -180 || targetLon > 180 ||
        targetLat < -90 || targetLat > 90
      ) {
        this.$message.warning('请输入有效的经纬度（经度-180~180，纬度-90~90）和高度')
        return
      }

      // 取所有飞机的最新定位点，组成坐标数组，传入 getBoundingCenter，求中心点
      const positions = this.planeList.map(p => {
        const pos = p?.planeState?.position
        // 取最后一个点（最新点），如果没有位置就用 null 过滤掉
        if (!Array.isArray(pos) || pos.length === 0) return null
        return pos[pos.length - 1]
      }).filter(Boolean)

      // 求所有飞机最新定位点的包围盒中心点
      const currentCenter = getBoundingCenter(positions)

      if (!currentCenter) {
        this.$message.error('无法获取飞行器中心位置，检查飞机是否都已定位')
        return
      }

      let minTargetAlt = Infinity // 标记最矮飞机 的目标高度 初始化为正无穷大
      // 计算每架飞机相对于当前中心的偏移量
      const commands = this.planeList.map(p => {
        const pos = p?.planeState?.position
        const last = Array.isArray(pos) && pos.length > 0 ? pos[pos.length - 1] : null
        if (!Array.isArray(last)) return null

        const offsetLon = last[0] - currentCenter.lon
        const offsetLat = last[1] - currentCenter.lat
        const offsetAlt = last[2] - currentCenter.alt

        const newLon = targetLon + offsetLon
        const newLat = targetLat + offsetLat
        const newAlt = targetAlt + offsetAlt

        if (newAlt < minTargetAlt) {
          minTargetAlt = newAlt
        }

        return {
          macadd: p.macadd,
          cmd: `{guidedMode:{lon:${newLon.toFixed(7)},lat:${newLat.toFixed(7)},alt:${newAlt.toFixed(1)}}}`
        }
      }).filter(Boolean)

      // 最矮的飞机小于地面高度 返回
      if (minTargetAlt < 0) {
        this.$message.warning(`指令已取消：最矮飞机将飞到地面以下（最低高度 ${minTargetAlt.toFixed(1)} 米）`)
        return
      }

      // 发送控制指令
      commands.forEach(({ macadd, cmd }) => {
        mqtt.publishFun(`cmd/${macadd}`, cmd)
      })

      this.isReserveGuidedMaker = true
      this.dialogVisible = false
    },
    // 地图组件回调地图加载完成后 执行
    onMapReady () {
      this.mapReady = true // 标记地图加载完成
      this.makePlanes(this.planeList)
    },
    /**
     * @description: 创建飞机图标
     */
    makePlanes (planes) {
      this.$refs.mapbox.removePlanes()// 先清除画布上现有的飞机
      planes.forEach((plane, index) => { // 创建所有飞机
        let planeDefaultLonLat
        if (localStorage.getItem(plane.name) !== null) { // 从本地缓存 拿飞机得初始位置
          planeDefaultLonLat = JSON.parse(localStorage.getItem(plane.name))
          plane.lon = planeDefaultLonLat.lon
          plane.lat = planeDefaultLonLat.lat
        } else {
          // 缺省 给经纬度 小数点后随机第五位 即有个10米左右的随机距离
          plane.lon = 100 + Number((Math.random() * 0.01).toFixed(5))
          plane.lat = 40 + Number((Math.random() * 0.01).toFixed(5))
        }
        this.$refs.mapbox.makePlane(plane, index)
      })
    }
  },
  watch: {
    /**
     * @description: 飞机列表更新时候 更新地图
     */
    planeList: {
      async handler () {
        try {
          // 等待地图画布准备好
          await waitForMapCanvasReady(this.$refs.mapbox.map)
          // 画布准备好后执行你自己的逻辑
          this.onMapReady()
        } catch (err) {
          console.debug('等待地图画布准备超时', err)
        }
      },
      immediate: true
    },
    // 实时更新所有状态 到对应飞机弹出框
    planeStatus: {
      handler (val) {
        val.forEach((stateObj, index) => {
          stateObj.name = this.planeList[index].name // 保留飞机名称
          this.$refs.mapbox.updatePopupContent(stateObj, index)
        })
      },
      deep: true
    },
    // 专门监听轻量图标状态，必要时才更新图标，避免不必要的 DOM 操作
    planeIconStates: {
      handler (val, oldVal) {
        val.forEach((iconState, index) => {
          const prev = Array.isArray(oldVal) ? oldVal[index] : undefined
          const changed = !prev || prev.offline !== iconState.offline || prev.run !== iconState.run
          if (changed) {
            const stateObj = this.planeList[index].planeState || {}
            this.$refs.mapbox.updatePlaneIcon(stateObj, index)
          }
        })
      },
      deep: true
    },
    // 实时更新所有飞机位置 和轨迹
    planePositions: {
      handler (allPositions) {
        // allPositions 是一个数组，每个元素是该飞机的 position 数组
        allPositions.forEach((positions, idx) => {
          const n = positions.length
          if (n > 2) {
            const [lon, lat] = positions[n - 1]
            // 定期存储 (例如每100次) 当前飞机的位置
            const key = `swarm_plane_${this.planeList[idx].name}`
            // 初始化本地计数器
            if (!this._storeCount) this._storeCount = {}
            const cnt = (this._storeCount[key] = (this._storeCount[key] || 0) + 1)
            if (cnt % 100 === 1) {
              localStorage.setItem(key, JSON.stringify({ lon, lat }))
            }

            // 更新 MapBox 中第 idx 架飞机的位置与轨迹
            this.$refs.mapbox.setPlaneLonLat({ lon, lat }, idx, positions)
          }
        })
      },
      deep: true
    },
    /**
     * @description: 侧边栏缩进有变化时 地图重新自适应
     */
    isCollapse: {
      handler (val) {
        if (val) {
          setTimeout(() => {
            this.$nextTick(() => {
              this.$refs.mapbox.handleResize()
            })
          }, 500)
        }
      },
      deep: true
    }
  }
}
</script>

<style lang="scss" scoped></style>
