<template>
  <div id="cesiumcontainer">
    <div class="tree">
      <n-row>
        <n-col :span="13"></n-col>
        <n-col :span="5">
          <n-button color="#1d97f3" @click="addFence()"> +新建电子围栏 </n-button>
        </n-col>
      </n-row>
      <n-row>
        <n-col :span="1"></n-col>
        <n-col :span="13" style="color: black;">所有区域</n-col>
      </n-row>
      <hr style="color: #e5e5e5;">
      <div class="tree-item">
        <n-scrollbar style="max-height: 300px">
          <n-tree :data="treeData" key-field="id" label-field="name" block-line checkable default-expand-all cascade
            @update:checked-keys="override" />
        </n-scrollbar>
      </div>
    </div>
    <div v-if="showModal" class="coordinates">
      <n-row>
        <n-col :span="9"></n-col>
        <n-col :span="10">
          <div style="color: #000000 ; font-size: 20px; font-weight: 500;">新建电子围栏</div>
        </n-col>
        <n-col :span="2"></n-col>
        <n-col :span="2">
          <n-button @click="handlerClose()">x</n-button>
        </n-col>
      </n-row>
      <hr style="color: #e5e5e5;">&nbsp;
      <n-row>
        <n-col :span="1"></n-col>
        <n-col :span="23">
          <n-form inline="true" ref="formRef" :model="formData" :rules="rules" label-placement="left" label-width="auto"
            require-mark-placement="right-hanging" size="small" :style="{
              maxWidth: '640px',
            }">
            <n-form-item label="区域名称:" path="rangeName">
              <n-input style="width: 200px;" :clearable="true" v-model:value="formData.rangeName"
                placeholder="请输入区域名称" />
            </n-form-item>
            <n-form-item path="rangeType">
              <n-select class="regionType" :clearable="true" style="width: 100px;" v-model:value="formData.rangeType"
                placeholder="请选择" :options="options" />
            </n-form-item>
          </n-form>
        </n-col>
      </n-row>
      <n-scrollbar style="max-height: 150px">
        <n-row style="padding-bottom: 15px; " v-for="(item, index) of posArr">
          <n-col :span="1"></n-col>
          <n-col style="display: flex; top: 2px;" :span="1">{{ index + 1 }}</n-col>
          <NCol span="11">
            <NRow gutter="12">
              <NCol :span="3" style="text-align: center; display: flex; justify-content: center; align-items: center">
                X:
              </NCol>
              <NCol :span="19">
                <NInput :clearable="true" v-model:value="item.xcoordinate" size="small" placeholder="请输入x坐标系"></NInput>
              </NCol>
            </NRow>
          </NCol>
          <NCol span="11">
            <NRow gutter="12">
              <NCol :span="4" style="text-align: center; display: flex; justify-content: center; align-items: center">
                Y:
              </NCol>
              <NCol :span="19">
                <NInput :clearable="true" v-model:value="item.ycoordinate" size="small" placeholder="请输入y坐标系"></NInput>
              </NCol>
            </NRow>
          </NCol>
        </n-row>
      </n-scrollbar>
      <n-row gutter="12">
        <n-col :span="16"></n-col>
        <n-col :span="3">
          <n-button quaternary type="info" @click="addCoordinate()">新增</n-button>
        </n-col>
        <n-col :span="3">
          <n-button quaternary type="info" @click="deleteCoordinate()">删除</n-button>
        </n-col>
      </n-row>
      <n-row gutter="12">
        <n-col :span="10"></n-col>
        <n-col :span="3">
          <n-button color="#165dff" @click="handlerSubmit()">保存采区</n-button>
        </n-col>
      </n-row>
    </div>

    <NModal v-model:show="modifyShowModel">
      <NCard style="width: 650px" title="修改区域名称" closable @close="modifyShowModel = false">
        <n-form ref="formRef" :model="formData" :rules="rules" label-placement="left" label-width="auto"
          require-mark-placement="right-hanging" :style="{
            maxWidth: '550px',
          }">
          <n-form-item label="区域名称" path="rangeName">
            <n-input v-model:value="formData.rangeName" placeholder="请输入区域名称" />
          </n-form-item>
        </n-form>

        <template #footer>
          <NFlex justify="end">
            <NSpace>
              <NButton @click="modifyShowModel = false">取消</NButton>
              <NButton type="primary" @click="modifyFenceNameSubmit()">确定</NButton>
            </NSpace>
          </NFlex>
        </template>
      </NCard>
    </NModal>
  </div>
</template>

<script lang="ts" setup>
import { addFenceApi, deleteFenceApi, getFenceByIdApi, getFenceListApi, getTreeNodeApi, updateFenceApi } from '@/api';
import { create3D } from '@/api/utils/cesium';
import { createCustomPinImage, deletePin, deletePins, getElevationFromRay } from '@/api/utils/cesiumUtil';
import { cesiumToLongitudeAndLatitude } from '@/api/utils/coordinateUtil';
import { FormRules, useMessage, NSpace, useDialog } from 'naive-ui';
import { h, onMounted, ref, watch } from 'vue';

let viewer: any = null
let pins: any = []
let heightList: any = []
let coorData: any = []
let fence = ref<any>()
let datasouce = ref<any>()
let showModal = ref(false)
let message = useMessage()
const dialog = useDialog()
let fenceData = ref({
  imagePath: '',
  imageColor: ''
})
const modifyShowModel = ref(false)
const ids = ref<any>(null)
const treeFence = ref<any>([])

const formData = ref({
  id: 0,
  rangeName: '',
  rangeType: undefined,
  coordinate: [{
    xcoordinate: "",
    ycoordinate: ""
  }]
})


const rules: FormRules = {
  rangeName: [
    { type: 'string', required: true, message: '请输入区域名称', trigger: 'blur' }
  ],
  rangeType: [
    { type: 'string', required: true, message: '请选择围栏类型', trigger: 'blur' }
  ],
}


const options = [
  {
    label: '车辆',
    value: '1',
  },
  {
    label: '人',
    value: '2'
  },
  {
    label: '全部',
    value: '3'
  }
]

const posArr = ref<any>([
  {
    xcoordinate: '',
    ycoordinate: '',
  },
  {
    xcoordinate: '',
    ycoordinate: '',
  },
  {
    xcoordinate: '',
    ycoordinate: '',
  }
]);

const treeData = ref<any>([])

watch(posArr.value, async (val, old) => {
  if (!formData.value.rangeType) {
    message.error('请先选取围栏类型后在进行操作')
    return
  }
  if (pins.length > 0) {
    handlerClean();
    pins = [];
  }
  if (heightList.length > 0) {
    heightList = []
  }

  for (let item of val) {
    console.log('111', item);

    if (item.xcoordinate && item.ycoordinate) {
      try {
        const cartographic = Cesium.Cartographic.fromDegrees(item.xcoordinate, item.ycoordinate);
        let height = await getElevationFromRay(cartographic, viewer)
        let cartesian = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, height);

        let pin = viewer.entities.add({
          position: cartesian,
          billboard: {
            image: createCustomPinImage(),
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            scale: 0.5
          }
        })

        heightList.push(height)
        pins.push({
          position: cartesian,
          pin: pin
        })
      } catch (error) {
        console.log(error);

      }
    }
  }
  createFence();
}, { deep: true })

function add3dtiles() {
  const CesiumConfig = {
    defaultAccessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2NTE1OTUxOS1jNTc5LTQwNmMtOWU5My1jNTI3NTIyYzAxNTUiLCJpZCI6MjUwODM5LCJpYXQiOjE3Mjk5MjE1MzV9.xromwPD3oA1e0YsWV035DE5KmYvivkC6fxt344vwObA",
  };

  Cesium.Ion.defaultAccessToken = CesiumConfig.defaultAccessToken;

  viewer = new Cesium.Viewer("cesiumcontainer", {
    geocoder: false,
    homeButton: false,
    infoBox: false,
    animation: false,
    fullscreenButton: false,
    enableCompass: true, // 启用指南针
    enableCompassOuterRing: true, // 启用指南针外环
    sceneModePicker: false,
    timeline: false,
    navigationHelpButton: false,
    baseLayerPicker: false,
    enableZoomControls: false, // 禁用缩放控件
    enableDistanceLegend: false // 禁用比例尺
  });

  viewer.scene.globe.depthTestAgainstTerrain = true;
  viewer.scene.globe.depthTestAgainstTerrain = true;
  viewer.cesiumWidget.creditContainer.style.display = 'none';
  viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

  let url = "http://192.168.3.249:9995/model/2025-04-22_11-28-19/terra_b3dms/tileset.json"

  create3D(viewer, url, 80)
}

async function getTreeNode() {
  let res = await getTreeNodeApi()
  if (res.data.code == 200) {
    console.log(res.data.data.data[0].children);
    treeData.value = res.data.data.data[0].children

    let areaList: any = []

    for (let item of res.data.data.data[0].children) {
      areaList.push(...item.children)
    }

    for (let item of areaList) {
      item.suffix = () => [
        h(
          NSpace,
          {
            size: 'small',
            onClick: () => {
              modifyFenceName(item.id)
            },
          },
          [
            h('img', {
              src: '/src/assets/bianjiblue.png',
              alt: '编辑',
              style: {
                width: '15px',
                height: '15px',
                marginRight: '5px',
              }
            })
          ]
        ),
        h(
          NSpace,
          {
            size: 'small',
            onClick: () => {
              deleteFenceName(item.id)
            },
          },
          [
            h('img', {
              src: '/src/assets/deletered.png',
              alt: '删除',
              style: {
                width: '15px',
                height: '15px',
                marginRight: '5px',
              }
            })
          ]
        )
      ]
    }
  } else {
    message.error(res.data.msg)
  }
}

const override = async (keys: any) => {
  ids.value = keys.join(',')
  if (ids.value) {
    let res = await getFenceListApi(ids.value)
    handlerClean()
    treeFence.value = []
    for (let item of res.data.data) {
      let positions = item.coordinate.map((item: { xcoordinate: any; ycoordinate: any; }) => {
        return [item.xcoordinate, item.ycoordinate]
      })
      let heights: any = []

      for (let data of item.coordinate) {
        const cartographic = Cesium.Cartographic.fromDegrees(data.xcoordinate, data.ycoordinate);
        let height = await getElevationFromRay(cartographic, viewer)

        heights.push(height)
      }
      electronic(positions, heights, item.rangeType)
    }
    console.log(treeFence.value);

  } else {
    handlerClean()
  }
};

async function modifyFenceName(id: any) {
  let res = await getFenceByIdApi(id)

  if (res.data.code == 200) {
    formData.value.rangeName = res.data.data.rangeName
    formData.value.id = res.data.data.id
    modifyShowModel.value = true
  } else {
    message.error(res.data.msg)
  }
}

async function modifyFenceNameSubmit() {
  let res = await updateFenceApi(formData.value.id, formData.value.rangeName)

  if (res.data.code == 200) {
    getTreeNode()
    modifyShowModel.value = false
    message.success('修改成功')
  } else {
    message.error(res.data.msg)
  }

}

function deleteFenceName(id: any) {
  dialog.create({
    title: '提示',
    content: '确定删除数据？',
    positiveText: '确定',
    negativeText: '取消',
    positiveButtonProps: {
      type: 'primary' // 设置确定按钮为蓝色
    },
    showIcon: false, // 去掉感叹号图标
    onPositiveClick: async () => {
      const res = await deleteFenceApi(id);
      if (res.data.code == 200) {
        getTreeNode()
        message.success('删除成功');
      } else {
        message.error(res.data.msg);
      }
    }
  });
}

function addCoordinate() {
  posArr.value.push({
    xcoordinate: '',
    ycoordinate: '',
  })
}

function addFence() {
  handlerClaner()
  showModal.value = true
}

async function handlerSubmit() {
  if (posArr.value.length > 0) {
    formData.value.coordinate = []

    for (let item of posArr.value) {
      if (item.xcoordinate && item.ycoordinate) {
        formData.value.coordinate.push({
          xcoordinate: item.xcoordinate,
          ycoordinate: item.ycoordinate
        })
      }
    }
    if (formData.value.coordinate.length < 3) {
      message.error('请选取三个及三个以上的点位进行保存')
    } else {
      let res = await addFenceApi(formData.value)
      if (res.data.code == 200) {
        showModal.value = false
        handlerClaner()
        deletePins(viewer, pins)
        pins = []
        message.success('新增成功')
        getTreeNode()
      } else {
        message.error(res.data.msg)
      }
    }

  } else {
    message.error('请选择区域拐点')
  }
}

function handlerClose() {
  showModal.value = false
  handlerClean();
}

function handlerClean() {
  if (pins.length > 0) {
    deletePins(viewer, pins)
  }
  if (treeFence.value.length > 0) {
    for (let item of treeFence.value) {
      datasouce.value.entities.remove(item)
    }
  }
}

function handlerClaner() {
  if (treeFence.value.length > 0) {
    for (let item of treeFence.value) {
      datasouce.value.entities.remove(item)
    }
  }

  formData.value = {
    id: 0,
    rangeName: '',
    rangeType: undefined,
    coordinate: [{
      xcoordinate: "",
      ycoordinate: ""
    }]
  }


  if (posArr.value.length > 3) {
    let data = posArr.value.length - 3;
    console.log('111', data);
    posArr.value.splice(2, data);
  }
  Object.assign(posArr.value, [
    {
      xcoordinate: '',
      ycoordinate: '',
    },
    {
      xcoordinate: '',
      ycoordinate: '',
    },
    {
      xcoordinate: '',
      ycoordinate: '',
    }
  ])

}

function deleteCoordinate() {
  heightList.pop()
  if (posArr.value.length > 3) {
    posArr.value.pop()
    if (pins.length > 0) {
      deletePin(viewer, pins[pins.length - 1])
      pins.pop()
    }
    createFence()
  } else {
    if (datasouce.value) {
      if (treeFence.value.length > 0) {
        for (let item of treeFence.value) {
          datasouce.value.entities.remove(item)
        }
        treeFence.value = []
      }
    }
    if (pins.length > 0) {
      deletePin(viewer, pins[pins.length - 1])
      pins.pop()
    }
    for (const item of posArr.value.slice().reverse()) {
      if (item.xcoordinate || item.ycoordinate) {
        item.xcoordinate = ''
        item.ycoordinate = ''
        return
      }
    }
  }
}

function createPosArrOrHeightList(data: any) {
  heightList.push(data.z)

  for (const item of posArr.value) {
    if (!item.xcoordinate || !item.ycoordinate) {
      item.xcoordinate = data.x
      item.ycoordinate = data.y
      return
    }
  }

  posArr.value.push({
    xcoordinate: data.x,
    ycoordinate: data.y
  })
}

function electronic(position: any, heightData: any, rangeType: any) {
  function map_common_addDatasouce(datasouceName: string) {
    let datasouce = viewer.dataSources._dataSources.find(t => {
      return t && t.name == datasouceName;
    });
    if (!datasouce) {
      datasouce = new Cesium.CustomDataSource(datasouceName);
      viewer.dataSources.add(datasouce);
    }
    return datasouce;
  }

  function DynamicWallMaterialProperty(options: any) {
    this._definitionChanged = new Cesium.Event();
    this._color = undefined;
    this._colorSubscription = undefined;
    this.color = options.color || Color.BLUE;
    this.duration = options.duration || 1000;
    this.trailImage = options.trailImage;
    this._time = (new Date()).getTime();
  }
  function _getDirectionWallShader(options: any) {
    if (options && options.get) {
      var materail = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\
      {\n\
          czm_material material = czm_getDefaultMaterial(materialInput);\n\
          vec2 st = materialInput.st;";
      if (options.freely == "vertical") { //（由下到上）
        materail += "vec4 colorImage = texture(image, vec2(fract(st.s), fract(float(" + options.count + ")*st.t" + options.direction + " time)));\n\ ";
      } else { //（逆时针）
        materail += "vec4 colorImage = texture(image, vec2(fract(float(" + options.count + ")*st.s " + options.direction + " time), fract(st.t)));\n\ ";
      }
      //泛光
      materail += "vec4 fragColor;\n\
          fragColor.rgb = (colorImage.rgb+color.rgb) / 1.0;\n\
          fragColor = czm_gammaCorrect(fragColor);\n\
          material.diffuse = colorImage.rgb;\n\
          material.alpha = colorImage.a;\n\
          material.emission = fragColor.rgb;\n\
          return material;\n\
      }";
      return materail
    }
  }

  Object.defineProperties(DynamicWallMaterialProperty.prototype, {
    isConstant: {
      get: function () {
        return false;
      }
    },
    definitionChanged: {
      get: function () {
        return this._definitionChanged;
      }
    },
    color: Cesium.createPropertyDescriptor('color')
  });

  var MaterialType = 'wallType' + parseInt(Math.random() * 1000);
  DynamicWallMaterialProperty.prototype.getType = function (time) {
    return MaterialType;
  };

  DynamicWallMaterialProperty.prototype.getValue = function (time, result) {
    if (!Cesium.defined(result)) {
      result = {};
    }
    result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
    result.image = this.trailImage;
    if (this.duration) {
      result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;
    }
    viewer.scene.requestRender();
    return result;
  };

  DynamicWallMaterialProperty.prototype.equals = function (other) {
    return this === other ||
      (other instanceof DynamicWallMaterialProperty
        && Cesium.Property.equals(this._color, other._color))
  };

  Cesium.Material._materialCache.addMaterial(MaterialType, {
    fabric: {
      type: MaterialType,
      uniforms: {
        color: new Cesium.Color(1.0, 0.0, 0.0, 0.1),
        image: Cesium.Material.DefaultImageId,
        time: -20
      },
      source: _getDirectionWallShader({
        get: true,
        count: 3.0,
        freely: 'vertical',
        direction: '-'
      })
    },
    translucent: function (material) {
      return true;
    }
  });
  Cesium.DynamicWallMaterialProperty = DynamicWallMaterialProperty;

  //加载范围
  function loadWall() {
    position.push(position[0])
    heightData.push(heightData[0])

    let data = position.map(item => {
      return item
    })
    let heightMax = heightData.map(item => {
      return item
    })
    console.log('111', data);
    console.log('222', heightMax);


    let coor = Array.prototype.concat.apply(
      [],
      data
    );

    let minHeightList = heightMax.map(item => {
      return item + 30;
    })

    datasouce.value = map_common_addDatasouce('wall');

    if (fence.value) {
      if (treeFence.value.length > 0) {
        for (let item of treeFence.value) {
          datasouce.value.entities.remove(item)
        }
      }
      treeData.value = []
    }

    if (rangeType == 1) {
      fenceData.value = {
        imagePath: '/src/assets/wallss.png',
        imageColor: 'Cesium.Color.ORANGE'
      }
    } else if (rangeType == 2) {
      fenceData.value = {
        imagePath: '/src/assets/walls.png',
        imageColor: 'Cesium.Color.CYAN'
      }
    } else {
      fenceData.value = {
        imagePath: '/src/assets/walls.png',
        imageColor: 'Cesium.Color.CYAN'
      }
    }

    let entity = datasouce.value.entities.add({
      wall: {
        positions: Cesium.Cartesian3.fromDegreesArray(coor),
        maximumHeights: heightMax,
        minimumHeights: minHeightList,
        material: new Cesium.DynamicWallMaterialProperty({
          trailImage: fenceData.value.imagePath,
          color: fenceData.value.imageColor,
          duration: 1500
        })
      },
    });
    treeFence.value.push(entity)
    // 保存围栏数据用于边界检测
    window.fenceData = position;
  }
  loadWall();
}

function createFence() {
  if (pins.length >= 3) {
    let res = []
    for (let item of posArr.value) {
      if (item.xcoordinate && item.ycoordinate) {
        res.push([item.xcoordinate, item.ycoordinate])
      }
    }
    coorData = res

    let heights = heightList.map((item: any) => {
      return item
    })

    electronic(coorData, heights, formData.value.rangeType)
  }
}

onMounted(() => {
  add3dtiles()
  getTreeNode()
  const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

  // 鼠标相关事件
  handler.setInputAction(function (click: any) {
    const pickedObject = viewer.scene.pick(click.position)

    if (!showModal.value) {
      return;
    }

    if (!formData.value.rangeType) {
      message.error('请先选取围栏类型后在进行操作')
      return;
    }

    if (Cesium.defined(pickedObject) && pickedObject.id && pickedObject.collection) {
      return;
    }

    const cartesian = viewer.scene.pickPosition(click.position);

    let coorResult = cesiumToLongitudeAndLatitude(cartesian)

    createPosArrOrHeightList(coorResult)
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
})
</script>

<style scoped>
#home {
  width: 100%;
  height: 100%;
}

.tree {
  width: 300px;
  height: 400px;
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 1;
  background-color: white;
  padding-top: 10px;
}

.coordinates {
  width: 450px;
  height: 350px;
  position: absolute;
  margin-top: 280px;
  margin-left: 996px;
  z-index: 99;
  background-color: white;
  padding-top: 10px;
}


#cesiumcontainer {
  width: 100%;
  height: 70vh;
  position: relative;
  overflow: hidden;
  box-sizing: border-box;
  /* 添加以下属性 */
  contain: strict;
  isolation: isolate;
}
</style>