<template>
    <div>
        <div id="gltf"></div>
        <div id="dom"></div>
        <div class="btnGroup">
            <div class="button" @click="toHomeView">
                主视角
            </div>
            <div class="button" @click="setLabel">
                {{ isAddLabel ? '添加标签' : '移除标签' }}
            </div>
            <div class="button" @click="setBottom()">
                {{ isRemoveBottom ? '移除地板' : '恢复地板' }}
            </div>
            <!-- <div class="button" @click="roam()">
                漫游
            </div> -->
            <div class="button" @click="warn()">
                查看预警设备
            </div>
            <div class="button" @click="check()">
                巡检
            </div>
            <div class="button" @click="changeMap()">
                墙体寿命
            </div>
        </div>
        <div class="wall_tooltips" v-show="isShowWall">
            <p>
                <span class="qing"></span>小于1年
            </p>
            <p>
                <span class="blue"></span>大于1年小于2年
            </p>
            <p>
                <span class="yellow"></span>大于2年小于3年
            </p>
            <p>
                <span class="red"></span>大于3年
            </p>
        </div>
    </div>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue';
import * as THREE from 'three';
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
import { RoomEnvironment } from "three/examples/jsm/environments/RoomEnvironment.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import TWEEN from "@tweenjs/tween.js";
import imgs from "../../../../assets/finish.png";
import {
    CSS2DObject,
    CSS2DRenderer,
} from "three/examples/jsm/renderers/CSS2DRenderer";
import Bus from '@/utils/bus.js'
import bimStore from '@/store/modules/bim';
import gsap from "gsap";
onMounted(() => {
    init();
    loadSence();
    renderScene();
    //点击模型
    document.addEventListener('click', onMouseDown);
    // 右击事件
    window.addEventListener('contextmenu', function (e) {
        if (e.button === 2) {
            onMouseDownRight(e);
        }
    });
    // document.addEventListener("mousemove", onMouseMove);
});
let scene, renderer, camera, controls, clickedObject, model;

// 克隆颜色和模型
let objArr = [];
let objM = [];
// 监测设备
let warnSets = [];
// 设置巡检
let checkArr = [];
let checkindex = 0;



let mouse = new THREE.Vector2();
let labelRenderer = new CSS2DRenderer(); //新建CSS2DRenderer
const data = reactive({
    isAddLabel: true,
    isRemoveBottom: true,
    isShowWall: false //墙体
});
const { isAddLabel, isRemoveBottom, isShowWall } = toRefs(data);
// 建筑树点击
Bus.on('clickBuild', (isParent) => {
    // Todo
    console.log('clickBuild', isParent);
    var clickName = bimStore().activateTree.clickName;
    var Floor = scene.getObjectByName(clickName);
    boxLight(Floor);
    
    return;
})
// 设备树点击
Bus.on('clickDevice', (isParent) => {
    if (!isParent) {// 点击子级
        var clickName = bimStore().activateDevice.clickName;
        var Floor = scene.getObjectByName(clickName);
        removeLabel();
        boxLight(Floor);
        // 拉近距离
        // nearCamera(Floor);
        return;
    }
})

// 系统树点击
Bus.on('clickApplication', (isParent) => {
    // Todo
    if (!isParent) {
        xiaof();
    }

})
// 监听底部菜单切换
watch(() => bimStore().activateMenu, value => {
    // 更换场景颜色
    scene.background = new THREE.Color(value.background);
    toHomeView();
    // 移除消防图标
    removexf();
}, { deep: true });

const init = () => {
    // 场景
    scene = new THREE.Scene();
    scene.background = new THREE.Color(bimStore().activateMenu.background);
    // 相机
    camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(-65.82410159732751, 111.17437832684305, -45.026345528621334);
    camera.lookAt(scene.position);
    //渲染器
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.outputEncoding = THREE.sRGBEncoding;
    document.getElementById('gltf').appendChild(renderer.domElement);

    controls = new OrbitControls(camera, renderer.domElement);
    const pmremGenerator = new THREE.PMREMGenerator(renderer);
    scene.environment = pmremGenerator.fromScene(new RoomEnvironment()).texture;
    var vector = new THREE.Vector3();
    console.log('刚开始场景', vector);
}
const loadSence = () => {
    const gltfLoader = new GLTFLoader();
    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath('/draco/gltf/')//设置解压库文件路径
    gltfLoader.setDRACOLoader(dracoLoader)
    gltfLoader.load('/jzc/jz.gltf', (gltf) => {
        model = gltf.scene;
        // 克隆初始的材料和模型
        model.traverse(e => {
            objArr.push(e);
            objM.push(e.material);
            if (enableGroup.indexOf(e.name) != -1) {
                xfobj.push(e);
            }
            if (yjGroup.indexOf(e.name) != -1) {
                yjobj.push(e);
            }
        })

        // 获取巡检设备
        const checkname = [{
            name: 'start',
            isPass: true
        }, {
            name: 'middle1',
            isPass: true
        }, {
            name: 'middle2',
            isPass: false
        }, {
            name: 'end',
            isPass: true
        }]
        checkname.forEach((item, index) => {
            var targetO = model.getObjectByName(item.name);
            if (targetO) {
                targetO.isPass = item.isPass;
                checkArr.push(
                    targetO
                )
            }
        })

        scene.add(model);

    });
};
const renderScene = () => {
    requestAnimationFrame(renderScene);
    const cameraPosition = camera.position;
    const cameraX = cameraPosition.x;
    const cameraY = cameraPosition.y;
    const cameraZ = cameraPosition.z;
    // console.log('坐标', cameraX, cameraY, cameraZ);
    TWEEN.update();
    controls.update();
    renderer.render(scene, camera);
    labelRenderer.render(scene, camera);
};

const onWindowResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener("resize", onWindowResize, false);

// 能选中的组
const enableGroup = [
    'yuanliao_room',
    'tanghua_room',
    'touliao_room',
    'guolvcao_1',// 过滤槽
    'T3',
    'T4',
    'T5',
    'T6',
    'T7',
    'T8',
    'T9',
    'T10',
    'T11',// 立仓
    'T12'
]
// 预警设备
const yjGroup = [
    'T7',
]
const isSelent = (obj) => {
    var o = obj
    while (true) {
        if (o.name != "jzgltf" && enableGroup.indexOf(o.name) != -1) {
            return o;
        } else {
            if (o.parent && o.parent.name == "jzgltf") {
                return null;
            } else {
                o = o.parent;
            }
        }
    }
}

let selectedObjects = ref([]);
let selectBoxByClick, selectBoxByMouseon, pointLabel, selectedObject;
var marginLeft = 0;
var marginTop = 70;
// 鼠标移动效果
const onMouseMove = (event) => {
    var raycaster = new THREE.Raycaster()
    mouse.x = ((event.clientX - marginLeft) / window.innerWidth) * 2 - 1;
    mouse.y = -((event.clientY - marginTop) / window.innerHeight) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(scene.children, true);
    if (intersects.length > 0) {
        const clickedObject = intersects[0].object;
        selectedObject = isSelent(clickedObject);
        if (selectedObject) {
            selectedObjects[0] = selectedObject;
            if (selectBoxByMouseon) {
                scene.remove(selectBoxByMouseon);
            }
            selectBoxByMouseon = new THREE.BoxHelper(selectedObjects[0], '#ffffff');
            scene.add(selectBoxByMouseon);
        }
    }
}
const emit = defineEmits(['handleRightClick', 'checkComplete'])
// 鼠标右击事件
const onMouseDownRight = (event) => {
    var raycaster = new THREE.Raycaster()
    mouse.x = ((event.clientX - marginLeft) / window.innerWidth) * 2 - 1;
    mouse.y = -((event.clientY - marginTop) / window.innerHeight) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(scene.children, true);
    // console.log(123, event);

    if (intersects.length > 0) {
        const clickedObject = intersects[0].object;
        console.log('这是我选中的模型', clickedObject);
        selectedObject = isSelent(clickedObject);
        addLabel(selectedObject, 'details');
    }
}
// 鼠标点击效果
const onMouseDown = (event) => {
    var raycaster = new THREE.Raycaster()
    // 将鼠标点击位置的屏幕坐标转换成threejs中的标准坐标
    mouse.x = ((event.clientX - marginLeft) / window.innerWidth) * 2 - 1;
    mouse.y = -((event.clientY - marginTop) / window.innerHeight) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(scene.children, true);
    console.log(123, event);

    if (intersects.length > 0) {
        clickedObject = intersects[0].object;
        console.log('这是我选中的模型', clickedObject);
        selectedObject = isSelent(clickedObject);
        // 高亮所在区域
        boxLight(selectedObject);
        // 染色点击的模型
        console.log(1, clickedObject);
        if (bimStore().activateIndex == '0') {
            // 联动左侧菜单
            Bus.emit('handleTreeClick', clickedObject);
            return;
        }
        if (bimStore().activateIndex == '1') {
            // 联动左侧菜单
            Bus.emit('handleTreeClick1', clickedObject);
            return;
        }

    }
}
const changeColor = (Floor) => {
    // Floor.children.forEach((obj) => {
    //     if (obj.isMesh) {
    //         console.log(123, obj);
    //         obj.material.transparent = true;
    //         obj.material.opacity = 0.3;
    //         obj.material.color = new THREE.Color('rgb( 0 , 0 , 225 )');
    //     }
    // })
    // 染色
    Floor.traverse(e => {
        if (e.isMesh) {
            e.material.transparent = true;
            e.material.opacity = 0.3;
            e.material.color = new THREE.Color('rgb( 0 , 0 , 225 )');
        }
    })
}
// 清除模型颜色
const cleanColor = () => {
    // 恢复之前被选中模型的材质
    if (objArr.length > 0 && objM.length > 0) {
        objArr.forEach((ele, index) => {
            console.log(objM[index]);
            ele.material = objM[index]
        })
        objArr = [];
        objM = [];
    }
    scene.traverse(e => {
        objArr.push(e);
        objM.push(e.material);
    })
}
// 预警
const warn = () => {
    ['T7'].forEach(item => {
        warnSets.push(scene.getObjectByName(item));
    })

    warnSets[0].traverse(e => {
        e.material = new THREE.MeshBasicMaterial({
            transparent: true,
            opacity: 0.9,
            color: new THREE.Color('rgb( 237,33,2 )')
        });
    })
    yjf();

    // animateCamera(warnSets[0]);
}

const animateCamera = (one) => {
    const lookO = one.getWorldPosition(new THREE.Vector3())
    gsap.to(controls.target, {
        x: lookO.x,
        y: lookO.y + 1.2,
        z: lookO.z,
        duration: 4,
        ease: "power1.inOut",
        onComplete: () => { },
    });
}

const boxLight = (selectedObject) => {
    if (selectedObject) {
        selectedObjects[0] = selectedObject;
        if (selectBoxByClick) {
            scene.remove(selectBoxByClick);
        }
        selectBoxByClick = new THREE.BoxHelper(selectedObjects[0], '#00ffff');
        scene.add(selectBoxByClick);
        centerSelectedGroup(selectedObject);
    }
}
// 居中显示选中
const centerSelectedGroup = (obj) => {
    let tween = new TWEEN.Tween(controls.target).to(obj.position, 1000).easing(TWEEN.Easing.Quadratic.Out);
    controls.enabled = false;
    tween.onComplete(function () {
        controls.enabled = true;
    });
    tween.start();
}

// 返回初始值
const toHomeView = () => {
    // 清除选中框
    if (selectBoxByClick) {
        scene.remove(selectBoxByClick);
    }
    // 清除标签
    removeLabel();
    isAddLabel.value = true;
    // 清除精灵图
    controls.reset();
    // 恢复初始颜色
    cleanColor();
    // 隐藏图例
    isShowWall.value = false;
}
// 拉近距离
const nearCamera = (floor) => {
    controls.reset();

    gsap.to(camera.position, {
        x: floor.position.x,
        y: floor.position.y,
        z: floor.position.z,
        duration: 2,
        ease: "power1.inOut",
        onComplete: () => {
        },
    });

}
//标签
const setLabel = () => {
    if (isAddLabel.value) {
        let obj = scene.getObjectByName('T11');
        addLabel(obj, 'title');
    } else {
        removeLabel();
    }
    isAddLabel.value = !isAddLabel.value;
}
// 添加标签
const addLabel = (obj, t) => {
    removeLabel();
    centerSelectedGroup(obj);
    pointLabel = createLableObj(obj.name, t);
    obj.add(pointLabel);
    labelRenderer.setSize(window.innerWidth, window.innerHeight);
    labelRenderer.domElement.style.position = "absolute";
    labelRenderer.domElement.style.top = 0;
    labelRenderer.domElement.style.pointerEvents = 'none';// 必须加上
    document.body.appendChild(labelRenderer.domElement);
    // 将呈现器的输出添加到HTML元素
    document.getElementById("dom").appendChild(renderer.domElement);
};
const createLableObj = (text, t) => {
    let laberDiv = document.createElement("div"); //创建div容器
    // 只显示标签
    if (t === 'title') {
        laberDiv.className = "laber_name";
        laberDiv.innerHTML = `<div class="arrow_outer">
            <div>设备名称：${text}</div>
            <div>状态：启用</div>
            <div>压力：50 Pa</div>
            </div>`
        //只显示详情
    } else if (t === 'details') {
        laberDiv.style.pointerEvents = 'auto';// 必须加
        laberDiv.className = "laber_details";
        laberDiv.innerHTML = `<div class="detail-btn">详情</div>`;
        laberDiv.addEventListener('click', function (event) {
            emit('handleRightClick', selectedObject);
            console.log(labelRenderer.domElement);
        })
        // 巡检逻辑
    } else {
        setTimeout(()=>{
        laberDiv.innerHTML = `<div class="checking"><span class="text">巡检中...</span></div>`;
      },1000)
      setTimeout(()=>{
        laberDiv.className = "laber_state";
        let innerHTML = t ? `<div class="arrow_state">
            <div>设备名称：${text}</div>
            <div>
                巡检结果：巡检通过 
                <img src=${imgs} width="24px"/>
            </div>
            <div>
                巡检时间：2023-12-23
            </div>
        </div>`: `<div class="arrow_state1">
            <div>设备名称：${text}</div>
            <div>
                巡检结果：巡检不通过，已记录异常
                <img src=${imgs} width="24px"/>
            </div>
            <div>
                巡检时间：2023-01-11
            </div>
        </div>`;

        laberDiv.innerHTML = innerHTML;
      },3000)
    }
    let pointLabel = new CSS2DObject(laberDiv);
    return pointLabel;
};
const removeLabel = () => {
    if (pointLabel) {
        pointLabel.visible = false;
    }
    // document.body.removeChild(labelRenderer.domElement);

}

// 设置地板
const setBottom = () => {
    var target = scene.getObjectByName('tanghua_2F');
    centerSelectedGroup(target);
    console.log(target);
    if (isRemoveBottom.value) {
        target.visible = false;
    } else {
        target.visible = true;
    }
    isRemoveBottom.value = !isRemoveBottom.value;
}

// 消防
const xiaof = () => {
    xfobj.forEach((o) => {
        xfadd(o, Math.random() < 0.3);
    })
}
// 预警
const yjf = () => {
    yjobj.forEach((o) => {
        xfadd(o, 'yj');
    })
}
let xfobj = [];
let yjobj = [];
let sprite = null;
// 消防标签
const xfadd = (obj, state) => {
    const texLoader = new THREE.TextureLoader();
    let texture = null;
    if(state == 'yj') {
        texture = texLoader.load("/yj.png");
    } else if (state) {
        texture = texLoader.load("/ygr.png");
    } else {
        texture = texLoader.load("/yg.png");
    }
    const spriteMaterial = new THREE.SpriteMaterial({
        map: texture,
    });
    sprite = new THREE.Sprite(spriteMaterial);
    // 控制精灵大小
    sprite.scale.set(5, 5, 5);
    sprite.position.y = 12; //标签底部箭头和空对象标注点重合  
    obj.add(sprite); //tag会标注在空对象obj对应的位置
}
// 移除消防标签
const removexf = () => {
    console.log(xfobj.length);
    xfobj.forEach((o) => {
        // 倒序
        let obj = o.children[o.children.length-1];
        if(obj && obj.type === 'Sprite') {
            o.remove(o.children[o.children.length-1]);
        }
       
    })
}
// 更换纹理贴图方法
const changeMap = (img) => {
    isShowWall.value = true;
    // 获取墙体
    model.traverse(e => {
        if (['touliao_wall1', 'touliao_wall2', 'touliao_wall3', 'touliao_wall4', 'touliao_wall5', 'touliao_wall6', 'touliao_wall7', 'touliao_wall8'].indexOf(e.name) != -1) {
            console.log(e)
            e.material = new THREE.MeshBasicMaterial({
                transparent: true,
                opacity: 0.5,
                color: new THREE.Color('rgb( 88,211,247)')
            });
        } else if (['yuanliao_wall1', 'yuanliao_wall2', 'yuanliao_wall3', 'yuanliao_wall4', 'yuanliao_wall5', 'yuanliao_wall6', 'yuanliao_wall7', 'yuanliao_wall8', 'yuanliao_wall9','yuanliao_wall10'].indexOf(e.name) != -1) {
            e.material = new THREE.MeshBasicMaterial({
                transparent: true,
                opacity: 0.5,
                color: new THREE.Color('rgb( 0,128,255)')
            });
        } else if (['tanghua_wall1', 'tanghua_wall2','tanghua_wall3', 'tanghua_wall4','tanghua_wall5', 'tanghua_wall6','tanghua_wall7', 'tanghua_wall8'].indexOf(e.name) != -1) {
            e.material = new THREE.MeshBasicMaterial({
                transparent: true,
                opacity: 0.5,
                color: new THREE.Color('rgb(247,254,46)')
            });
        } else if (['tanghua_wall9', 'tanghua_wall10','tanghua_wall11'].indexOf(e.name) != -1) {
            e.material = new THREE.MeshBasicMaterial({
                transparent: true,
                opacity: 0.5,
                color: new THREE.Color('rgb(253,45,45)')
            });
        }
    })
}
// 巡检
const check = () => {
    let yn = 8, duration = 0;
    if (checkindex < checkArr.length ) {  
         // 1，提前把下一个目标找到，转动镜头
        let nextObj;// 下一个目标
        if (checkindex == checkArr.length ) {
            nextObj = checkArr[0].getWorldPosition(new THREE.Vector3()) 
        }
        if(checkindex < checkArr.length) { 
            nextObj = checkArr[checkindex].getWorldPosition(new THREE.Vector3())
        }
        if (checkindex === 0) {
            duration = 0
        } else {
            duration = 10
        }
         // 2，转动镜头
        gsap.to(controls.target, {
            x: nextObj.x,
            y: nextObj.y + 2,
            z: nextObj.z,
            duration: duration,
            ease: "power1.inOut",
            onComplete: () => {
                // 3，移动摄像机
                gsap.to(camera.position, {
                    x: nextObj.x-0.5,
                    y: nextObj.y + yn,
                    z: nextObj.z,
                    duration: 10,
                    ease: 'power1.inOut',
                    onComplete: () => { 
                        // 显示标签，已经检查通过
                        addLabel(checkArr[checkindex], checkArr[checkindex].isPass);
                        setTimeout(() => {
                        if (checkindex == checkArr.length) { // 巡检结束
                            checkComplete();
                        } else {
                            check()
                            
                        }
                        }, 4000)
                        checkindex++;
                    }
                });
            },
        });
    }
}
// 巡检结束
const checkComplete = () => {
    toHomeView();
    bimStore().setCheckArr(checkArr);
    emit('checkComplete', checkArr);
    return;
}

</script>
<style lang='scss'>
#gltf {
    height: 100%;
    width: 100%;
}

.btnGroup {
    width: 180px;
    position: absolute;
    left: 260px;
    top: 10px;
    z-index: 999;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    color: #ffff;

    >div {
        cursor: pointer;
        // background: #0549a7;
        border: 1px solid #3cbfdf;
        background: rgba(0, 0, 0, .8);
        width: 110px;
        height: 40px;
        border-radius: 5px;
        line-height: 40px;
        text-align: center;
        margin-top: 10px;
    }
}

.laber_name {
    width: 120px;
    height: 90px;
    padding: 5px 10px;
    white-space: nowrap;
    background-color: #ffffffb3;
    border-radius: 12px;
    font-size: 12px;
    display: flex;
    flex-direction: column;

    span {
        line-height: 24px;
    }
}

.laber_details {
    width: 100px;
    height: 50px;
    border-radius: 5px;
    cursor: pointer;
    background-color: #00174b;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 999;
}

.arrow_state {
    display: inline-block;
    // width: 200px;
    // height: 100px;
    padding: 10px;
    background: #0dbc79;
    color: #fff;
    padding: 15px;
    border-radius: 5px;

    >div {
        line-height: 32px;
    }
}

.arrow_state1 {
    display: inline-block;
    padding: 10px;
    background: #e03528;
    color: #fff;
    padding: 15px;
    border-radius: 5px;

    >div {
        line-height: 32px;
    }
}

.wall_tooltips {
    position: absolute;
    top: 20px;
    left: 400px;
    z-index: 999;
    display: flex;
    color: #fff;
    width: 600px;
    justify-content: space-around;
    align-items: center;

    span {
        display: inline-block;
        width: 16px;
        height: 8px;
        margin-right: 5px;

        &.qing {
            background: #3cbfdf;
        }

        &.blue {
            background: #2c68f3;
        }

        &.yellow {
            background: #dff04e;
        }

        &.red {
            background: red;
        }
    }
}
.arrow_outer {
    width: 100px;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    >div {
        line-height: 24px;
    }
}
.arrow_state {
  display: inline-block;
  width: 200px; 
  background: #2dfa82c4;
  color: #fff;
  padding: 15px;
  border-radius: 5px;
  >div {
        line-height: 32px;
    }
}
.arrow_state1 {
    display: inline-block;
    background: #e03528;
    color: #fff;
    padding: 15px;
    border-radius: 5px;

    >div {
        line-height: 32px;
    }
}
@keyframes textAnimation {
    0% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.2);
    }
    100% {
        transform: scale(1);
    }
}
.checking {
  display: inline-block;
  width: 100px; 
  height: 100px; 
  background: rgb(255, 255, 255);
  color: #141313;
  padding: 15px;
  text-align: center;
  line-height: 100px;
  border-radius: 5px;
  border-radius: 50%;
  .text{
    display: inline-block;
    animation: textAnimation 2s infinite;
  }
}

</style>