<template>
	<div class="three">
		<div class="parameter">
			<label>
				<span>X:</span>
				<a-slider class="system_silder"
					v-model:value="repeat.x"
					:tooltipVisible="false"
					@change="changeRepeat"
					:max="2"
					:step="0.001"
					:min="0.002"
				>
				</a-slider>
			</label>
			<label>
				<span>Y:</span>
				<a-slider class="system_silder"
					v-model:value="repeat.y"
					:tooltipVisible="false"
					@change="changeRepeat"
					:max="2"
					:step="0.01"
				>
				</a-slider>
			</label>
		</div>
		<div class="model" ref="threeDom">

		</div>
		<div class="load" v-show="load.state">
			<i class="fi fi-rr-cubes"></i>
			<div class="text">Load...</div>
			<div class="loadBox">
				<div class="schedule" :style="{width:load.progress+'%'}"></div>
			</div>
		</div>
	</div>
</template>
<script lang="ts">
import { defineComponent,computed,shallowRef,provide,nextTick,onMounted,toRefs, reactive, onBeforeUnmount} from 'vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { Https } from "@/tool/https";
import { useStore } from "vuex";
import { useI18n } from 'vue-i18n'

// @ts-ignore
import * as THREE from 'three';
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
import gsap from 'gsap';
import { env } from 'echarts';

export default defineComponent({
	components:{
	},
	props:{
	},
	emits:[],
	setup(props,{emit}) {
		const store = useStore();
		const data = reactive({
			scene:shallowRef() as any,//场景
			group:shallowRef() as any,//组
			camera:shallowRef() as any,//相机
			renderer:shallowRef() as any,//渲染器
			pointLight:shallowRef() as any,//光
			controls:shallowRef() as any,//监听鼠标、键盘事件
			textureLoader:shallowRef() as any,//材质
			load:{
				state:false,
				progress:0 as any,
			},
			repeat:{
				x:1,
				y:1,
			},
			animationId:null as any,
		})
		const dataDom = reactive({
			threeDom:null as any,
		})
		const dataTime = reactive({
			updataRepeat:null as any
		})
		const init = ()=>{
			data.scene = new THREE.Scene();
			data.group = new THREE.Group()
			data.scene.add(data.group)

			//创建相机对象
			// this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
			data.camera = new THREE.PerspectiveCamera(45, dataDom.threeDom.offsetWidth / dataDom.threeDom.offsetHeight, 0.1, 10000);
			data.camera.position.set(0, 90, 6); //设置相机位置
			data.camera.lookAt(data.scene.position); //设置相机方向(指向的场景对象)

				/**
			 * 创建渲染器对象
			 */
			let width = dataDom.threeDom.offsetWidth; //窗口宽度
			let height = dataDom.threeDom.offsetHeight; //窗口高度
			data.renderer = new THREE.WebGLRenderer({
				antialias: true,
				logarithmicDepthBuffer: true,//深度缓存 防止模型闪烁重影
			});

			// data.renderer.outpuEncoding = THREE?.RGBEEncoding//设置输出颜色编码格式

			data.renderer.toneMapping = THREE.ACESFilmicToneMapping;//设置色调
			data.renderer.toneMappingExposure = 1.3;

			data.renderer.shadowMap.enabled = true;
			data.renderer.setPixelRatio(window.devicePixelRatio);
			data.renderer.setSize(width, height); //设置渲染区域尺寸
			data.renderer.setClearColor(0xffffff, 1); //设置背景颜色 
			dataDom.threeDom.innerHTML = '';
			dataDom.threeDom.appendChild(data.renderer.domElement);
			// 设置渲染器大小
			//环境光
			let ambient = new THREE.AmbientLight(0xffffff,.8);
			data.scene.add(ambient);
			data.controls = new OrbitControls(data.camera,data.renderer.domElement)//监听鼠标、键盘事件;
			// data.controls.minDistance = 500; // 设置相机与焦点的最小距离
			// data.controls.maxDistance = 4000; // 设置相机与焦点的最大距离
			data.controls.mouseButtons = {
				// LEFT:THREE.MOUSE.PAN, // 左键 拖动(默认旋转：ROTATE)
				LEFT:THREE.MOUSE.ROTATE, // 左键 拖动(默认旋转：ROTATE)
				MIDDLE:THREE.MOUSE.DOLLY, // 滑轮 缩放
				RIGHT:THREE.MOUSE.PAN // 右键 旋转（默认拖动：PAN）
				// RIGHT:THREE.MOUSE.ROTAafTE // 右键 旋转（默认拖动：PAN）
			}
			/**
			 * 光源设置
			 */
			//点光源
			/**
			 * AmbientLight	环境光
				PointLight	点光源
				DirectionalLight	平行光，比如太阳光
				SpotLight	聚光源
			 */
			data.pointLight = new THREE.DirectionalLight(0xffffff,.5);
			data.pointLight.intensity = 1.2
			data.pointLight.castShadow = true//开启阴影
			data.pointLight.shadow.mapSize = new THREE.Vector2(width, height)
			data.scene.add(data.pointLight); //点光源添加到场景中
			// data.pointLight.position.set(400, 200, 300); //点光源位置
			data.pointLight.position.y = 400;
			data.pointLight.position.z = 200;
			data.pointLight.position.x = 200;
			let floorGeometry = new THREE.PlaneGeometry(5000, 3000)//地板大小
			let floorMaterial = new THREE.MeshPhongMaterial({ color: "#7e7ab0", })
			let floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
			floorMesh.rotation.x = -0.5 * Math.PI;
			floorMesh.receiveShadow = true;
			floorMesh.position.y = -0.001;
			// data.scene.add(floorMesh);
			const textureLoader = new THREE.TextureLoader();
			// const texture = textureLoader.load('/3dModel/sketch-thick.jpg');
			data.scene.background = new THREE.Color("#fff");
			// data.scene.background = texture;

			let openModel = (event:any)=>{
				let mouse=new THREE.Vector2();
				let raycaster=new THREE.Raycaster();
				mouse.x=(event.clientX/window.innerWidth)*2-1;
				mouse.y=-(event.clientY/window.innerHeight)*2+1;
				raycaster.setFromCamera(mouse, data.camera);
				let intersects = raycaster.intersectObjects(data.scene.children);
				return intersects
			}

			dataDom.threeDom.ondblclick = (event:any)=>{
				let intersects = openModel(event);
				if(!intersects || intersects.length<=0) return
				const bbox = new THREE.Box3().setFromObject(intersects[0].object);
				const size = new THREE.Vector3();
				let target2 = bbox.getCenter(size);//获取选中包围起来后的中心坐标
				animateCamera(data.camera.position,intersects[0].point,data.controls.target,target2)
			}
			let isTweening = false;
			function animateCamera(current1:any, target1:any, current2:any, target2:any){
				if (isTweening) return
				isTweening = true
				let options = {
					x1: current1.x, // 相机当前位置x
					y1: current1.y, // 相机当前位置y
					z1: current1.z, // 相机当前位置z
					x2: current2.x, // 控制当前的中心点x
					y2: current2.y, // 控制当前的中心点y
					// z2: current2.z  // 控制当前的中心点z
				}
				gsap.to(options,{
					x1: 0, // 新的相机位置x
					y1: target2.y, // 新的相机位置y
					z1: 2500, // 新的相机位置z
					x2: 0, // 新的控制中心点位置x
					y2: target2.y, // 新的控制中心点位置x
					duration:1,
					ease:'linear',
					onUpdate:()=>{
						data.camera.position.x = options.x1;
						data.camera.position.y = options.y1;
						data.camera.position.z = options.z1;
						data.controls.target.x = options.x2;
						data.controls.target.y = options.y2;
						// data.controls.target.z = object.z2;
						data.controls.update();
					},
					onComplete:()=>{
						isTweening = false
					}
					// z2: target2.z  // 新的控制中心点位置x
				})
			}
			// let setHighlight = (obj:any)=>{
			// 	outlinePass.selectedObjects = obj;
			// }


			data.controls.enableDamping = true;
			let animate =  ()=>{
				data.animationId = requestAnimationFrame(animate);
				// data.renderer.render(data.scene, data.camera);
				// model.rotation.x += 0.01; //旋转物体
				var vector = data.camera.position.clone()
				data.controls.update();
				data.renderer.render(data.scene, data.camera);
				// point.position.set(vector.x,vector.y,vector.z);
				// group.rotation.y += 0.01; 

				// composer.render();
			};
			animate();
		}
		
		const setModel = async (url:any)=>{
			clearModel()
			await addModel(url)
			// addMaterial()
		}
		const addMaterial =async (item:any)=>{
			//添加图片材质
			let url = item.url || item.url || item.imgUrl
			data.load.state = true
			let textureLoader = new THREE.TextureLoader()
			await textureLoader.load(url, // 图片放在public/textures目录下
				(texture:any) => {
				data.textureLoader = texture
				// 3. 配置纹理参数
				texture.wrapS = THREE.RepeatWrapping;
				texture.wrapT = THREE.RepeatWrapping;
				
				// texture.repeat.set(1, 1); // 纹理重复次数
				texture.anisotropy = 32;  // 提高纹理清晰度
				data.group?.traverse((child:any) => {
					if (child.isMesh) {
						// 5. 创建新材质（根据需求选择材质类型）
						const textureWidth = texture.image.width;
						const textureHeight = texture.image.height;
						const box = new THREE.Box3().setFromObject(child);
						const modelWidth = box.getSize(new THREE.Vector3()).x;
						const modelHeight = box.getSize(new THREE.Vector3()).y;
						data.repeat.x = 2 - modelWidth / textureWidth;
						data.repeat.y = 2 - modelHeight / textureHeight;
						let patternMaking3D = store.state.HomeStoreModule.patternMaking3D
						if(patternMaking3D.x)data.repeat.x = patternMaking3D.x
						if(patternMaking3D.y)data.repeat.y = patternMaking3D.y
						
						// texture.repeat.set(1, 1); // 纹理重复次数
						texture.repeat.set(2 - data.repeat.x, 2 - data.repeat.y); // 纹理重复次数
						
						const newMaterial = new THREE.MeshStandardMaterial({
							map: texture,        // 基础颜色贴图
							roughness: 0.7,      // 表面粗糙度 (0-1)
							metalness: .2,      // 金属质感 (0-1)
							side: THREE.DoubleSide // 双面渲染
						});
						// 6. 替换原有材质
						child.material = newMaterial;
						// 7. 如果需要单独控制某些子模型的UV
						if (child.geometry.attributes.uv) {
							// 可以在这里修改UV坐标
							const uvs = child.geometry.attributes.uv.array;
							// ...UV操作逻辑...
						}
					}
					data.load.state = false
				},(xhr:any) => { // 加载进度回调
					const percent = xhr.total == 0?100:(xhr.loaded / xhr.total * 100).toFixed(2);
					data.load.progress = percent
					// updateProgressBar(Number(percent));
				},(error:any) => {
					console.error('纹理加载失败:', error);
					data.load.state = false
				});
				let value = {
					collectionElementId:item.id,
					x:data.repeat.x,
					y:data.repeat.y,
				}
				store.commit('setPatternMaking3D',value)
				
			})
		}
		const addModel = async (url:any)=>{
			await new Promise((resolve, reject) => {
				var fbxLoader = new GLTFLoader();
				let drac = new DRACOLoader()
				drac.setDecoderPath('/draco/')
				fbxLoader.setDRACOLoader(drac)
				// fbxLoader.load('/3dModel/222/1111.glb',
				fbxLoader.load(url,
				
				(obj:any) => {
					let scene = obj.scene;
					var box = new THREE.Box3().setFromObject(scene);
					var center = box.getCenter(new THREE.Vector3());
					data.controls.target.copy(center);
					// data.controls.autoRotate  = true
					data.camera.position.y = center.y;
					data.camera.position.z = 1000;
					data.pointLight.position.y = 250;
					data.pointLight.position.z = 1250;
					data.group.add(scene);
					resolve('')
				},(xhr:any) => { // 加载进度回调
					const percent = xhr.total == 0?100:(xhr.loaded / xhr.total * 100).toFixed(2);
					data.load.progress = percent
					// updateProgressBar(Number(percent));
				},(error:any) => { // 加载失败回调
					console.error('模型加载失败:', error);
					reject('')
				})	
			})
		}
		const clearModel = ()=>{
			const oldGroup:any = data.group;
			data.group = new THREE.Group();
			data.scene.add(data.group);
			data.scene.remove(oldGroup);
		}
		// const loadThree = ()=>{

		// 	init()
		// }
		const getModelUrl = (value:any)=>{
			return new Promise((resolve, reject) => {

				// Https.axiosGet(Https.httpUrls.getThreeDGlb,{params:{threeDSimpleId:value.id},env:{binary:true}}).then((rv)=>{
				// 	//二进制流转本地路径
					
				// 	console.log(rv)
				// 	resolve(rv)
				// }).catch(()=>{
				// 	reject('')
				// })
				// //fetch get请求携带token

				
				// fetch("https://develop.api.aida.com.hk/api/project/getThreeDGlb?threeDSimpleId=1", {
				// 	headers:{
				// 		authorization:'Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiI4OCIsInN1YiI6IntcImNvdW50cnlcIjpcIkNoaW5hXCIsXCJpZFwiOjg4LFwibGFuZ3VhZ2VcIjpcIkVOR0xJU0hcIixcInVzZXJuYW1lXCI6XCJzaGJcIn0iLCJpYXQiOjE3NDMzNDkwNjQsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE3NTE5ODkwNjR9.gmL0JufYy9wd23qCY-ibwhgpXZ2X68WAiHSeC99I4x7cipWyxLaQmuIBk2SJSdWBm0tTN2Mx-etXO9a7MtQmpw',
				// 	}
				// }).then(res => {
	 			// 	return res.blob();
				// }).then((res) => {
	 			// 	var url = URL.createObjectURL(res);
	 			// 	console.log(url, res)
				// 	resolve(url)
				// }).catch(err => {
	 			// 	console.log(err);
				// })
				resolve(value.threeDSimpleUrl)
			})
		}
		const openSetData = async (value:any)=>{
			if(!data.scene){
				init()
			}
			data.load.state = true
			const modeUrl = await getModelUrl(value)
			await setModel(modeUrl)
			let patternMaking3D = store.state.HomeStoreModule.patternMaking3D
			if(patternMaking3D.printMinioUrl)await addMaterial({url:patternMaking3D.printMinioUrl})
			data.load.state = false
		}
		const changeRepeat = (e:any)=>{
			clearTimeout(dataTime.updataRepeat)
			dataTime.updataRepeat = setTimeout(()=>{
				data.textureLoader.repeat.set(2 - data.repeat.x,2 - data.repeat.y); // 纹理重复次数
				let value = {
					x:data.repeat.x,
					y:data.repeat.y,
				}
				store.commit('setPatternMaking3D',value)
			},1000)
		}
		onMounted(()=>{
		})
		onBeforeUnmount(()=>{
			if(data.animationId){
				cancelAnimationFrame(data.animationId);
				data.animationId = null;
			}
			data.scene.traverse((child:any) => {
				if (child.material) {
					child.material.dispose();
				}
				if (child.geometry) {
					child.geometry.dispose();
				}
				child = null;
			});
			data.renderer.forceContextLoss();
			data.renderer.dispose();
			data.scene.clear();
			data.scene = null;
			data.camera = null;
			data.controls = null;
			data.renderer.domElement = null;
			data.renderer = null;
		})
		return{
			...toRefs(dataDom),
			...toRefs(data),
			openSetData,
			addMaterial,
			changeRepeat,
		}
	},
	provide() {
		return {
		}
	},
})
</script>
<style lang="less" scoped>
	.three{
		width: 100%;
		height: 100%;
		position: relative;
		flex: 1;
		overflow: hidden;
		> .parameter{
			display: flex;
			> label{
				display: flex;
				align-items: center;
				flex: 1;
				padding-right: 2rem;
				// &:not(:last-child){
				// 	margin-right: 3rem;
				// }
				> span{
					font-size: 2rem;
					margin-right: 1rem;
				}
			}
		}
		> .model{
			width: 100%;
			height: 100%;
		}
		> .load{
			position: absolute;
			width: 100%;
			height: 100%;
			top: 0;
			left: 0;
			background: rgba(0, 0, 0, .2);
			display: flex;
			align-items: center;
			justify-content: center;
			flex-direction: column;
			color: #fff;
			> i{
				font-size: 3rem;
			}
			> .loadBox{
				width: 15rem;
				height: 1rem;
				border-radius: 1rem;
				background: #fff;
				overflow: hidden;
				> .schedule{
					height: 100%;
					background: greenyellow;
				}
			}
		}
	}
</style>