<template>
  <div class="g-map-wrapper">
    <!-- 地图区域 -->
    <div id="g-container" :style="{ width: '100%', height: '100%' }"></div>
    <!-- 绘制面板 -->
    <div class="g-action-panel">
      <div :class="state.currentType === 'pin' ? 'g-action-item selection' : 'g-action-item'"
        @click="draw('pin', true)">
        <a><a-image :src="pin" :preview="false" /></a>
      </div>
      <div :class="state.currentType === 'polyline' ? 'g-action-item selection' : 'g-action-item'"
        @click="draw('polyline', true)">
        <a>
          <LineOutlined :rotate="135" class="fz20" />
        </a>
      </div>
      <div :class="state.currentType === 'polygon' && !state.isFlightArea ? 'g-action-item selection' : 'g-action-item'"
        @click="draw('polygon', true)">
        <a>
          <BorderOutlined class="fz18" />
        </a>
      </div>
      <div v-if="mouseMode" class="g-action-item" @click="draw('off', false)">
        <a style="color: red;">
          <CloseOutlined />
        </a>
      </div>
    </div>
    <!-- 地图类型切换控件 -->
    <div class="g-mapType">
      <img :src="planeSrc" v-if="state.mapType === 0" @click="onClickSwitchMapType" />
      <img :src="satelliteSrc" v-else @click="onClickSwitchMapType" />
    </div>
    <!-- 最下方信息区域 -->
    <div class="g-info">
      <AimOutlined style="margin-right: 10px;" />
      <div>
        WGS 84
      </div>
    </div>
    <!-- 机场OSD -->
    <AirportOsdInfoModal :osdInfo="osdVisible" :deviceInfo="deviceInfo"
      v-if="osdVisible.visible && osdVisible.is_dock" />
    <!-- 飞机OSD -->
    <DeviceOsdInfoModal :osdInfo="osdVisible" :deviceInfo="deviceInfo"
      v-if="osdVisible.visible && !osdVisible.is_dock" />
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, onMounted, reactive, ref, watch, onUnmounted } from 'vue'
import { BorderOutlined, LineOutlined, CloseOutlined, AimOutlined } from '@ant-design/icons-vue'
import {
  generateLineContent,
  generatePointContent,
  generatePolyContent
} from '../utils/map-layer-utils'
import { postElementsReq } from '/@/api/layer'
import { MapDoodleType, MapElementEnum } from '/@/constants/map'
import AirportOsdInfoModal from '/@/components/airport/components/InfoModal.vue'
import DeviceOsdInfoModal from '/@/components/onLineDevice/components/InfoModal.vue'
import { useGMapManage } from '/@/hooks/use-g-map'
import { useGMapCover } from '/@/hooks/use-g-map-cover'
import { useMouseTool } from '/@/hooks/use-mouse-tool'
import { useGMapTrajectory } from '/@/hooks/use-g-map-trajectory'
import { getApp, getRoot } from '/@/root'
import { useMyStore } from '/@/store'
import { GeojsonCoordinate } from '/@/types/map'
import { MapDoodleEnum } from '/@/types/map-enum'
import { PostElementsBody } from '/@/types/mapLayer'
import { uuidv4 } from '/@/utils/uuid'
import { gcj02towgs84, wgs84togcj02 } from '../vendors/coordtransform'
import { deviceTsaUpdate } from '/@/hooks/use-g-map-tsa'
import pin from '/@/assets/icons/pin-2d8cf0.svg'
import planeSrc from '/@/assets/icons/plane.png'
import satelliteSrc from '/@/assets/icons/satellite.png'
import { EDeviceTypeName, ELocalStorageKey } from '../types'
import { EFlightAreaType } from '../types/flight-area'
import { useFlightArea } from './flight-area/use-flight-area'
import { useConnectMqtt } from './g-map/use-connect-mqtt'
import { useFlightAreaDroneLocationEvent } from './flight-area/use-flight-area-drone-location-event'
import { DeviceOsd, DeviceStatus, DockOsd, EModeCode, GatewayOsd } from '/@/types/device'

export default defineComponent({
  components: {
    BorderOutlined,
    LineOutlined,
    CloseOutlined,
    AimOutlined,
    AirportOsdInfoModal,
    DeviceOsdInfoModal,
  },
  name: 'GMap',
  props: {},
  setup() {
    const useMouseToolHook = useMouseTool()
    const useGMapManageHook = useGMapManage()
    const deviceTsaUpdateHook = deviceTsaUpdate()

    const root = getRoot()

    const mouseMode = ref(false)
    const store = useMyStore()
    const state = reactive({
      mapType: 0,// 地图类型 0-普通 1-卫星
      currentType: '',
      coverIndex: 0,
      isFlightArea: false,
    })

    // 点击切换地图类型
    const onClickSwitchMapType = () => {
      const mapType = state.mapType === 0 ? 1 : 0;
      state.mapType = mapType;
      useMouseToolHook.onChangeMapType(mapType);
    }

    const str: string = '--';

    const deviceInfo: any = reactive({
      gateway: {
        capacity_percent: str,
        transmission_signal_quality: str,
      } as GatewayOsd,
      dock: {} as DockOsd,
      device: {
        gear: -1,
        mode_code: EModeCode.Disconnected,
        height: str,
        home_distance: str,
        horizontal_speed: str,
        vertical_speed: str,
        wind_speed: str,
        wind_direction: str,
        elevation: str,
        position_state: {
          gps_number: str,
          is_fixed: 0,
          rtk_number: str
        },
        battery: {
          capacity_percent: str,
          landing_power: str,
          remain_flight_time: 0,
          return_home_power: str,
        },
        latitude: 0,
        longitude: 0,
      } as DeviceOsd
    })

    const shareId = computed(() => {
      return store.state.layerBaseInfo.share
    })

    const osdVisible = computed(() => {
      return store.state.osdVisible
    })

    watch(() => store.state.trajectoryList, (list: any) => {
      setTimeout(() => {
        if (list.length >= 2) {// 至少要有起点终点两个坐标才可以绘制轨迹
          const trajectoryHook = useGMapTrajectory()
          trajectoryHook.drawTrajectory(list);
        }
      }, 1000)
    }, { deep: true })

    watch(() => store.state.realTimeTrajectory, newData => {// 实时轨迹绘制
      const trajectoryHook = useGMapTrajectory()
      const deviceInfo = store.state.deviceState.deviceInfo[newData.sn]
      trajectoryHook.drawDynamicTrajectory(newData.sn, deviceInfo, newData.host)
    }, { deep: true })

    watch(() => store.state.deviceStatusEvent, (data: any) => {
      if (Object.keys(data.deviceOnline).length !== 0) {
        deviceTsaUpdateHook.initMarker(data.deviceOnline.domain, data.deviceOnline.device_callsign, data.deviceOnline.sn)
        store.state.deviceStatusEvent.deviceOnline = {} as DeviceStatus
      }
      if (Object.keys(data.deviceOffline).length !== 0) {
        deviceTsaUpdateHook.removeMarker(data.deviceOffline.sn)
        if ((data.deviceOffline.sn === osdVisible.value.sn) || (osdVisible.value.is_dock && data.deviceOffline.sn === osdVisible.value.gateway_sn)) {
          osdVisible.value.visible = false
          store.commit('SET_OSD_VISIBLE_INFO', osdVisible)
        }
        store.state.deviceStatusEvent.deviceOffline = {}
      }
    }, { deep: true })

    watch(() => store.state.deviceState, data => {
      if (data.currentType === EDeviceTypeName.Gateway && data.gatewayInfo[data.currentSn]) {
        const coordinate = wgs84togcj02(data.gatewayInfo[data.currentSn].longitude, data.gatewayInfo[data.currentSn].latitude)
        deviceTsaUpdateHook.moveTo(data.currentSn, coordinate[0], coordinate[1])
        if (osdVisible.value.visible && osdVisible.value.gateway_sn !== '') {
          deviceInfo.gateway = data.gatewayInfo[osdVisible.value.gateway_sn]
        }
      }
      if (data.currentType === EDeviceTypeName.Aircraft && data.deviceInfo[data.currentSn]) {
        const coordinate = wgs84togcj02(data.deviceInfo[data.currentSn].longitude, data.deviceInfo[data.currentSn].latitude)
        deviceTsaUpdateHook.moveTo(data.currentSn, coordinate[0], coordinate[1])
        if (osdVisible.value.visible && osdVisible.value.sn !== '') {
          deviceInfo.device = data.deviceInfo[osdVisible.value.sn]
        }
      }
      if (data.currentType === EDeviceTypeName.Dock && data.dockInfo[data.currentSn]) {
        const coordinate = wgs84togcj02(data.dockInfo[data.currentSn].basic_osd?.longitude, data.dockInfo[data.currentSn].basic_osd?.latitude)
        deviceTsaUpdateHook.initMarker(EDeviceTypeName.Dock, EDeviceTypeName[EDeviceTypeName.Dock], data.currentSn, coordinate[0], coordinate[1])
        if (osdVisible.value.visible && osdVisible.value.is_dock && osdVisible.value.gateway_sn !== '') {
          deviceInfo.dock = data.dockInfo[osdVisible.value.gateway_sn]
          deviceInfo.device = data.deviceInfo[deviceInfo.dock.basic_osd.sub_device?.device_sn ?? osdVisible.value.sn]
        }
      }
    }, {
      deep: true
    })

    watch(() => store.state.wsEvent, newData => {
      const useGMapCoverHook = useGMapCover()
      const event = newData
      let exist = false
      if (Object.keys(event.mapElementCreat).length !== 0) {
        const ele: any = event.mapElementCreat
        store.state.Layers.forEach((layer: any) => {
          layer.elements.forEach((e: any) => {
            if (e.id === ele.id) {
              exist = true
            }
          })
        })
        if (exist === false) {
          setLayers({
            id: ele.id,
            name: ele.name,
            resource: ele.resource
          })
          updateCoordinates('wgs84-gcj02', ele)
          const data = { id: ele.id, name: ele.name }
          if (MapElementEnum.PIN === ele.resource?.type) {
            useGMapCoverHook.init2DPin(
              ele.name,
              ele.resource.content.geometry.coordinates,
              ele.resource.content.properties.color,
              data
            )
          } else if (MapElementEnum.LINE === ele.resource?.type) {
            useGMapCoverHook.initPolyline(
              ele.name,
              ele.resource.content.geometry.coordinates,
              ele.resource.content.properties.color,
              data
            )
          } else if (MapElementEnum.POLY === ele.resource?.type) {
            useGMapCoverHook.initPolygon(
              ele.name,
              ele.resource.content.geometry.coordinates,
              ele.resource.content.properties.color,
              data
            )
          }
        }
        store.state.wsEvent.mapElementCreat = {}
      }
      if (Object.keys(event.mapElementUpdate).length !== 0) {
        console.log('该功能还未实现，请开发商自己增加')
        store.state.wsEvent.mapElementUpdate = {}
      }
      if (Object.keys(event.mapElementDelete).length !== 0) {
        console.log('该功能还未实现，请开发商自己增加')
        store.state.wsEvent.mapElementDelete = {}
      }
    }, { deep: true })

    function draw(type: MapDoodleType, bool: boolean, flightAreaType?: EFlightAreaType) {
      state.currentType = type
      mouseMode.value = bool
      state.isFlightArea = !!flightAreaType
      useMouseToolHook.mouseTool(type, getDrawCallback, flightAreaType)
    }

    // 连接或断开drc
    useConnectMqtt()

    onMounted(() => {
      const app = getApp()
      useGMapManageHook.globalPropertiesConfig(app)
    })

    onUnmounted(() => {
      const gatewayInfo = store.state.deviceState.gatewayInfo;
      for (const key in gatewayInfo) {
        deviceTsaUpdateHook.removeDeviceMarker(key)
      }
      root.$map.destroy()
    })

    const { getDrawFlightAreaCallback, onFlightAreaDroneLocationWs } = useFlightArea()

    useFlightAreaDroneLocationEvent(onFlightAreaDroneLocationWs)

    function getDrawCallback({ obj }: { obj: any }) {
      if (state.isFlightArea) {
        getDrawFlightAreaCallback(obj)
        return
      }
      switch (state.currentType) {
        case MapDoodleEnum.PIN:
          postPinPositionResource(obj)
          break
        case MapDoodleEnum.POLYLINE:
          postPolylineResource(obj)
          break
        case MapDoodleEnum.POLYGON:
          postPolygonResource(obj)
          break
        default:
          break
      }
      draw('off', false)
    }

    async function postPinPositionResource(obj: any) {
      const req: any = getPinPositionResource(obj)
      const userName = localStorage.getItem(ELocalStorageKey.Username) || ''
      req.element_from = 1
      req.resource.user_name = userName
      setLayers(req)
      const coordinates = req.resource.content.geometry.coordinates
      updateCoordinates('gcj02-wgs84', req);
      const data = {
        ...req,
      }
      data.resource.content.geometry.coordinates = [...data.resource.content.geometry.coordinates, 0];
      await postElementsReq(shareId.value, data)
      obj.setExtData({ id: req.id, name: req.name })
      const title = coordinates.map((item: any, index: number) => {
        if (index < 2) {
          return item.toFixed(4)
        }
      });
      obj.setTitle(title)
      store.state.coverMap[req.id] = [obj]
      const map = root.$map
      const AMap = root.$aMap
      const text = new AMap.Text({
        position: new AMap.LngLat(coordinates[0], coordinates[1]),
        offset: new AMap.Pixel(20, -2),
        text: req.name,
        style: {
          backgroundColor: 'transparent',
          borderColor: 'transparent',
        }
      })
      const other = [text]
      map.add(other);
      store.state.coverMap[req.id + '_other'] = other
      obj.on('click', function () {
        store.commit('SET_MAP_CLICK_ELEMENT', {
          id: req.id,
          type: 'DEFAULT',
        });
      });
    }

    async function postPolylineResource(obj: any) {
      const req: any = getPolylineResource(obj)
      const userName = localStorage.getItem(ELocalStorageKey.Username) || ''
      req.element_from = 1
      req.resource.user_name = userName
      setLayers(req)
      updateCoordinates('gcj02-wgs84', req)
      await postElementsReq(shareId.value, req)
      obj.setExtData({ id: req.id, name: req.name })
      store.state.coverMap[req.id] = [obj]
      const map = root.$map
      const AMap = root.$aMap
      const coordinatesList = req.resource.content.geometry.coordinates.map((item: any) => wgs84togcj02(item[0], item[1]))
      if (coordinatesList.length < 2) {
        return
      }
      const color = req.resource.content.properties.color
      const circles = coordinatesList.map((item: any) => {
        return new AMap.Circle({
          center: new AMap.LngLat(item[0], item[1]),
          radius: 0.5, // 半径
          strokeColor: color,
          fillColor: color,
          fillOpacity: 1,
          strokeWeight: 6,
        });
      })
      const coordinates = coordinatesList[0];
      const text = new AMap.Text({
        position: new AMap.LngLat(coordinates[0], coordinates[1]),
        offset: new AMap.Pixel(-30, -30),
        text: req.name,
        style: {
          backgroundColor: 'transparent',
          borderColor: 'transparent',
        }
      })
      const distances = [];
      const paths = [...coordinatesList]
      // 计算并显示每段线的距离
      for (let i = 0; i < paths.length - 1; i++) {
        const distance = AMap.GeometryUtil.distance(new AMap.LngLat(paths[i][0], paths[i][1]), new AMap.LngLat(paths[i + 1][0], paths[i + 1][1]));
        // 计算两个点之间的中点坐标
        const midLng = (paths[i][0] + paths[i + 1][0]) / 2;
        const midLat = (paths[i][1] + paths[i + 1][1]) / 2;
        const midPoint = new AMap.LngLat(midLng, midLat);
        // 在中点位置放置文本以显示距离
        const distanceText = new AMap.Text({
          position: midPoint,
          offset: new AMap.Pixel(-16, 10),
          text: `${distance.toFixed(1)} m`,// 距离
          style: {
            fontSize: '10px',
            color: '#FFFFFF',
            backgroundColor: 'rgba(0, 0, 0, 0.75)',
            borderColor: 'transparent',
          },
        });
        distances.push(distanceText);
      }
      const other = [...circles, text, ...distances]
      map.add(other);
      store.state.coverMap[req.id + '_other'] = other;
      obj.on('click', function () {
        store.commit('SET_MAP_CLICK_ELEMENT', {
          id: req.id,
          type: 'DEFAULT',
        });
      });
    }

    async function postPolygonResource(obj: any) {
      const req: any = getPoygonResource(obj)
      const userName = localStorage.getItem(ELocalStorageKey.Username) || ''
      req.element_from = 1
      req.resource.user_name = userName
      setLayers(req)
      updateCoordinates('gcj02-wgs84', req)
      await postElementsReq(shareId.value, req)
      obj.setExtData({ id: req.id, name: req.name })
      store.state.coverMap[req.id] = [obj]
      const map = root.$map
      const AMap = root.$aMap
      const coordinatesList = req.resource.content.geometry.coordinates[0].map((item: any) => wgs84togcj02(item[0], item[1]))
      if (coordinatesList.length < 3) {
        return
      }
      const color = req.resource.content.properties.color
      const circles = coordinatesList.map((item: any) => {
        return new AMap.Circle({
          center: new AMap.LngLat(item[0], item[1]),
          radius: 0.5, // 半径
          strokeColor: color,
          fillColor: color,
          fillOpacity: 1,
          strokeWeight: 6,
        });
      })
      const coordinates = coordinatesList[0];
      const text = new AMap.Text({
        position: new AMap.LngLat(coordinates[0], coordinates[1]),
        offset: new AMap.Pixel(0, -30),
        text: req.name,
        style: {
          backgroundColor: 'transparent',
          borderColor: 'transparent',
        }
      })
      const distances = [];
      // 确保首尾相连
      const paths = [...coordinatesList, coordinatesList[0]]
      // 计算并显示每段线的距离
      for (let i = 0; i < paths.length - 1; i++) {
        const distance = AMap.GeometryUtil.distance(new AMap.LngLat(paths[i][0], paths[i][1]), new AMap.LngLat(paths[i + 1][0], paths[i + 1][1]));
        // 计算两个点之间的中点坐标
        const midLng = (paths[i][0] + paths[i + 1][0]) / 2;
        const midLat = (paths[i][1] + paths[i + 1][1]) / 2;
        const midPoint = new AMap.LngLat(midLng, midLat);
        // 在中点位置放置文本以显示距离
        const distanceText = new AMap.Text({
          position: midPoint,
          offset: new AMap.Pixel(-16, 10),
          text: `${distance.toFixed(1)} m`,// 距离
          style: {
            fontSize: '10px',
            color: '#FFFFFF',
            backgroundColor: 'rgba(0, 0, 0, 0.75)',
            borderColor: 'transparent',
          },
        });
        distances.push(distanceText);
      }
      const other = [...circles, text, ...distances]
      map.add(other);
      store.state.coverMap[req.id + '_other'] = other;
      obj.on('click', function () {
        store.commit('SET_MAP_CLICK_ELEMENT', {
          id: req.id,
          type: 'DEFAULT',
        });
      });
    }

    function getPinPositionResource(obj: any) {
      const position = obj.getPosition()
      const resource = generatePointContent(position)
      const name = obj._originOpts.title
      const id = uuidv4()
      return {
        id,
        name,
        resource
      }
    }

    function getPolylineResource(obj: any) {
      const path = obj.getPath()
      const resource = generateLineContent(path)
      const { name, id } = getBaseInfo(obj._opts)
      return {
        id,
        name,
        resource
      }
    }

    function getPoygonResource(obj: any) {
      const path = obj.getPath()
      const resource = generatePolyContent(path)
      const { name, id } = getBaseInfo(obj._opts)
      return {
        id,
        name,
        resource
      }
    }

    function getBaseInfo(obj: any) {
      const name = obj.title
      const id = uuidv4()
      return { name, id }
    }

    function setLayers(resource: PostElementsBody) {
      const layers = store.state.Layers
      const layer: any = layers.find((item: any) => item.id.includes(shareId.value))
      if (layer?.elements) {
        (layer?.elements as any[]).push(resource)
      }
      store.commit('SET_LAYER_INFO', layers)
    }

    function updateCoordinates(transformType: string, element: any) {
      const type = element.resource?.type as number
      if (element.resource) {
        if (MapElementEnum.PIN === type) {
          const coordinates = element.resource?.content.geometry
            .coordinates as GeojsonCoordinate
          if (transformType === 'wgs84-gcj02') {
            const transResult = wgs84togcj02(
              coordinates[0],
              coordinates[1]
            ) as GeojsonCoordinate
            element.resource.content.geometry.coordinates = transResult
          } else if (transformType === 'gcj02-wgs84') {
            const transResult = gcj02towgs84(
              coordinates[0],
              coordinates[1]
            ) as GeojsonCoordinate
            element.resource.content.geometry.coordinates = transResult
          }
        } else if (MapElementEnum.LINE === type) {
          const coordinates = element.resource?.content.geometry
            .coordinates as GeojsonCoordinate[]
          if (transformType === 'wgs84-gcj02') {
            coordinates.forEach((coordinate, i, arr) => {
              arr[i] = wgs84togcj02(
                coordinate[0],
                coordinate[1]
              ) as GeojsonCoordinate
            })
          } else if (transformType === 'gcj02-wgs84') {
            coordinates.forEach((coordinate, i, arr) => {
              arr[i] = gcj02towgs84(
                coordinate[0],
                coordinate[1]
              ) as GeojsonCoordinate
            })
          }
          element.resource.content.geometry.coordinates = coordinates
        } else if (MapElementEnum.POLY === type) {
          const coordinates = element.resource?.content.geometry
            .coordinates[0] as GeojsonCoordinate[]
          if (transformType === 'wgs84-gcj02') {
            coordinates.forEach((coordinate, i, arr) => {
              arr[i] = wgs84togcj02(
                coordinate[0],
                coordinate[1]
              ) as GeojsonCoordinate
            })
          } else if (transformType === 'gcj02-wgs84') {
            coordinates.forEach((coordinate, i, arr) => {
              arr[i] = gcj02towgs84(
                coordinate[0],
                coordinate[1]
              ) as GeojsonCoordinate
            })
          }
          element.resource.content.geometry.coordinates = [coordinates]
        }
      }
    }

    return {
      draw,
      mouseMode,
      osdVisible,
      pin,
      state,
      planeSrc,
      satelliteSrc,
      deviceInfo,
      onClickSwitchMapType,
      EModeCode,
      str,
    }
  }
})
</script>

<style lang="scss" scoped>
.g-map-wrapper {
  height: 100%;
  width: 100%;

  .g-action-panel {
    position: absolute;
    top: 16px;
    right: 16px;

    .g-action-item {
      width: 28px;
      height: 28px;
      background: white;
      color: $primary;
      border-radius: 2px;
      line-height: 28px;
      text-align: center;
      margin-bottom: 2px;
    }

    .g-action-item:hover {
      border: 1px solid $primary;
      border-radius: 2px;
    }
  }

  .selection {
    border: 1px solid $primary;
    border-radius: 2px;
  }

  // antd button 光晕
  &:deep(.ant-btn) {
    &::after {
      display: none;
    }
  }
}

.g-mapType {
  width: 28px;
  height: 28px;
  background: white;
  border-radius: 2px;
  line-height: 28px;
  text-align: center;
  position: absolute;
  bottom: 50px;
  right: 16px;
  cursor: pointer;

  img {
    width: 18px;
    height: 18px;
  }
}

.g-info {
  width: 100%;
  height: 26px;
  padding: 0 16px;
  background: rgba(255, 255, 255, 0.7);
  border-radius: 2px;
  line-height: 28px;
  text-align: center;
  position: absolute;
  bottom: 0;
  right: 0;
  display: flex;
  justify-content: flex-end;
  align-items: center;
}
</style>

<style lang="scss">
.amap-logo {
  display: none !important;
}

.amap-copyright {
  display: none !important;
}
</style>