<template>
  <div class="my-ships-main" id="map">
    <!-- 气象点击显示内容组件 -->
    <OnClickWeather></OnClickWeather>
    <!-- 港口鼠标悬浮显示内容组件 -->
    <PortHoverView></PortHoverView>
    <!-- 船舶鼠标悬浮时显示信息组件 -->
    <ShipHoverView></ShipHoverView>
    <!-- 地图底部船舶类型备注框组件 -->
    <MapBottomShipType :carData="carData" :shipData="shipData"></MapBottomShipType>
    <!-- 地图底部鼠标位置经纬度显示组件 -->
    <MapBottomMousePos></MapBottomMousePos>
    <!-- 弹窗最小化组件 -->
    <MiniBox></MiniBox>
    <!-- 船舶轨迹鼠标悬浮时显示信息组件 -->
    <TrackHoverView></TrackHoverView>
    <!-- 消息列表循环滚动展示组件 -->
    <realTimeInfo></realTimeInfo>
    <!-- 显示全部港口组件 -->
    <ViewAllPort></ViewAllPort>
  </div>
</template>

<script lang="ts">
// 地图工具函数集合
import ShipFun from '@/util/map/map.js'
// Vue装饰器
import {Component, Vue} from 'vue-property-decorator'
// 状态管理工具
import storeUtil from '@/util/store'
// 组件导入
import OnClickWeather from "@/components/on-map-view/OnClickWeather.vue"; // 气象点击显示组件
import PortHoverView from "@/components/on-map-view/PortHoverView.vue"; // 港口悬浮显示组件
import ShipHoverView from "@/components/on-map-view/ShipHoverView.vue"; // 船舶悬浮显示组件
import MapBottomShipType from "@/components/on-map-view/MapBottomShipType.vue"; // 船舶类型备注组件
import MapBottomMousePos from "@/components/on-map-view/MapBottomMousePos.vue"; // 鼠标位置显示组件
import MiniBox from "@/components/on-map-view/MiniBox.vue"; // 弹窗最小化组件
import TrackHoverView from "@/components/on-map-view/TrackHoverView.vue"; // 轨迹悬浮显示组件
import realTimeInfo from "@/components/real-time-info/realTimeInfo.vue"; // 实时消息组件
import ViewAllPort from "@/components/on-map-view/ViewAllPort.vue"; // 显示全部港口组件
// API调用
import HttpApi from "@/api"; // HTTP请求API
// 弹窗工具
import DialogUtil from "@/util/new-dialog"; // 弹窗管理工具
// 弹窗模板
import PortQueryTemp from '../new-dialog/PortQueryTemp.vue'; // 港口查询弹窗模板
import ShipInfoTemp from '../new-dialog/ShipInfoTemp.vue'; // 船舶信息弹窗模板
import CarInfoTemp from '../new-dialog/CarInfoTemp.vue'; // 车辆信息弹窗模板
// 类型定义
import {DialogType,DialogType as DialogType2} from '@/util/temp-interface'; // 弹窗类型枚举'
// 工具类
import {SearchLogUtil,ShipUtils} from "@/util/tool"; // 搜索日志工具
import bus from '@/util/bus'; // 事件总线
// OpenLayers样式
import {Style} from 'ol/style.js' // 样式基础类
import Icon from 'ol/style/Icon' // 图标样式
import styleText from 'ol/style/Text' // 文字标注样式
import styleFill from 'ol/style/Fill' // 填充样式
import styleStroke from 'ol/style/Stroke' // 描边样式
// 常量定义
const warningImg = require('../../util/map/img/shipWarningIcon.png') // 警告图标
const config = require('../../../public/config/sys-config.json') // 系统配置
const elementResizeDetectorMaker = require("element-resize-detector") // 元素大小变化检测工具

// 组件装饰器，注册子组件
@Component({
  components: {
    OnClickWeather,
    PortHoverView,
    ShipHoverView,
    MapBottomShipType,
    MapBottomMousePos,
    MiniBox,
    TrackHoverView,
    realTimeInfo,
    ViewAllPort
  }
})
export default class Main extends Vue {
  private map: any // 地图实例对象

  private shipData = [] // 船舶数据数组
  private carData = [] // 车辆数据数组
  /**
   * 获取船舶数据并处理
   * 1. 从API获取船舶分组数据
   * 2. 提取船舶ID并获取详细信息
   * 3. 处理船舶数据并添加到地图
   */
  private async getShips() {
    const ships: any = []
    // 获取船舶分组数据
    await HttpApi.getShipRanks({}).then((res: any) => {
      res.forEach((item: any) => {
        // 筛选有效的船舶分组
        if (item.idw !== -1 && item.followShipList && item.followShipList.length) {
          // 处理每个船舶的分组信息
          item.followShipList.forEach(async (item2: any) => {
            item2.groupName = item.name;
            item2.color = item.color;
            ships.push(item2)
          })
        }
      })
    })

    // 提取船舶ID数组
    const shipIds: any[] = []
    for (let i = 0; i < ships.length; i++) {
      shipIds.push(ships[i].shipId)
    }
    // 处理船舶详细信息，根据ID数量选择不同的请求方式
    if (shipIds.length <= 100) {
      // 单次请求获取船舶详细信息
      await HttpApi.getShipMessage({shipId: shipIds.toString()}).then((res: any[]) => {
        // 合并船舶详细信息到现有数据
        for (let i = 0; i < ships.length; i++) {
          res.forEach((item: any) => {
            if (ships[i].shipId === item.shipId) {
              Object.keys(item).forEach((key) => {
                ships[i][key] = item[key]
              })
            }
          })
        }
      })
    } else {
      // 批量请求获取船舶详细信息（每100个ID一组）
      const p: any[] = []
      const idGroup = this.spArray(shipIds, 100);
      for (let i = 0; i < idGroup.length; i++) {
        const ids = idGroup[i];
        // 创建批量请求Promise
        p.push(new Promise((resolve) => {
          HttpApi.getShipMessage({shipId: ids.toString()}).then((res) => {
            resolve(res)
          })
        }))
      }

      const newGetShips: any[] = []
      // 等待所有请求完成
      await Promise.all(p).then((res) => {
        // 合并所有返回的船舶数据
        for (let i = 0; i < res.length; i++) {
          const shipG: any[] = res[i];
          for (let j = 0; j < shipG.length; j++) {
            newGetShips.push(shipG[j])
          }
        }
      })

      // 合并详细信息到现有船舶数据
      for (let i = 0; i < ships.length; i++) {
        newGetShips.forEach((item: any) => {
          if (ships[i].shipId === item.shipId) {
            Object.keys(item).forEach((key) => {
              ships[i][key] = item[key]
            })
          }
        })
      }
    }
    // 更新船舶数据
    this.shipData = ships
    // 解析船舶数据并添加到地图
    this.jiexiRanks(ships);
    // 存储船舶数据到状态管理
    storeUtil.setShipFleet(ships);
    // 设置船舶警告（注释掉）
    // this.setShipWarning(ships);
  }
  /**
   * 获取车辆数据并添加到地图
   * 1. 从API获取车辆数据
   * 2. 处理车辆数据格式
   * 3. 将有效的车辆数据添加到地图
   * 4. 设置车辆警告
   */
  private getCars() {
    const carData: any = []
    // 获取车辆数据
    HttpApi.getCarInfo().then((res) => {
      // 处理车辆数据，转换为统一格式
      for (let i = 0; i < Object.keys(res).length; i++) {
        const key = Object.keys(res)[i];
        carData.push({
          carNum: res[key].carNum, // 车牌号
          companyName: res[key].companyName, // 公司名称
          customsCreateDate: res[key].customsCreateDate, // 海关创建日期
          gpsTime: res[key].data && res[key].data.GpsTime ? res[key].data.GpsTime : '', // GPS时间
          latitude: res[key].data && res[key].data.Latitude ? res[key].data.Latitude : '', // 纬度
          longitude: res[key].data && res[key].data.Longitude ? res[key].data.Longitude : '', // 经度
          entryId: res[key].entryId, // 入境ID
          firstRegistrationDate: res[key].firstRegistrationDate, // 首次注册日期
          vehicleModel: res[key].vehicleModel // 车辆型号
        })
      }
      // 更新车辆数据
      this.carData = carData
      console.log(carData,'carData')
      // 将有效的车辆数据（有经纬度）添加到地图
      ShipFun.addCar(carData.filter((item: any) => {
        return item.latitude && item.longitude
      }), this.map)
      // 设置车辆警告
      this.setCarWarning(carData.filter((item: any) => {
        return item.latitude && item.longitude
      }))
    })
  }
  /**
   * 将数组按指定长度分组
   * @param {Array} array - 要分组的数组
   * @param {number} len - 每组的长度
   * @returns {Array} 分组后的二维数组
   */
  private spArray(array: any[], len: number) {
    const newArray: any[] = [];
    // 递归分组函数
    function item(array: any[], len: number) {
      if (array.length && array.length > len) {
        // 截取指定长度的数组并添加到结果
        newArray.push(array.splice(0, len))
        // 递归处理剩余数组
        item(array, len);
      } else if (array.length && array.length < len) {
        // 将剩余数组作为一组添加到结果
        newArray.push(array)
        array = []
      }
    }
    // 调用分组函数
    item(array, len)
    return newArray
  }

  /**
   * 解析船舶数据并添加到地图
   * @param {Array} data - 船舶数据数组
   * 将船舶数据转换为地图工具需要的格式，并添加到地图
   */
  private jiexiRanks(data: any) {
    const newShipList: any = []
    // 遍历船舶数据，转换为地图工具需要的格式
    data.forEach((item: any) => {
      newShipList.push({
        y: item.shiptype, // 船舶类型
        m: item.mmsi, // MMSI号
        h: item.heading, // 航向
        g: item.callsign, // 呼号
        c: item.cog, // 对地航向
        o: item.imo, // IMO号
        s: item.sog, // 对地航速
        v: item.aisNavStatus, // AIS导航状态
        l: item.length, // 长度
        p: item.destPort, // 目的港
        b: item.breadth, // 宽度
        r: item.eta, // 预计到达时间
        d: item.draught, // 吃水
        t: item.posTime, // 位置时间
        i: item.shipId, // 船舶ID
        n: item.lon, // 经度
        a: item.lat, // 纬度
        e: item.shipnameEn, // 英文船名
        color: item.color, // 颜色
        isFleet: true // 是否为船队
      })
    })
    // 深拷贝数组并添加船舶到地图
    ShipFun.addShip(JSON.parse(JSON.stringify(newShipList)), 11, storeUtil.getMapInstance())
  }

  /**
   * 设置船舶警告
   * 将更新时间超出30天的船舶图标设置为感叹号
   * @param {Array} ships - 船舶数据数组
   */
  private setShipWarning(ships: any[]) {
    const nowTime: number = (new Date()).getTime() // 当前时间戳
    const temp: string[] = [] // 超过30天未更新的船舶ID数组
    // 遍历船舶数据，筛选超过30天未更新的船舶
    ships.forEach((item: any) => {
      // 计算船舶数据更新时间与当前时间的差值（天数）
      let timeDiff: number = item.posTime ? (nowTime - (item.posTime * 1000)) / (24 * 60 * 60 * 1000) : 0
      if (timeDiff > 30) {
        temp.push(item.shipId) // 添加到警告列表
      }
    })
    // 获取需要警告的船舶要素
    const features = ShipFun.getShipFeaturesByIds(temp)
    // 创建警告图标样式
    const iconStyle = new Style({
      image: new Icon({
        color: '#ffffff',
        crossOrigin: 'anonymous',
        src: warningImg,
        scale: 0.18
      })
    })
    // 为超过30天未更新的船舶设置警告图标
    features.forEach((f: any) => {
      f.setStyle(iconStyle)
    })
  }
  /**
   * 设置车辆警告
   * 将更新时间超出3天的车辆图标设置为感叹号
   * @param {Array} dataList - 车辆数据数组
   */
  private setCarWarning(dataList: any[]) {
    const nowTime: number = (new Date()).getTime() // 当前时间戳
    const temp: string[] = [] // 超过3天未更新的车辆ID数组
    // 遍历车辆数据，筛选超过3天未更新的车辆
    dataList.forEach((item: any) => {
      // 计算车辆数据更新时间与当前时间的差值（天数）
      let timeDiff: number = item.gpsTime ? (nowTime - new Date(item.gpsTime).getTime()) / (24 * 60 * 60 * 1000) : 0
      if (timeDiff > 3) {
        temp.push(item.carNum) // 添加到警告列表
      }
    })
    // 获取需要警告的车辆要素
    const features = ShipFun.getCarFeaturesByIds(temp)
    // 为每个警告车辆设置警告样式
    features.forEach((f: any) => {
      const iconStyle = new Style({
        image: new Icon({
          color: '#ffffff',
          crossOrigin: 'anonymous',
          src: warningImg,
          scale: 0.25
        }),
        text: new styleText({
          font: '16px Microsoft YaHei 100',
          textAlign: 'center',
          overflow: true,
          fill: new styleFill({
            color: '#000'
          }),
          stroke: new styleStroke({
            color: '#fff',
            width: 3
          }),
          textBaseline: 'bottom',
          text: f.get('carNum')
        })
      })
      f.setStyle(iconStyle)
    })
  }
  /**
   * 重新显示所有数据
   * 从已有的数据中重新添加船舶和车辆到地图，并设置警告
   */
  private showAllData() {
    // 重新解析船舶数据并添加到地图
    this.jiexiRanks(this.shipData);
    // 重新设置船舶警告（注释掉）
    // this.setShipWarning(this.shipData);
    // 重新添加车辆数据到地图
    ShipFun.addCar(this.carData.filter((item: any) => {
      return item.latitude && item.longitude
    }), this.map)
    // 重新设置车辆警告
    this.setCarWarning(this.carData.filter((item: any) => {
      return item.latitude && item.longitude
    }))
  }
  /**
   * 组件挂载完成后的初始化
   * 1. 初始化地图
   * 2. 配置地图参数
   * 3. 添加地图控件
   * 4. 添加地图事件监听
   * 5. 获取初始数据
   */
  public mounted() {
    // 创建地图实例
    this.map = ShipFun.creatMap()
    // 更新地图大小
    this.map.updateSize()
    // 存储地图实例到状态管理
    storeUtil.setMapInstance(this.map)
    // 存储地图工具函数到状态管理
    storeUtil.setMapFun(ShipFun);
    // 设置地图实例到工具函数
    ShipFun.setmap(this.map)
    // 设置地图中心点
    ShipFun.setCenter([110, 19]);
    // 设置地图缩放级别
    ShipFun.setZoom(9)
    // 切换地图类型为天地图
    ShipFun.changeMap(this.map, 'tdt')
    // 创建测距显示工具
    ShipFun.createMeasureTooltip(this.map) // 测距显示
    // 添加全屏按钮（注释掉）
    // ShipFun.addFullScreen(this.map) // 全屏按钮显示
    // 添加比例尺
    ShipFun.addScaleLine(this.map) // 添加比例尺
    // 添加鼠标位置显示
    ShipFun.addMousePos(this.map) // 添加显示鼠标位置的经纬度信息
    // 添加地图缩放监听器
    ShipFun.addZoomListener(this.map, () => {
      this.map
        .getControls()
        .getArray()
        .forEach((item: any) => {
          if (
            item.values_ &&
            JSON.stringify(item.values_) !== '{}' &&
            Object.keys(item.values_).includes('units') &&
            item.values_.units === 'nautical'
          ) {
            ShipFun.plotting(parseInt(item.renderedHTML_))
          }
        })
    })
    // 添加地图点击事件监听
    ShipFun.addClick(async (res: any) => {
      // 处理港口点击
      if (res.isType === 'port') {
        let port: any = {}
        // 获取港口详细信息
        await HttpApi.getPortInfo(res.portId).then((res2: any) => {
          port = res2
          Object.assign(port, res)
        })
        // 计算港口坐标
        port.cLon = port.portLon * 600000
        port.cLat = port.portLat * 600000
        // 显示港口查询弹窗
        DialogUtil.showDialog(PortQueryTemp, DialogType.PORT_QUERY, {
          dialogData: {
            title: `${port.nameCn}-${port.nameEn}`,
            vueName: DialogType.PORT_QUERY
          },
          infoData: {
            portInfo: port
          },
          show: true
        })
      } else if (res.isType === 'ship') {
        let shipData: any = {}
        let docData = {}
        // 获取船舶详细信息
        await HttpApi.getShipMessage({shipId: res.shipId}).then((res: any) => {
          const SearchLog = (this as any).$SearchLog
          let flag = true
          // 检查是否已存在于搜索日志
          if (SearchLog.length) {
            for (let i = 0; i < SearchLog.length; i++) {
              const item = SearchLog[i]
              if (item.shipId === res[0].shipId) {
                flag = false
                break
              }
            }
          }
          // 添加到搜索日志
          if (flag) {
            SearchLogUtil.addSearchLog(res[0])
          }
          // 存储船舶数据到状态管理
          storeUtil.setShipData(res[0])
          shipData = res[0]
        })
        // 获取船舶文档信息
        await HttpApi.getShipDoc({shipId: res.shipId}).then((res: any) => {
          if (res) {
            docData = res
          }
        })
        // 获取船舶中文名称
        await HttpApi.getShipCnName({mmsi: shipData.mmsi}).then((res: any) => {
          if (res) {
            shipData.shipnameCn = res.nameCn
          }
        })
        // 显示船舶信息弹窗
        DialogUtil.showDialog(ShipInfoTemp, DialogType.SHIP_INFO, {
          dialogData: {
            title: shipData.shipnameCn,
            vueName: DialogType.SHIP_INFO
          },
          infoData: {
            shipData: shipData,
            docData: docData
          },
          show: true
        })
      } else if (res.isType === 'car') {
        DialogUtil.showDialog(CarInfoTemp, DialogType.CAR_INFO, {
          dialogData: {
            title: res.carNum,
            vueName: DialogType.CAR_INFO
          },
          infoData: {
            carData: res
          },
          show: true
        })
      }
    })
    // 监听地图容器大小变化，更新地图大小
    elementResizeDetectorMaker().listenTo(document.getElementById('map'), () => {
      this.map.updateSize()
    })
    // 获取初始船舶数据
    this.getShips()
    // 获取初始车辆数据
    this.getCars()
    // 监听全局事件，重新显示所有数据
    bus.$on('showAllData', () => {
      this.showAllData()
    })
    // 初始化筛选和搜索事件监听
    this.initFilterEvent()
  }

  /**
   * 初始化筛选和搜索事件
   */
  private initFilterEvent() {
    // 类型筛选事件
    bus.$on('filterTypeChange', (data: any) => {
      this.handleFilterTypeChange(data)
    })
    // 搜索事件
    bus.$on('filterSearch', (data: any) => {
      this.handleFilterSearch(data)
    })
  }

  /**
   * 处理类型筛选变化
   * @param {Object} data - 筛选数据
   * @param {string} data.type - 类型：ship, car, yacht
   * @param {boolean} data.isChecked - 是否勾选
   */
  private handleFilterTypeChange(data: any) {
    const { type, isChecked } = data
    switch (type) {
      case 'ship':
        if (isChecked) {
          // 显示船舶
          const filteredShips = this.shipData.filter((ship: any) => {
            return ship.shipTypeName !== '其他'
          })
          this.jiexiRanks(filteredShips)
        } else {
          // 只隐藏船舶，保留游艇
          const shipIds = this.shipData
            .filter((ship: any) => ship.shipTypeName !== '其他')
            .map((ship: any) => ship.shipId)
          console.log(shipIds,'shipIds')
          ShipFun.hideShips(shipIds)
          DialogUtil.closeCom(DialogType.SHIP_INFO)
          DialogUtil.closeCom(DialogType2.TRACK_RECORD)
        }
        break
      case 'car':
        if (isChecked) {
          // 显示车辆
          ShipFun.addCar(this.carData.filter((item: any) => {
            return item.latitude && item.longitude
          }), this.map)
        } else {
          // 隐藏车辆
          ShipFun.clearAllCar(this.map)
          DialogUtil.closeCom(DialogType.CAR_INFO)
          DialogUtil.closeCom(DialogType2.TRACK_RECORD)
          ShipFun.delPath()
        }
        break
      case 'yacht':
        if (isChecked) {
          // 显示游艇
          const yachts = this.shipData.filter((ship: any) => {
            return ship.shipTypeName === '其他'
          })
          this.jiexiRanks(yachts)
        } else {
          // 只隐藏游艇，保留船舶
          const yachtIds = this.shipData
            .filter((ship: any) => ship.shipTypeName === '其他')
            .map((ship: any) => ship.shipId)
          console.log(yachtIds,'yachtIds')
          ShipFun.hideShips(yachtIds)
          DialogUtil.closeCom(DialogType.SHIP_INFO)
          DialogUtil.closeCom(DialogType2.TRACK_RECORD)
        }
        break
    }
  }

  /**
   * 处理搜索
   * @param {Object} data - 搜索数据
   * @param {string} data.type - 类型：ship, car, yacht
   * @param {string} data.value - 搜索值
   */
  private handleFilterSearch(data: any) {
    const { type, value } = data
    if (!value) {
      // 搜索值为空，显示所有数据
      this.handleFilterTypeChange({ type, isChecked: true })
      return
    }

    switch (type) {
      case 'ship': {
        // 船舶搜索
        const allShips = this.shipData.filter((ship: any) => {
          const isShip = ship.shipTypeName !== '其他'
          return isShip
        })
        console.log(allShips,'所有的船舶数据')
        console.log(value,'搜索值')
        // 再根据mmsi包含value筛选
        const filteredaShips = allShips.filter((ship: any) => {
          const mmsi = ship.mmsi || ''
          const isMatch = mmsi.includes(value)
          return isMatch
        })
        // 清空现有船舶数据
        console.log(filteredaShips,'筛选后的船舶数据')
        ShipFun.clearallship(this.map)
        if (filteredaShips.length > 0) {
          this.jiexiRanks(filteredaShips)
        } else {
          console.log('没有匹配到船舶数据')
        }
        break
      }
      case 'car': {
        // 车辆搜索
        const filteredCars = this.carData.filter((car: any) => {
          const carNum = car.carNum || ''
          return carNum.includes(value)
        })
        ShipFun.clearAllCar(this.map)
        ShipFun.addCar(filteredCars.filter((item: any) => {
          return item.latitude && item.longitude
        }), this.map)
        break
      }
      case 'yacht': {
        // 游艇搜索 - 先过滤游艇数据，再根据mmsi包含value筛选
        // 先过滤出游艇数据
        const allYachts = this.shipData.filter((ship: any) => {
          const isYacht = ship.shipTypeName === '其他'
          return isYacht
        })
        // 再根据mmsi包含value筛选
        const filteredYachts = allYachts.filter((ship: any) => {
          const mmsi = ship.mmsi || ''
          const isMatch = mmsi.includes(value)
          return isMatch
        })
        // 清空现有船舶数据
        ShipFun.clearallship(this.map)

        if (filteredYachts.length > 0) {
          // 直接调用jiexiRanks方法处理数据并添加到地图
          this.jiexiRanks(filteredYachts)
        } else {
          console.log('没有匹配到游艇数据')
        }
        break
      }
    }
  }
}
</script>
<style scoped lang="scss">
.my-ships-main {
  width: 100%;
  height: 100%;
  position: relative;
  font-size: 0.875rem;

  ::v-deep .ol-zoom {
    position: absolute;
    background: none;
    left: 1.25rem !important;
    bottom: 6.25rem !important;
    top: auto !important;
  }

  ::v-deep .ol-full-screen {
    position: absolute;
    left: 1.25rem !important;
    margin: 0 !important;
    background: none !important;
    top: auto !important;
    right: auto !important;
    bottom: 9.375rem !important;
  }

  ::v-deep .ol-scale-line {
    position: absolute !important;
    left: 9.375rem !important;
    width: 7.5rem !important;
    height: 3.125rem !important;
    box-sizing: border-box !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;

    .ol-scale-line-inner {
      width: 6.875rem !important;
      height: 2.5rem !important;
      font-size: 0.875rem !important;
      display: flex !important;
      align-items: center !important;
      justify-content: center !important;
    }
  }
}
</style>
