<template>
    <el-dialog class="pointModal-wrap" v-model="show" @close="handleClose" @opened="onDialogOpened">
        <div class="pcd-container">
            <div ref="pcdContainer" style="width: 100%; height: 100%" />
            <span class="button-first" @click="zoomIn"></span>
            <span class="button-second" @click="zoomOut"></span>
            <span class="button-thrid" :disabled="!pcdLoaded" @click="returnToCenter"></span>
            <!-- 新增进度条 -->
            <div v-if="loading" class="progress-bar">
                <div class="progress" :style="{ width: progress + '%' }"></div>
            </div>
        </div>
    </el-dialog>
</template>

<script lang="ts" setup>
import { ref, computed, defineProps, defineEmits, withDefaults } from 'vue';
import * as THREE from "three";
import { PCDLoader } from "three/examples/jsm/loaders/PCDLoader.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

interface Props {
    /** 弹窗显隐 */
    value: boolean;
    info: Record<string, any>;
}
interface Emits {
    (e: "update:value", val: boolean): void;
}
const props = withDefaults(defineProps<Props>(), {
    value: false,
    info: {}
});

const emit = defineEmits<Emits>();

// 定义全局变量
let scene;
let renderer;

// 新增加载状态和进度
const loading = ref(false);
const progress = ref(0);
// 处理对话框关闭事件
const handleClose = () => {
    if (pcdContainer.value) {
        // 移除渲染器的 DOM 元素
        while (pcdContainer.value.firstChild) {
            pcdContainer.value.removeChild(pcdContainer.value.firstChild);
        }
        // 释放场景资源
        if (scene) {
            scene.traverse((object) => {
                if (object instanceof THREE.Mesh) {
                    object.geometry.dispose();
                    if (object.material instanceof THREE.Material) {
                        object.material.dispose();
                    } else {
                        object.material.forEach((material) => material.dispose());
                    }
                }
            });
        }
        // 销毁控制器
        if (controls) {
            controls.dispose();
        }
        // 移除窗口大小变化监听器
        // window.removeEventListener('resize', onWindowResize);
        // 重置变量
        scene = null;
        camera = null;
        renderer = null;
        controls = null;
        pcdLoaded.value = false;
    }
    emit("update:value", false);
};

const show = computed({
    get() {
        return props.value;
    },
    set(val: boolean) {
        emit("update:value", val);
    }
});
const pcdContainer = ref(null);
let initialCameraPosition;
let initialCameraRotation;
let initialControlsTarget;
let initialCameraZoom;
let controls;
let camera;
const pcdLoaded = ref(false);

const onDialogOpened = () => {
    // 检查点云数据URL是否存在
    if (!props.info.point_cloud_url) {
        return;
    }
    if (pcdContainer.value) {
        scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera(
            75,
            pcdContainer.value.clientWidth / pcdContainer.value.clientHeight,
            0.1,
            1000
        );
        renderer = new THREE.WebGLRenderer();
        renderer.setSize(pcdContainer.value.clientWidth, pcdContainer.value.clientHeight);
        pcdContainer.value.appendChild(renderer.domElement);

        // 创建 OrbitControls 实例
        controls = new OrbitControls(camera, renderer.domElement);

        const loader = new PCDLoader();
        // 开始加载，设置加载状态为 true
        loading.value = true;
        loader.load(
            props.info.point_cloud_url,
            function (pointCloud) {
                // 加载完成，设置加载状态为 false
                loading.value = false;
                // 调整点云的位置到原点
                pointCloud.position.set(0, 100, 0);

                // 获取点云的几何体
                const geometry = pointCloud.geometry;

                // 创建颜色数组
                const colors = [];
                const positions = geometry.attributes.position.array;
                const numPoints = positions.length / 3;

                // 定义起始颜色和结束颜色
                const startColor = new THREE.Color(0x0000ff); // 蓝色
                const midColor1 = new THREE.Color(0x00ff00);  // 绿色
                const midColor2 = new THREE.Color(0xffff00);  // 黄色
                const endColor = new THREE.Color(0xff0000);   // 红色

                // 计算点云在 z 轴上的最小值和最大值
                let minZ = Infinity;
                let maxZ = -Infinity;
                for (let i = 0; i < numPoints; i++) {
                    const z = positions[i * 3 + 2];
                    if (z < minZ) minZ = z;
                    if (z > maxZ) maxZ = z;
                }

                for (let i = 0; i < numPoints; i++) {
                    const z = positions[i * 3 + 2];
                    // 计算颜色渐变因子
                    const factor = (z - minZ) / (maxZ - minZ);

                    let color;
                    if (factor < 0.33) {
                        // 从蓝到绿的渐变
                        const subFactor = factor / 0.33;
                        color = startColor.clone().lerp(midColor1, subFactor);
                    } else if (factor < 0.66) {
                        // 从绿到黄的渐变
                        const subFactor = (factor - 0.33) / 0.33;
                        color = midColor1.clone().lerp(midColor2, subFactor);
                    } else {
                        // 从黄到红的渐变
                        const subFactor = (factor - 0.66) / 0.34;
                        color = midColor2.clone().lerp(endColor, subFactor);
                    }

                    // 将颜色添加到颜色数组中
                    colors.push(color.r, color.g, color.b);
                }
                // 创建颜色属性
                const colorAttribute = new THREE.Float32BufferAttribute(colors, 3);
                geometry.setAttribute('color', colorAttribute);

                // 创建一个新的材质并启用顶点颜色
                const material = new THREE.PointsMaterial({ vertexColors: true });
                pointCloud.material = material;

                // 调整点云的缩放比例
                pointCloud.scale.set(1, 1, 1);
                // 计算点云的边界框
                const box = new THREE.Box3().setFromObject(pointCloud);
                const size = box.getSize(new THREE.Vector3());
                const maxSize = Math.max(size.x, size.y, size.z);
                const fov = camera.fov * (Math.PI / -180);
                const distance = maxSize / 2 / Math.tan(fov / 3);

                // 调整相机位置为正视图
                camera.position.set(0, distance, 0);
                camera.rotation.set(0, 0, 0);
                camera.lookAt(0, 0, 0);

                // 调整点云的旋转角度，绕 y 轴旋转 45 度（Math.PI / 4 弧度）
                pointCloud.rotation.set(0, 0, 0);

                // 保存初始相机位置、旋转、缩放和控制器目标位置
                initialCameraPosition = camera.position.clone();
                initialCameraRotation = camera.rotation.clone();
                initialCameraZoom = camera.zoom;
                initialControlsTarget = controls.target.clone();

                scene.add(pointCloud);
                pcdLoaded.value = true;

                // // 监听窗口大小变化
                // const onWindowResize = () => {
                //     camera.aspect = pcdContainer.value.clientWidth / pcdContainer.value.clientHeight;
                //     camera.updateProjectionMatrix();
                //     renderer.setSize(pcdContainer.value.clientWidth, pcdContainer.value.clientHeight);
                // };
                // window.addEventListener('resize', onWindowResize);
            },
            function (xhr) {
                // 更新加载进度
                progress.value = (xhr.loaded / xhr.total) * 100;
            },
            function (error) {
                // 加载失败，设置加载状态为 false
                loading.value = false;
                console.error('点云文件加载失败:', error);
            }
        );

        function animate() {
            requestAnimationFrame(animate);
            // 更新控制器
            if (controls) {
                controls.update();
            }
            if (renderer && scene && camera) {
                renderer.render(scene, camera);
            }
        }

        animate();
    } else {
        console.error('pcdContainer is null');
    }
};

const zoomIn = () => {
    if (camera) {
        camera.position.multiplyScalar(0.9);
        camera.updateProjectionMatrix();
        if (controls) {
            controls.update();
        }
    }
};

const zoomOut = () => {
    if (camera) {
        camera.position.multiplyScalar(1.1);
        camera.updateProjectionMatrix();
        if (controls) {
            controls.update();
        }
    }
};

const returnToCenter = () => {
    if (initialCameraPosition && initialCameraRotation && initialControlsTarget && camera && controls) {
        // 重置控制器的临时状态
        controls.reset();

        // 恢复相机位置
        camera.position.copy(initialCameraPosition);
        // 恢复相机旋转角度
        camera.rotation.copy(initialCameraRotation);
        // 恢复相机缩放
        camera.zoom = initialCameraZoom;

        // 多次更新投影矩阵和控制器
        for (let i = 0; i < 3; i++) {
            camera.updateProjectionMatrix();
            if (controls) {
                controls.update();
            }
        }

        // 恢复控制器目标位置
        controls.target.copy(initialControlsTarget);

        // 重置控制器的所有状态
        controls.target0.copy(initialControlsTarget);
        controls.position0.copy(initialCameraPosition);
        controls.zoom0 = initialCameraZoom;

        // 延迟更新控制器
        setTimeout(() => {
            if (controls) {
                controls.update();
            }
        }, 100);
    } else {
        console.error("Initial state is not defined");
    }
};
</script>

<style lang="scss">
.pointModal-wrap.el-dialog {
    box-sizing: border-box;
    width: 1600px;
    height: 810px;
    background-image: url("@/assets/common/pointModalBg.png");
    background-size: 100% 100%;
    background-position: center;
    background-repeat: no-repeat;
    background-color: #000;
    .pcd-container {
        position: relative;
        width: 1560px;
        height: 760px;
        .button-first,
        .button-second,
        .button-thrid {
            position: absolute;
            width: 24px;
            height: 24px;
            cursor: pointer;
            background-image: url("@/assets/common/amplify_btn.png");
            background-size: 100% 100%;
            background-position: center;
            background-repeat: no-repeat;
            bottom: 112px;
            right: 32px;
            /* 添加过渡效果 */
            transition: all 0.3s ease;
        }
        .button-second {
            bottom: 72px;
            right: 32px;
            background-image: url("@/assets/common/reduce_btn.png");
            background-size: 100% 100%;
            background-position: center;
            background-repeat: no-repeat;
            /* 添加过渡效果 */
            transition: all 0.3s ease;
        }
        .button-thrid {
            bottom: 33px;
            right: 32px;
            background-image: url("@/assets/common/reset_btn.png");
            background-size: 100% 100%;
            background-position: center;
            background-repeat: no-repeat;
            /* 添加过渡效果 */
            transition: all 0.3s ease;
        }
        .progress-bar {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            width: 80%;
            height: 20px;
            background-color: #ccc;
            border-radius: 10px;
            overflow: hidden;
        }
        .progress {
            height: 100%;
            background-color: #007bff;
            transition: width 0.3s ease;
        }
    }
}
</style>