<template>
  <el-container id="layoutBox">
    <el-aside class="animation" :class="isCollapse ? 'menuW' : 'menuS'">
      <Menubar />
    </el-aside>
    <el-container>
      <el-header>
        <Headbar />
      </el-header>
      <el-main>
        <router-view :key="rouKey" />
      </el-main>
      <el-footer>
        <BlogBox />
      </el-footer>
    </el-container>
  </el-container>
</template>

<script>
import mqtt from '@/utils/mqtt'
import geodist from 'geodist'
import { saveFlyData } from '@/utils/api/table'
import Menubar from '@/views/layout/components/menubar'
import Headbar from '@/views/layout/components/headbar'
import BlogBox from '@/views/layout/components/BlogBox'

export default {
  name: 'Layout',
  data () {
    return {
      frequencySetTimeout: null // 对频信息保持
    }
  },
  methods: {
    // 加锁时 解构 并 上传飞行数据
    async handleFlightDataUpload (plane) {
      const flyData = { ...plane.planeState.flyDataSave }
      const path = flyData.path || []
      const distanceList = []

      // 记录加锁时间与电量
      flyData.endTime = Math.floor(Date.now() / 1000)
      flyData.endBattery = plane.planeState.batteryRemaining

      // 计算累计飞行距离
      let totalDistance = 0
      for (let i = 1; i < path.length; i++) {
        const prev = path[i - 1]
        const curr = path[i]
        const dist = geodist(
          { lat: prev[1], lon: prev[0] },
          { lat: curr[1], lon: curr[0] },
          { exact: true, unit: 'meters' }
        )
        totalDistance += dist
        distanceList.push(dist)
      }

      // 计算电量消耗
      const batteryDrop = Number(flyData.startBattery) - Number(flyData.endBattery)
      const totalCapacity = Number(plane.planeState.battCapacity)
      const powerUsed = Math.round(totalCapacity / 100 * batteryDrop)

      // 构造上传数据
      const uploadData = {
        plane_id: plane.id,
        start_time: flyData.startTime,
        end_time: flyData.endTime,
        gps_path: JSON.stringify(path),
        distance: Math.round(totalDistance),
        power_used: powerUsed
      }
      try {
        await saveFlyData(uploadData)
      } catch (err) {
        console.error('上传飞行数据失败', err)
      }
    }
  },
  components: {
    Menubar,
    Headbar,
    BlogBox
  },
  computed: {
    rouKey () {
      return this.$route.path
    },
    isCollapse () {
      return this.$store.state.app.isCollapse
    },
    shop_id () {
      return this.$store.state.user.shop_id
    },
    airList () {
      return this.$store.state.airList
    },
    shopList () {
      return this.$store.state.shopList
    }
  },
  mounted () {
    // 定时清理过期的ADSB数据
    setInterval(() => {
      if (this.$store.state.ADSBList.length > 0) {
        this.$store.commit('cleanExpiredADSBList')
      }
    }, 5000)
  },
  created () {
    /* init */
    this.$store.commit('app/setIsMobile')
    Promise.all([
      this.$store.dispatch('fetchPlaneClassList'),
      this.$store.dispatch('fetchAirList'),
      this.$store.dispatch('fetchShopList'),
      this.$store.dispatch('fetchAdminList'),
      this.$store.dispatch('fetchSiteList'),
      this.$store.dispatch('fetchRouteList'),
      this.$store.dispatch('fetchCategoryList'),
      this.$store.dispatch('fetchSpuList'),
      this.$store.dispatch('fetchSkuList'),
      this.$store.dispatch('fetchPaidOrderList'),
      this.$store.dispatch('fetchMessageList'),
      this.$store.dispatch('fetchMapStyleList', this.$store.state.settings.host)
    ]).then(() => {
      return this.$store.dispatch('fetchNoflyData', this.shop_id)
    })
  },
  watch: {

    /**
     * @description: 异步拿到飞机列表之后 再进行一些初始化操作
     * @param {*} res 飞机列表
     */
    airList (res) {
      /* mqtt */
      mqtt.mqttConf()// 连接mqtt
      // 订阅飞机信息
      mqtt.doSubscribe('planeState/+', (mqttRes) => {
        res.forEach(plane => {
          if (plane.macadd && mqttRes.topic.indexOf(plane.macadd) > -1) {
            try {
              // 反序列化 mqtt信息
              const jsonData = JSON.parse(mqttRes.msg.trim())

              // 更新mqtt信息 选择性更新状态
              for (const key in jsonData) {
                if (key === 'heartBeat') {
                  // 每次接收到心跳时，更新随机数以触发 watch 监听
                  plane.planeState.heartRandom = Math.random()
                  plane.planeState.heartBeat = jsonData.heartBeat

                  /* 判断飞机是否在线 */
                  // 设置为在线
                  plane.planeState.online = true
                  // 清除旧的离线定时器
                  if (plane.planeState.onlineTimeout) {
                    clearTimeout(plane.planeState.onlineTimeout)
                  }
                  // 重新设定掉线判断定时器（如10秒内无心跳，则为离线）
                  plane.planeState.onlineTimeout = setTimeout(() => {
                    plane.planeState.online = false
                  }, 10000)

                  /* 飞行数据上传 */
                  const oldMark = plane.planeState.isUnlock
                  const newMark = (Number(jsonData.heartBeat) & 128) !== 0

                  // 解锁状态变更检测：用于控制飞行数据的采集与上传
                  if (!oldMark && newMark) {
                    // 从加锁切换为解锁：初始化飞行数据记录
                    plane.planeState.isUnlock = true
                    plane.planeState.flyDataSave = {
                      startTime: Math.floor(Date.now() / 1000), // 解锁时间（秒）
                      startBattery: plane.planeState.batteryRemaining,
                      endTime: null,
                      endBattery: null,
                      path: []
                    }
                  } else if (oldMark && !newMark) {
                    plane.planeState.isUnlock = false

                    this.handleFlightDataUpload(plane) // 上传飞行数据

                    // 上传完成后清空记录缓存
                    plane.planeState.flyDataSave = {
                      startTime: null, // 解锁时的时间戳（秒）
                      endTime: null, // 加锁时的时间戳（秒）
                      startBattery: null, // 解锁时的电池电量（百分比）
                      endBattery: null, // 加锁时的电池电量（百分比）
                      path: []
                    }
                  }
                } else if (key === 'position') {
                  // 如果是飞机位置信息 则不是直接刷新状态 而是累计 到数组 以便于画出飞机路径
                  const position = JSON.parse(jsonData.position)
                  // 检查 lon, lat, 和 alt 是否不全为零或空值
                  if (position.lon !== 0 && position.lat !== 0 &&
                    position.lon !== null && position.lat !== null &&
                    position.lon !== '' && position.lat !== '') {
                    plane.planeState.position.push([position.lon / 10e6, position.lat / 10e6, Number(position.alt)])
                  }
                  if (plane.planeState.position.length > 1000) {
                    plane.planeState.position.shift() // 删除最早的经纬度
                  }
                  // 如果是解锁状态，记录轨迹用于上传
                  if (plane.planeState.isUnlock && plane.planeState.flyDataSave?.path) {
                    plane.planeState.flyDataSave.path.push([
                      position.lon / 10e6,
                      position.lat / 10e6,
                      Number(position.alt)
                    ])
                  }
                } else if (key === 'homePosition') {
                  const homePosition = JSON.parse(jsonData.homePosition)// home点反序列化再赋值
                  homePosition.lon = homePosition.lon / 10e6
                  homePosition.lat = homePosition.lat / 10e6
                  homePosition.alt = Number(homePosition.alt)
                  plane.planeState[key] = homePosition
                } else if (key === 'statusText') {
                  /* 飞控信息 插入日志 */
                  this.$store.dispatch('fetchLog', { content: `${plane.name}--${jsonData[key]}`, color: '#f57c00' })
                } else {
                  plane.planeState[key] = jsonData[key] // 按订阅信息 刷新飞机状态
                  // 重量更新时，派生更新是否有货标记
                  if (key === 'loadweight') {
                    const n = Number(jsonData[key])
                    plane.planeState.hasGoods = Number.isFinite(n) && n > 300
                  }
                }
              }
            } catch (error) {
              console.error('Error parsing JSON or processing message:', error)
            }
          }
        })
      })
      // 订阅ADSB信息
      mqtt.doSubscribe('ADSB/+', (res) => {
        if (res.topic.indexOf('ADSB') > -1) {
          const data = JSON.parse(res.msg)
          this.$store.commit('setADSBList', data)
        }
      })
      // 订阅对频
      mqtt.doSubscribe('crosFrequency/+', (res) => {
        if (res.topic.indexOf('crosFrequency') > -1) {
          this.$store.commit('setCrosFrequency', res.msg)// 设置对频信息
          clearTimeout(this.frequencySetTimeout)// 接收到新的订阅信息 清除之前的倒计时
          this.frequencySetTimeout = setTimeout(() => { // 倒计时10秒 随之清除缓存中对频信息
            this.$store.commit('setCrosFrequency', null)
          }, 10000)
        }
      })
      // 订阅游客下单频道
      mqtt.doSubscribe(`refreshQuestList/${this.shop_id}`, (res) => {
        if (res.topic.indexOf(`refreshQuestList/${this.shop_id}`) > -1) {
          this.$store.dispatch('fetchSiteList')// 刷新站点列表
          this.$store.dispatch('fetchPaidOrderList')// 刷新订单列表 ps:待发货及待收货 并且不是退款成功状态
        }
      })
      // 向所有飞机发送 让飞控刷新各种请求
      res.forEach(item => {
        mqtt.publishFun(`cmd/${item.macadd}`, '{"refreshRequest":1}')
      })
    }
  },
  destroyed () {
    mqtt.mqttDestroy()// 断开mqtt
  }
}
</script>

<style lang="scss" scoped>
@import "@/styles/theme.scss";

#layoutBox {
  height: 100%;
}

.el-aside {
  background-color: #304156;
  overflow: hidden !important;
}

.menuW {
  width: 60px !important;
}

/* 竖屏模式样式 */
@media (orientation: portrait) {
  .menuW {
    width: 0px !important;
  }
}

.menuS {
  width: 210px !important;
}

.el-header {
  padding: 0 !important;
  height: 50px !important;
  line-height: 50px !important;
  overflow: hidden;
  z-index: 99;
  box-shadow: 0 0px 4px rgba(0, 21, 41, .08);
}

.el-main {
  padding: 0 !important;
  height: 100%;
  background-color: $white-color;
}

.el-footer {
  height: 24px !important;
}
</style>
