<template>
  <div class="map-container">
    <div id="baidu-map" ref="mapContainer"></div>
    <div class="map-controls">
      <button @click="zoomIn">放大</button>
      <button @click="zoomOut">缩小</button>
      <button @click="toggleMapType">切换地图类型({{ mapType === 'BMAP_NORMAL_MAP' ? '地图' : '卫星' }})</button>
    </div>
    <div v-if="selectedDevice" class="device-info-dialog" :style="{ left: dialogLeft + 'px', top: dialogTop + 'px' }">
      <div class="dialog-header">
        <h3>设备详情</h3>
        <button @click="closeDeviceInfo">×</button>
      </div>
      <div class="dialog-content">
        <p><strong>设备ID:</strong> {{ selectedDevice.id }}</p>
        <p><strong>设备名称:</strong> {{ selectedDevice.name }}</p>
        <p><strong>位置:</strong> {{ selectedDevice.location }}</p>
        <p><strong>状态:</strong> {{ deviceStatusMap[selectedDevice.status] }}</p>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, onBeforeUnmount, ref } from 'vue';

interface Device {
  id: string;
  name: string;
  location: string;
  status: number;
  lng: number;
  lat: number;
}

interface Cluster {
  lng: number;
  lat: number;
  count: number;
  devices?: Device[];
}

export default defineComponent({
  name: 'ChinaDeviceMap',
  setup() {
    const mapContainer = ref<HTMLElement | null>(null);
    const map = ref<any>(null);
    const mapType = ref<'BMAP_NORMAL_MAP' | 'BMAP_SATELLITE_MAP'>('BMAP_NORMAL_MAP');
    const selectedDevice = ref<Device | null>(null);
    const hoverDevice = ref<Device | null>(null);
    const clusters = ref<Cluster[]>([]);
    const dialogLeft = ref<number>(0);
    const dialogTop = ref<number>(0);

    // 设备数据示例
    const devices = ref<Device[]>([
      { id: 'D001', name: '设备1', location: '北京', status: 1, lng: 116.404, lat: 39.915 },
      { id: 'D002', name: '设备2', location: '上海', status: 2, lng: 121.474, lat: 31.230 },
      { id: 'D003', name: '设备3', location: '广州', status: 1, lng: 113.264, lat: 23.129 },
      { id: 'D004', name: '设备4', location: '深圳', status: 3, lng: 114.058, lat: 22.543 },
      { id: 'D005', name: '设备5', location: '成都', status: 1, lng: 104.065, lat: 30.659 },
      { id: 'D006', name: '设备6', location: '武汉', status: 2, lng: 114.305, lat: 30.593 },
      { id: 'D007', name: '设备7', location: '西安', status: 1, lng: 108.948, lat: 34.263 },
      { id: 'D008', name: '设备8', location: '杭州', status: 3, lng: 120.155, lat: 30.274 },
      { id: 'D009', name: '设备9', location: '南京', status: 1, lng: 118.797, lat: 32.060 },
      { id: 'D010', name: '设备10', location: '重庆', status: 2, lng: 106.505, lat: 29.533 },
    ]);

    const deviceStatusMap = {
      1: '在线',
      2: '离线',
      3: '异常'
    };

    // 初始化地图
    const initMap = () => {
      if (!mapContainer.value) return;

      const script = document.createElement('script');
      script.src = `https://api.map.baidu.com/api?v=3.0&ak=c0crhdxQ5H7WcqbcazGr7mnHrLa4GmO0&type=webgl`;
      script.async = true;
      script.onload = () => {
        if ((window as any).BMap) {
          map.value = new (window as any).BMap.Map(mapContainer.value);
          const point = new (window as any).BMap.Point(104.114129, 37.550339);
          map.value.centerAndZoom(point, 5);

          map.value.enableScrollWheelZoom(true);
          map.value.setMapType((window as any)[mapType.value]);

          map.value.addControl(new (window as any).BMap.NavigationControl());
          map.value.addControl(new (window as any).BMap.ScaleControl());

          initDeviceMarkers();
          map.value.addEventListener('zoomend', initDeviceMarkers);

          // 添加地图点击事件监听器
          map.value.addEventListener('click', closeDeviceInfoIfOutside);
        } else {
          console.error('百度地图API加载失败');
        }
      };
      script.onerror = () => {
        console.error('百度地图API加载失败');
      };
      document.head.appendChild(script);
    };

    const initDeviceMarkers = () => {
      if (!map.value) return;

      map.value.clearOverlays();

      const zoomLevel = map.value.getZoom();
      if (zoomLevel > 10) {
        // 高缩放级别下显示单个设备标记
        devices.value.forEach(device => {
          const point = new (window as any).BMap.Point(device.lng, device.lat);
          const marker = createDeviceMarker(device, point);
          map.value.addOverlay(marker);
        });
      } else {
        // 低缩放级别下进行聚合
        clusters.value = clusterDevices(devices.value, map.value);
        clusters.value.forEach(cluster => {
          if (cluster.count === 1) {
            // 只有一个设备时显示设备图标
            const device = cluster.devices?.[0];
            if (device) {
              const point = new (window as any).BMap.Point(device.lng, device.lat);
              const marker = createDeviceMarker(device, point);
              map.value.addOverlay(marker);
            }
          } else if (cluster.count > 1) {
            // 多个设备时显示聚合标签
            const point = new (window as any).BMap.Point(cluster.lng, cluster.lat);
            const label = createClusterLabel(cluster, point);
            map.value.addOverlay(label);
          }
        });
      }
    };

    const createDeviceMarker = (device: Device, point: any) => {
      const marker = new (window as any).BMap.Marker(point, {
        icon: new (window as any).BMap.Icon('https://iot.deepoil.cc/images/ding300.svg', new (window as any).BMap.Size(28, 30),
          {
            anchor: new (window as any).BMap.Size(10, 25),
            // imageOffset: new (window as any).BMap.Size(0, -5)
          }
        )
      });

      // 添加点击事件
      marker.addEventListener('click', () => {
        showDeviceInfo(device, point);
      });

      // 添加鼠标悬停事件
      marker.addEventListener('mouseover', () => {
        hoverDevice.value = device;
        showDeviceInfo(device, point);
      });

      marker.addEventListener('mouseout', () => {
        hoverDevice.value = null;
      });

      return marker;
    };

    const createClusterLabel = (cluster: Cluster, point: any) => {
      const label = new (window as any).BMap.Label(cluster.count.toString(), {
        position: point,
        offset: new (window as any).BMap.Size(-10, -10)
      });

      // 初始样式
      label.setStyle({
        color: '#fff',
        backgroundColor: '#c38f65',
        borderRadius: '50%',
        width: '40px',
        height: '40px',
        textAlign: 'center',
        lineHeight: '40px',
        cursor: 'pointer',
        fontSize: '18px',
        fontWeight: 'bold',
        boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
        transition: 'all 0.3s ease',
        border: '3px solid rgba(255, 255, 255, 0.5)' // 添加带有不透明度的边框
      });

      // 鼠标悬停样式
      const hoverStyle = {
        backgroundColor: '#a5734b',
        transform: 'scale(1.1)'
      };

      // 鼠标移出样式
      const normalStyle = {
        backgroundColor: '#c38f65',
        transform: 'scale(1)'
      };

      // 添加鼠标悬停事件
      label.addEventListener('mouseover', () => {
        Object.assign(label.getStyle(), hoverStyle);
        label.setStyle(label.getStyle());
      });

      // 添加鼠标移出事件
      label.addEventListener('mouseout', () => {
        Object.assign(label.getStyle(), normalStyle);
        label.setStyle(label.getStyle());
      });

      // 添加点击事件
      label.addEventListener('click', () => {
        map.value?.setZoom(9.5);
        map.value?.panTo(point);
      });

      return label;
    };

    const clusterDevices = (devices: Device[], map: any): Cluster[] => {
      const clusters: Cluster[] = [];
      const gridSize = getGridSize(map.getZoom());

      const gridMap = new Map<string, Cluster>();

      devices.forEach(device => {
        const gridKey = `${Math.floor(device.lng / gridSize)}_${Math.floor(device.lat / gridSize)}`;

        if (!gridMap.has(gridKey)) {
          gridMap.set(gridKey, {
            lng: Math.floor(device.lng / gridSize) * gridSize + gridSize / 2,
            lat: Math.floor(device.lat / gridSize) * gridSize + gridSize / 2,
            count: 0,
            devices: []
          });
        }

        const cluster = gridMap.get(gridKey)!;
        cluster.count++;
        if (!cluster.devices) cluster.devices = [];
        cluster.devices.push(device);
      });

      return Array.from(gridMap.values());
    };

    const getGridSize = (zoom: number): number => {
      if (zoom <= 5) return 2;
      if (zoom <= 8) return 1;
      if (zoom <= 10) return 0.5;
      return 0.1;
    };

    const showDeviceInfo = (device: Device, point: any) => {
      selectedDevice.value = device;
      const pixel = map.value.pointToOverlayPixel(point);
      const dialogWidth = 300; // 对话框宽度
      const arrowWidth = 10; // 箭头宽度
      const arrowHeight = 10; // 箭头高度

      // 计算对话框的左偏移量，使箭头居中指向设备
      dialogLeft.value = pixel.x - dialogWidth / 2;

      // 计算对话框的上偏移量，使箭头指向设备
      dialogTop.value = pixel.y - arrowHeight;

      // 确保对话框不会超出地图边界
      if (dialogLeft.value < 0) {
        dialogLeft.value = 0;
      }
      if (dialogTop.value < 0) {
        dialogTop.value = 0;
      }
    };

    const closeDeviceInfo = () => {
      selectedDevice.value = null;
    };

    const closeDeviceInfoIfOutside = (e: any) => {
      const dialogElement = document.querySelector('.device-info-dialog');
      if (dialogElement && selectedDevice.value) {
        const rect = dialogElement.getBoundingClientRect();
        const x = e.pixel.x;
        const y = e.pixel.y;
        if (
          x < rect.left ||
          x > rect.right ||
          y < rect.top ||
          y > rect.bottom
        ) {
          closeDeviceInfo();
        }
      }
    };

    const zoomIn = () => {
      if (map.value) {
        map.value.zoomIn();
      }
    };

    const zoomOut = () => {
      if (map.value) {
        map.value.zoomOut();
      }
    };

    const toggleMapType = () => {
      if (!map.value) return;

      mapType.value = mapType.value === 'BMAP_NORMAL_MAP'
        ? 'BMAP_SATELLITE_MAP'
        : 'BMAP_NORMAL_MAP';
      map.value.setMapType((window as any)[mapType.value]);
    };

    onMounted(() => {
      initMap();
    });

    onBeforeUnmount(() => {
      if (map.value) {
        map.value.destroy();
      }
    });

    return {
      mapContainer,
      selectedDevice,
      hoverDevice,
      deviceStatusMap,
      zoomIn,
      zoomOut,
      toggleMapType,
      showDeviceInfo,
      closeDeviceInfo,
      dialogLeft,
      dialogTop
    };
  }
});
</script>

<style scoped>
.map-container {
  position: relative;
  width: 100%;
  height: 100vh;
}

#baidu-map {
  width: 100%;
  height: 100%;
}

.map-controls {
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 1000;
  display: flex;
  gap: 10px;
}

.map-controls button {
  padding: 5px 10px;
  background: #fff;
  border: 1px solid #ccc;
  border-radius: 3px;
  cursor: pointer;
}

.device-info-dialog {
  position: absolute;
  z-index: 1000;
  width: 300px;
  background: #fff;
  border-radius: 5px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  padding: 15px;
}

.dialog-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

.dialog-header button {
  background: none;
  border: none;
  font-size: 18px;
  cursor: pointer;
}

.dialog-content p {
  margin: 5px 0;
}

/* 箭头样式 */
.dialog-arrow {
  position: absolute;
  bottom: -10px; /* 调整箭头的垂直位置 */
  left: 50%; /* 使箭头水平居中 */
  transform: translateX(-50%); /* 使箭头水平居中 */
  width: 0;
  height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-top: 10px solid #fff; /* 箭头颜色与对话框背景色一致 */
}
</style>
