<template>
  <div class="flex justify-between" v-loading="treeLoading">
    <el-tree-v2
      style="width: 340px; overflow: auto"
      show-checkbox
      :data="jsonData"
      :height="500"
      @check-change="handleCheckChange"
      :props="treeProps"
      @node-contextmenu="showMenu"
      ref="treeRef"
      @node-click="isMenuVisible = false"
    >
      <template #default="{ node, data }">
        <span @dblclick="handlePosition(data)">{{ data.name }}</span>
      </template>
    </el-tree-v2>
    <div>
      <div class="ol-map" id="olMap"></div>
      <div class="h15" v-if="!selectLayer.length"></div>
      <div class="m-0 c-white text-3 flex" v-else>
        <p
          v-for="(item, index) in selectLayer"
          class="pl-xl border-rd pr mt-2 p-3 w-111 mr-1 bg-#909399 flex items-center cursor-pointer justify-between"
          @click="delLayer(index)"
        >
          {{ item.location.name + '被选中为' + item.option }}
          <el-icon>
            <Close />
          </el-icon>
        </p>
      </div>
      <el-form-item label="类型" class="items-center">
        <el-radio-group v-model="layerType">
          <el-radio value="1" size="large">光伏板</el-radio>
          <el-radio value="2" size="large">桩点/支架</el-radio>
          <el-radio value="3" size="large">方阵</el-radio>
        </el-radio-group>
      </el-form-item>
    </div>

    <div v-if="isMenuVisible" :style="{ left: menuX + 'px', top: menuY + 'px' }" class="fixed bg-white shadow-md rounded-md overflow-hidden">
      <ul class="py-1 pl-0">
        <li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('光伏板')">
          <i class="fa-solid fa-check mr-2"></i>光伏板
        </li>
        <li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('桩点/支架')">
          <i class="fa-solid fa-times mr-2"></i>桩点/支架
        </li>
        <li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('方阵')">
          <i class="fa-solid fa-times mr-2"></i>方阵
        </li>
        <li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('名称')">
          <i class="fa-solid fa-times mr-2"></i>名称
        </li>
      </ul>
    </div>
  </div>
  <div class="float-right">
    <el-button @click="emit('close')">取消</el-button>
    <el-button type="primary" @click="addFacilities" :loading="loading">确定</el-button>
  </div>
</template>

<script lang="ts" setup>
import Map from 'ol/Map'; // OpenLayers的主要类，用于创建和管理地图
import View from 'ol/View'; // OpenLayers的视图类，定义地图的视图属性
import { Tile as TileLayer } from 'ol/layer'; // OpenLayers的瓦片图层类
import { XYZ, OSM } from 'ol/source'; // OpenLayers的瓦片数据源，包括XYZ格式和OpenStreetMap专用的数据源
import { fromLonLat, toLonLat } from 'ol/proj'; // OpenLayers的投影转换函数，用于经纬度坐标和投影坐标之间的转换
import { defaults as defaultInteractions, DragRotateAndZoom } from 'ol/interaction'; // OpenLayers的交互类，包括默认的交互集合和特定的旋转缩放交互
import { defaults as defaultControls, defaults, FullScreen, MousePosition, ScaleLine } from 'ol/control'; // OpenLayers的控件类，包括默认的控件集合和特定的全屏、鼠标位置、比例尺控件
import Feature from 'ol/Feature'; // OpenLayers的要素类，表示地图上的一个对象或实体
import Point from 'ol/geom/Point'; // OpenLayers的点几何类，用于表示点状的地理数据
import { Vector as VectorLayer } from 'ol/layer'; // OpenLayers的矢量图层类，用于显示矢量数据
import { Vector as VectorSource } from 'ol/source'; // OpenLayers的矢量数据源类，用于管理和提供矢量数据
import { Circle, Style, Stroke, Fill, Icon, Text } from 'ol/style'; // OpenLayers的样式类，用于定义图层的样式，包括圆形样式、基本样式、边框、填充和图标
import LineString from 'ol/geom/LineString'; // OpenLayers的线几何类，用于表示线状的地理数据
import Polygon from 'ol/geom/Polygon'; // OpenLayers的多边形几何类，用于表示面状的地理数据
import * as turf from '@turf/turf';
import { TreeInstance } from 'element-plus';
import { addProjectFacilities, addProjectPilePoint, addProjectSquare, listDXFProject } from '@/api/project/project';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;

const props = defineProps({
  projectId: String,
  designId: String
});
const treeData = ref<any>([]);
const layerType = ref(null);
const contextMenu = ref(null);
const selectLayer = ref([]);
const treeRef = ref<TreeInstance>();
const treeProps = {
  value: 'name'
};
const loading = ref(false);
const treeLoading = ref(false);
const emit = defineEmits(['handleCheckChange', 'close']);
let map: any = null;

const layerData = reactive<any>({});
const centerPosition = ref(fromLonLat([107.13761560163239, 23.80480003743964]));

const jsonData = computed(() => {
  let id = 0;
  let arr = [];
  treeData.value.forEach((item: any, index: any) => {
    arr.push({
      name: item.name,
      index
    });
    for (const itm of item.features) {
      if (itm.geometry.id) {
        break;
      }
      itm.geometry.id = ++id;
      itm.geometry.coordinates = convertStrToNum(itm.geometry.coordinates);
    }
  });
  return arr; // treeData.value;
});
console.log(jsonData);

const handlePosition = (data: any) => {
  //切换中心点
  centerPosition.value = fromLonLat(turf.center(data).geometry.coordinates);
  console.log(turf.center(data));

  map.getView().setCenter(centerPosition.value);
};
const handleCheckChange = (data: any, bool) => {
  let features = treeData.value[data.index].features;
  if (isMenuVisible.value) isMenuVisible.value = false;
  if (bool) {
    if (!layerData[features[0].properties.id]) {
      features.forEach((item: any) => {
        creatPoint(item.geometry.coordinates, item.geometry.type, item.geometry.id, item.properties.text);
      });
    } else {
      features.forEach((item: any) => {
        map.addLayer(layerData[item.geometry.id]);
      });
    }
  } else {
    features.forEach((item, index) => {
      map.removeLayer(layerData[item.geometry.id]);
    });
  }

  // creatPoint(fromLonLat(data.geometry.coordinates), data.geometry.type);
};
function initOLMap() {
  // 创造地图实例
  map = new Map({
    // 设置地图容器的ID
    target: 'olMap',
    // 定义地图的图层列表，用于显示特定的地理信息。
    layers: [
      // 高德地图
      // TileLayer表示一个瓦片图层，它由一系列瓦片（通常是图片）组成，用于在地图上显示地理数据。
      new TileLayer({
        // 设置图层的数据源为XYZ类型。XYZ是一个通用的瓦片图层源，它允许你通过URL模板来获取瓦片
        source: new XYZ({
          url: 'https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}'
        })
      })
    ],
    // 设置地图的视图参数
    // View表示地图的视图，它定义了地图的中心点、缩放级别、旋转角度等参数。
    view: new View({
      // fromLonLat是一个函数，用于将经纬度坐标转换为地图的坐标系统。
      center: centerPosition.value, //地图中心点
      zoom: 15, // 缩放级别
      minZoom: 0, // 最小缩放级别
      // maxZoom: 18, // 最大缩放级别
      constrainResolution: true // 因为存在非整数的缩放级别，所以设置该参数为true来让每次缩放结束后自动缩放到距离最近的一个整数级别，这个必须要设置，当缩放在非整数级别时地图会糊
      // projection: 'EPSG:4326' // 投影坐标系，默认是3857
    }),
    // 按住shift进行旋转
    // interactions: defaultInteractions().extend([new DragRotateAndZoom()]),
    // 控件
    // controls: defaults().extend([
    //   new FullScreen(), // 全屏
    //   new MousePosition(), // 显示鼠标当前位置的地图坐标
    //   new ScaleLine() // 显示比例尺

    // ])

    //加载控件到地图容器中
    controls: defaultControls({
      zoom: false,
      rotate: false,
      attribution: false
    }).extend([
      new FullScreen() // 全屏
    ])
  });

  // 事件
  // map.on('moveend', (e: any) => {
  //   // console.log('地图移动', e);
  //   // 获取当前缩放级别
  //   var zoomLevel = map.getView().getZoom();
  //   // console.log('当前缩放级别：', zoomLevel);
  // });
  // map.on('rendercomplete', () => {
  //   // console.log('渲染完成');
  // });
  // map.on('click', (e: any) => {
  //   var coordinate = e.coordinate;

  //   // 将投影坐标转换为经纬度坐标
  //   var lonLatCoordinate = toLonLat(coordinate);
  //   // 输出转换后的经纬度坐标
  //   console.log('经纬度坐标：', lonLatCoordinate);
  // });
}

//递归字符串数组变成数字
function convertStrToNum(arr) {
  if (typeof arr === 'string') {
    const num = Number(arr);
    return isNaN(num) ? arr : num;
  } else if (Array.isArray(arr)) {
    return arr.map((item) => convertStrToNum(item));
  }
  return arr;
}

/**
 * 创建图层
 * @param {*} pointObj 坐标数组
 * @param {*} type 类型
 * @param {*} id 唯一id
 * @param {*} name 名称
 *    */
const creatPoint = (pointObj: Array<any>, type: string, id: string, name?: string) => {
  // 创建多边形的几何对象
  let polygon;
  if (type === 'Point') {
    polygon = new Point(fromLonLat(pointObj));
  } else if (type === 'LineString') {
    const lineStringData = pointObj.map((arr: any) => fromLonLat(arr));
    polygon = new Polygon([lineStringData]);
  } else {
    const polygonData = pointObj.map((arr: any) => arr.map((i: any) => fromLonLat(i)));
    polygon = new Polygon(polygonData);
  }
  // 创建特征（Feature）
  let polygonFeature = new Feature({
    geometry: polygon
  });

  const pointStyle = new Style({
    image: new Circle({
      radius: 2,
      fill: new Fill({
        color: 'red'
      })
    }),
    text: new Text({
      font: '12px Microsoft YaHei',
      text: name,
      scale: 1,
      fill: new Fill({
        color: '#7bdd63'
      })
    })
  });
  const polygonStyle = new Style({
    stroke: new Stroke({
      color: type === 'LineString' ? 'skyblue' : 'purple', // 多边形边界线的颜色
      width: 2 // 多边形边界线的宽度
    }),
    fill: new Fill({
      color: 'transparent' // 多边形填充颜色，这里设置为半透明红色
    })
  });
  // 设置多边形的样式（Style）
  polygonFeature.setStyle(type === 'Point' ? pointStyle : polygonStyle);
  // 创建和添加特征到源（Source）
  let source = new VectorSource();
  source.addFeature(polygonFeature);
  // 创建图层并设置源（Layer）
  layerData[id] = new VectorLayer();
  layerData[id].setSource(source);

  map.addLayer(layerData[id]);
};

// 控制菜单是否显示
const isMenuVisible = ref(false);
// 菜单的 x 坐标
const menuX = ref(0);
// 菜单的 y 坐标
const menuY = ref(0);

// 显示菜单的方法
const showMenu = (event: MouseEvent, data) => {
  console.log('🚀 ~ showMenu ~ data:', data, treeData.value[data.index]);
  contextMenu.value = data;
  isMenuVisible.value = true;
  menuX.value = event.clientX;
  menuY.value = event.clientY;
};

// 处理菜单项点击事件的方法
const handleMenuItemClick = (option: string) => {
  isMenuVisible.value = false;
  if (selectLayer.value.length == 2) {
    ElMessage.warning('最多只能选择两个图层');
    return;
  }
  selectLayer.value.push({ location: contextMenu.value, option });
  emit('handleCheckChange', selectLayer.value);
};

//删除菜单
const delLayer = (index) => {
  selectLayer.value.splice(index, 1);
  emit('handleCheckChange', selectLayer.value);
};

// 点击页面其他区域隐藏菜单
const closeMenuOnClickOutside = (event: MouseEvent) => {
  if (isMenuVisible.value) {
    const menuElement = document.querySelector('.fixed.bg-white');
    if (menuElement && !menuElement.contains(event.target as Node)) {
      isMenuVisible.value = false;
    }
  }
};

// 添加全局点击事件监听器
window.addEventListener('click', closeMenuOnClickOutside);
const getTreeData = async () => {
  treeLoading.value = true;
  try {
    const res = await listDXFProject(props.designId);
    treeData.value = res.data.layers;
    treeLoading.value = false;
  } catch (err) {
    treeLoading.value = false;
  }
};

// 组件卸载时移除事件监听器
const onUnmounted = () => {
  window.removeEventListener('click', closeMenuOnClickOutside);
};

const addFacilities = async () => {
  console.log(layerType.value);

  if (!layerType.value) {
    return proxy?.$modal.msgError('请选择图层类型');
  }
  if (!selectLayer.value.length) {
    return proxy?.$modal.msgError('请选择需要上传的图层');
  }
  const data = {
    projectId: props.projectId,
    nameGeoJson: null,
    locationGeoJson: null,
    pointGeoJson: null
  };

  if (layerType.value == 1) {
    if (!checkOptions(selectLayer.value, '光伏板')) {
      return proxy?.$modal.msgError('请选择名称和光伏板');
    }
    loading.value = true;
    if (selectLayer.value[0].option == '名称') {
      data.nameGeoJson = treeData.value[selectLayer.value[0].location.index];
      data.locationGeoJson = treeData.value[selectLayer.value[1].location.index];
    } else {
      data.nameGeoJson = treeData.value[selectLayer.value[1].location.index];
      data.locationGeoJson = treeData.value[selectLayer.value[0].location.index];
    }

    await addProjectFacilities(data);
    await proxy?.$modal.msgSuccess('添加成功');
  } else if (layerType.value == 2) {
    if (selectLayer.value.length > 1) return proxy?.$modal.msgError('最多选择一个桩点/支架');
    if (selectLayer.value[0].option != '桩点/支架') return proxy?.$modal.msgError('请选择类型为桩点/支架');
    loading.value = true;
    data.pointGeoJson = treeData.value[selectLayer.value[0].location.index];
    await addProjectPilePoint(data);
    await proxy?.$modal.msgSuccess('添加成功');
  } else if (layerType.value == 3) {
    if (!checkOptions(selectLayer.value, '方阵')) {
      return proxy?.$modal.msgError('请选择名称和方阵');
    }
    loading.value = true;
    if (selectLayer.value[0].option == '名称') {
      data.nameGeoJson = treeData.value[selectLayer.value[0].location.index];
      data.locationGeoJson = treeData.value[selectLayer.value[1].location.index];
    } else {
      data.nameGeoJson = treeData.value[selectLayer.value[1].location.index];
      data.locationGeoJson = treeData.value[selectLayer.value[0].location.index];
    }

    await addProjectSquare(data);
    await proxy?.$modal.msgSuccess('添加成功');
  }
  reset();
  loading.value = false;
};

const reset = () => {
  selectLayer.value = [];
  treeRef.value?.setCheckedKeys([]);
  for (const key in layerData) {
    map.removeLayer(layerData[key]);
  }
  layerType.value = null;
};
//校验
function checkOptions(arr, type) {
  let hasName = false;
  let hasJson = false;

  for (let i = 0; i < arr.length; i++) {
    if (arr[i].option === '名称') {
      hasName = true;
    } else if (arr[i].option === type) {
      hasJson = true;
    }
  }

  return hasName && hasJson;
}

watch(
  () => props.designId,
  (newId, oldId) => {
    if (newId !== oldId) {
      reset();
      getTreeData();
    }
  },
  { immediate: true }
);

onMounted(() => {
  // 地图初始化
  initOLMap();
  console.log(props.designId);
});
</script>
<style scoped lang="scss">
.ol-map {
  height: 450px;
  width: 950px;
  margin: 0 auto;
}
.ol-custome-full-screen {
  border-radius: 3px;
  font-size: 12px;
  padding: 5px 11px;
  height: 24px;
  background-color: #409eff;
  color: #fff;
  border: 1px solid #409eff;
  &:active {
    background-color: #337ecc;
    border-color: #66b1ff;
  }
  &:hover {
    background-color: #79bbff;
    border-color: #79bbff;
  }
}
li {
  list-style-type: none;
}
</style>
