<template>
  <div id="scene">
    <div id="cvs" ref="content"></div>
    <dev-info ref="info" :devInfo="devInfo" />
    <!-- 这里的预览模式需要做成不能修改的模式 -->
    <edit-dialog
      ref="edit"
      @addEquipment="handleAddEqu"
      @removeEquipment="handleRemoveEqu"
      @cancel="handleCancel"
      :hasDev="hasDevice"
      :pointNum="pointNum"
      :tunnelId="params.tunnelId"
      :position="targetP?.name"
      :hasEquipment="hasDevice"
      :pointGap="pointGap"
      :form="params.form"
    />
    <el-dialog
      v-model="centerDialogVisible"
      width="30%"
      destroy-on-close
      center
      :show-close="false"
      style="
        margin: 20% auto;
        width: 569px;
        height: 330px;
        background: rgba(7, 35, 72, 0.79);
        border-radius: 20px;
        border: 2px solid #0f82af;
      "
    >
      <p id="remove-title">是否确定删除该设备</p>
      <div class="btn">
        <button @click="centerDialogVisible = false">取消</button>
        <button @click="handleConfirmAddEqu">确定</button>
      </div>
    </el-dialog>
  </div>
</template>

<script setup>
import * as three from "three";
import ThreeDScene from "./sceneClass/demo.js";
import DevInfo from "./displayInfoComp/DevInfo.vue";
import EditDialog from "./editEquComp/editDialog.vue";

// 导入模模型加载器
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
// import { DRACOLoader } from "three/examples/jsm/loaders/dracoloader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import * as TWEEN from "three/examples/jsm/libs/tween.module";
import {
  CSS3DRenderer,
  CSS3DObject,
  CSS3DSprite,
} from "three/addons/renderers/CSS3DRenderer.js";
// 引入CSS2渲染器CSS2DRenderer和CSS2模型对象CSS2DObject
import {
  CSS2DRenderer,
  CSS2DObject,
} from "three/addons/renderers/CSS2DRenderer.js";

import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import { onMounted, reactive, ref, watch } from "vue";
import { ElMessage } from "element-plus";
import { deleteEquipment, initData } from "./request";

// 获取html标签跟随组件dom
const content = ref(null);
const info = ref(null);
const edit = ref(null);
let modelList = ref(null);
let demo; //定义demo对象
const loader = new OBJLoader();
let hdrLoader = new RGBELoader();
let backColorSet = three.sRGBEncoding;

const params = defineProps(["isedit", "tunnelId", "tunnelLength", "form"]); //接收参数看是不是编辑模式，如果是编辑模式，则需要做一些处理

let isedit = ref(params.isedit);
let tunnelId = reactive(params.tunnelId);

watch(
  () => params.tunnelLength,
  (now) => {
    params.tunnelLength = now;
    console.log(params.tunnelLength);
    pointGap = now / 20;
  },
  { deep: true }
);

let pointGap = reactive(params.tunnelLength);

onMounted(handleMounted);
// 挂载后回调
async function handleMounted() {
  const doms = [info.value.$el, edit.value.$el];
  demo = new ThreeDScene(three, content.value);
  //看是不是预览模式，然后继续相关的操作(会在demo中的初始化中进行)
  demo.isedit = params.isedit;

  const loaded = await demo.loadModel(
    GLTFLoader,
    "./assets/tunnelModel/chanel-have-wall.gltf"
  );
  demo.addOrbitControls(OrbitControls);
  demo.addTween(TWEEN);
  demo.addCSS3Renderer(CSS3DRenderer, CSS3DSprite, doms);
  demo.setDistance(10);
  lClickCallback(demo); //绑定左键回调
  rClickCallback(demo); //绑定右键回调

  //加载HDR背景图片
  demo.loadBackground(hdrLoader, backColorSet);

  // 初始化设备模型
  try {
    const map = new Map();
    map.set("equ_fan", await loadModel("/devicesModel/model2.obj"));
    map.set("equ_sensors", await loadModel("/devicesModel/sensors.obj"));
    demo.initDevicesModel(map);
    // 初始化
    modelList.value = await initData(params.tunnelId, params.form);
    console.log("init", params.tunnelId);
    demo.editTunnelInit(modelList.value);
  } catch (err) {
    ElMessage({
      message: "场景初始化异常！",
      type: "warning",
    });
  }
}

// 每个模型加载回调
function loadModel(path) {
  return new Promise((resolve, reject) => {
    loader.load(
      path,
      (obj) => {
        resolve(obj);
      },
      (xhr) => {},
      (err) => {
        reject(err);
      }
    );
  });
}

let hasDevice = ref(true);
let devInfo = reactive({
  meshId: null,
  name: "无",
  state: "无",
  position: "无",
});

// 对象建构赋值功能
function editDevInfo(
  value = {
    meshId: null,
    name: "无",
    state: "无",
    position: "无",
  }
) {
  devInfo.meshId = value.meshId;
  devInfo.name = value.name;
  devInfo.state = value.state;
  devInfo.position = value.position;
}

//左键/双击左键回调函数
function lClickCallback(demo) {
  //demo动态添加函数，为操作组件内部
  function displayDevInfo(targetPoint = null) {
    hasDevice.value = targetPoint.hasDevice;
    if (!targetPoint.info) {
      editDevInfo();
      return;
    }
    editDevInfo(targetPoint.info);
  }

  // 传给内部使用
  demo.addFunction("displayDevInfo", displayDevInfo);
}

let pointNum = ref(0);
let targetP = ref({});
// 右键点击附着点后调函数
function rClickCallback(demo) {
  function editDev(targetPoint = null) {
    hasDevice.value = targetPoint.hasDevice;
    targetP.value = targetPoint;
    pointNum.value = Number(
      targetPoint.name.substring(
        targetPoint.name.indexOf("_") + 1,
        targetPoint.name.lastIndexOf("_")
      ) - 1
    );
    if (!targetPoint.info) return;
    editDevInfo(targetPoint.info);
  }
  demo.addFunction("editDev", editDev);
}

// 场景添加设备
function handleAddEqu(formInfo) {
  demo.addEquipment(targetP.value, formInfo);
}

const centerDialogVisible = ref(false);
// 删除设备
function handleRemoveEqu() {
  if (!targetP.value.hasDevice) {
    ElMessage({
      message: "该点位不存在设备！",
      type: "warning",
    });
    return;
  }
  centerDialogVisible.value = true;
}
// 对话框确认删除
function handleConfirmAddEqu() {
  console.log("target:", targetP.value.info);
  deleteEquipment(targetP.value.info.equipmentId, pointGap)
    .then((res) => {
      demo.removeEquipment(targetP.value);
      centerDialogVisible.value = false;
      ElMessage({
        message: "删除成功！",
        type: "success",
      });
    })
    .catch((res) => {
      ElMessage({
        message: "删除失败！",
        type: "warning",
      });
    });
}
// 处理取消关闭编辑框事件
function handleCancel() {
  if (!demo) return;
  // 关闭标签
  demo.isControlOrbit(true);
  demo._resetState();
  demo.clearTagsObj();
}

//现在首先有二种方案，是写在TunnelScene.vue中还是demo.js中呢？
//我认为可能看数据在哪获取？到时候看在哪里导入，首先我们放在TunnelScene里面吧
//因为没获取到接口，我们先写死！！！
//需要参考接口的数据结构！！！，主要是传入函数的参数应该是什么结构？？？
const ThreeConfig = {
  code: 0,
  data: {
    tunnelThreeConfig: [
      {
        equipmentId: "fan_01", //传感器id
        equipmentName: "01", //设备名称
        pointName: "point_005_tl", //附着点名称(定位)
        equipmentType: "fan", //设备类型(类型可根据后端
        equipmentValue: 23, //设备存的值
      },
      {
        equipmentId: "sensors_01", //传感器id
        equipmentName: "01", //设备名称
        pointName: "point_009_bl", //附着点名称(定位)
        equipmentType: "sensors", //设备类型(类型可根据后端
        equipmentValue: 67, //设备存的值
      },
    ],
  },
  msg: "dda",
};
</script>

<style lang="scss" scoped>
#scene {
  position: relative;
  height: 100%;
  width: 100%;

  #cvs {
    height: 100%;
  }
}

#remove-title {
  height: 42px;
  font-size: 32px;
  font-family: MicrosoftYaHei, MicrosoftYaHei;
  font-weight: bold;
  color: #08b7b8;
  line-height: 42px;
  letter-spacing: 3px;
  text-align: center;
  margin: 65px 0px 70px 0px;
}

.btn {
  display: flex;
  justify-content: center;
  gap: 80px;

  :nth-child(1) {
    width: 190px;
    height: 60px;
    border-radius: 11px;
    border: 2px solid #0f82af;
    font-size: 28px;
    font-family: MicrosoftYaHei;
    color: #08b7b8;
    line-height: 37px;
    background: transparent;
  }

  :nth-child(2) {
    width: 190px;
    height: 60px;
    background: #08b7b8;
    border-radius: 11px;
    font-size: 28px;
    font-family: MicrosoftYaHei, MicrosoftYaHei;
    font-weight: bold;
    color: #ffffff;
    line-height: 37px;
  }
}
</style>
