<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';


// 添加字体加载器
const fontLoader = new FontLoader();
const container = ref<HTMLDivElement | null>(null);
const width = 600;
const height = 400;

// 场景变量
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
let controls: any = null;
let animateId: any = null;

// 初始化场景
const initScene = () => {
  // 设置渲染器
  renderer.setSize(width, height);
  renderer.setClearColor(0x87ceeb); // 天空蓝色背景
  renderer.shadowMap.enabled = true;
  container.value && container.value.appendChild(renderer.domElement);

  // 设置相机位置
  camera.position.set(0, 10, 100);

  // 添加轨道控制器
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;

  // 添加光源
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
  scene.add(ambientLight);

  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  directionalLight.position.set(10, 20, 10);
  directionalLight.castShadow = true;
  directionalLight.shadow.mapSize.width = 2048;
  directionalLight.shadow.mapSize.height = 2048;
  scene.add(directionalLight);

  // 添加地面
  const groundGeometry = new THREE.PlaneGeometry(100, 100);
  const groundMaterial = new THREE.MeshStandardMaterial({
    color: 0x4CAF50,
    roughness: 0.8,
    metalness: 0.2
  });
  const ground = new THREE.Mesh(groundGeometry, groundMaterial);
  ground.rotation.x = -Math.PI / 2;
  ground.receiveShadow = true;
  scene.add(ground);

  // 添加建筑物
  createBuildings();

  // 添加树木和道路
  createEnvironment();

  // 创建椭圆操场
  createEllipticalPlayground(0, 0.02, 0);
};

// 创建校园建筑物
const createBuildings = async() => {
  // 主教学楼
  const mainBuilding = await createBuilding(15, 8, 10, 0xcccccc, 0, 4, 38,"教学楼");
  scene.add(mainBuilding);
  // 添加左右两侧建筑
  
  const leftBuilding = await createBuilding(10, 5, 8, 0xcccccc, -30, 4, 36);
  scene.add(leftBuilding);
  const rightBuilding = await createBuilding(10, 5, 8, 0xcccccc, 30, 4, 36);
  scene.add(rightBuilding);

  // 右侧三栋建筑
  const rightBuilding1 = await createBuilding(10, 5, 8, 0xcccccc, 30, 4, 16);
  scene.add(rightBuilding1);
  const rightBuilding2 = await createBuilding(10, 5, 8, 0xcccccc, 30, 4, -10);
  scene.add(rightBuilding2);
  const rightBuilding3 = await createBuilding(10, 5, 8, 0xcccccc, 30, 4, -36);  
  scene.add(rightBuilding3);
  // 左侧三栋建筑
  const leftBuilding1 = await createBuilding(10, 5, 8, 0xcccccc, -30, 4, 16);
  scene.add(leftBuilding1);
  const leftBuilding2 = await createBuilding(10, 5, 8, 0xcccccc, -30, 4, -10);
  scene.add(leftBuilding2);
  const leftBuilding3 = await createBuilding(10, 5, 8, 0xcccccc, -30, 4, -36);  
  scene.add(leftBuilding3);
  // 添加窗户细节
  addBuildingDetails();
};

// 创建建筑物通用函数
const createBuilding = async(width: any, height: any, depth: any, color: any, x: any, y: any, z: any,name: any="") => {
  const geometry = new THREE.BoxGeometry(width, height, depth);
  const material = new THREE.MeshStandardMaterial({
    color: color,
    roughness: 0.7
  });
  const building = new THREE.Mesh(geometry, material);
  building.position.set(x, y, z);
  building.castShadow = true;
  building.receiveShadow = true;
  // 添加建筑物名称
  if (name) {
    const text = await create3DText(name, {
      size: 2,
      height: 0.1,
      color: 0xffffff,
      position: { x: x, y: y + height/2 + 0.5, z: z },
      rotation: { x: 0, y: 0, z: 0 }
    });
    scene.add(text);
  }
  return building;
};

// 创建3D文字
type TextOptions = {
  size?: number;
  height?: any;
  color?: number;
  position?: { x: number; y: number; z: number };
  rotation?: { x: number; y: number; z: number };
};

const create3DText = async (message: any, options: TextOptions = {}) => {
  const {
    size = 2,
    height = 0.2,
    color = 0xffffff,
    position = { x: 0, y: 0, z: 0 },
    rotation = { x: 0, y: 0, z: 0 }
  } = options;
  
  // 加载字体
  const font = await new Promise<any>((resolve) => {
    fontLoader.load('/FangSong_Regular.json', (font) => resolve(font));
  });
  
  // 创建文字几何体
  const textGeometry = new TextGeometry(message, {
    font: font,
    size: size,
    depth: height,
    curveSegments: 12,
    bevelEnabled: false
  });
  
  // 居中文字
  textGeometry.computeBoundingBox();
  const textWidth = textGeometry.boundingBox &&textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x;
  if(textWidth){
    textGeometry.translate(-textWidth / 2, 0, 0);
  }
  
  const textMaterial = new THREE.MeshStandardMaterial({ color });
  const textMesh = new THREE.Mesh(textGeometry, textMaterial);
  
  textMesh.position.set(position.x, position.y, position.z);
  textMesh.rotation.set(rotation.x, rotation.y, rotation.z);
  
  return textMesh;
};

// 添加建筑物细节（窗户等）
const addBuildingDetails = () => {
  // 在主教学楼上添加窗户
  for (let i = -6; i <= 6; i += 3) {
    for (let j = 1; j <= 6; j += 2) {
      const window = new THREE.Mesh(
        new THREE.PlaneGeometry(1, 1.5),
        new THREE.MeshStandardMaterial({ color: 0x0000AA })
      );
      window.position.set(i, j, 43.1);
      scene.add(window);
    }
  }
};

// 创建环境（树木、道路等）
const createEnvironment = () => {
  // 添加道路
  const roadGeometry = new THREE.PlaneGeometry(5, 100);
  const roadMaterial = new THREE.MeshStandardMaterial({ color: 0x333333 });

  // 靠近地面左侧边缘的纵向道路
  const roadLeft = new THREE.Mesh(roadGeometry, roadMaterial);
  roadLeft.rotation.x = -Math.PI / 2;
  roadLeft.position.y = 0.01;
  roadLeft.position.x = -47.5;
  roadLeft.position.z = 0;
  scene.add(roadLeft);

  // 靠近地面右侧边缘的纵向道路
  const roadRight = new THREE.Mesh(roadGeometry, roadMaterial);
  roadRight.rotation.x = -Math.PI / 2;
  roadRight.position.y = 0.01;
  roadRight.position.x = 47.5;
  roadRight.position.z = 0;
  scene.add(roadRight);

  // 道路中间白线（右侧）
  const lineGeometry = new THREE.PlaneGeometry(0.2, 95);
  const lineMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });
  const roadLine = new THREE.Mesh(lineGeometry, lineMaterial);
  roadLine.rotation.x = -Math.PI / 2;
  roadLine.position.y = 0.02;
  roadLine.position.x = 47.5;
  roadLine.position.z = 0;
  scene.add(roadLine);
  // 道路中间白线（左侧）
  const roadLine1 = new THREE.Mesh(lineGeometry, lineMaterial);
  roadLine1.rotation.x = -Math.PI / 2;
  roadLine1.position.y = 0.02;
  roadLine1.position.x = -47.5;
  roadLine1.position.z = 0;
  scene.add(roadLine1);

  // 中间白线
  const crossRoadGeometry = new THREE.PlaneGeometry(95, 0.2);
  const crossRoadLine = new THREE.Mesh(
    crossRoadGeometry,
    lineMaterial
  );
  crossRoadLine.rotation.x = -Math.PI / 2;
  crossRoadLine.position.y = 0.02;
  crossRoadLine.position.z = 47.5;
  scene.add(crossRoadLine);
  // 横向道路（前）
  const crossRoad = new THREE.Mesh(
    new THREE.PlaneGeometry(100, 5),
    roadMaterial
  );
  crossRoad.rotation.x = -Math.PI / 2;
  crossRoad.position.y = 0.01;
  crossRoad.position.z = -47.5; // 靠近地面边缘
  scene.add(crossRoad);

  // 
  const crossRoadLine2 = new THREE.Mesh(
    crossRoadGeometry,
    lineMaterial
  );
  crossRoadLine2.rotation.x = -Math.PI / 2;
  crossRoadLine2.position.y = 0.02;
  crossRoadLine2.position.z = -47.5;
  scene.add(crossRoadLine2);
  // 横向道路（后）
  const crossRoad2 = new THREE.Mesh(
    new THREE.PlaneGeometry(100, 5),
    roadMaterial
  );
  crossRoad2.rotation.x = -Math.PI / 2;
  crossRoad2.position.y = 0.01;
  crossRoad2.position.z = 47.5; // 另一侧边缘
  scene.add(crossRoad2);

  // 进门道路(左)
  const entranceRoadGeometry = new THREE.PlaneGeometry(5, 25);
  const entranceRoad = new THREE.Mesh(
    entranceRoadGeometry,
    roadMaterial
  );
  entranceRoad.rotation.x = -Math.PI / 2;
  entranceRoad.position.y = 0.01;
  entranceRoad.position.z = 35; // 靠近地面边缘
  entranceRoad.position.x = -15; // 中间位置
  scene.add(entranceRoad);

  // 左侧中间白线
  const entranceRoadLineGeometry = new THREE.PlaneGeometry(0.2, 20);
  const entranceRoadLine = new THREE.Mesh(
    entranceRoadLineGeometry,
    lineMaterial
  );
  entranceRoadLine.rotation.x = -Math.PI / 2;
  entranceRoadLine.position.y = 0.02;
  entranceRoadLine.position.z = 35; // 靠近地面边缘
  entranceRoadLine.position.x = -15; // 中间位置
  scene.add(entranceRoadLine);

  // 右侧道路
  const entranceRoad1 = new THREE.Mesh(
    entranceRoadGeometry,
    roadMaterial
  );
  entranceRoad1.rotation.x = -Math.PI / 2;
  entranceRoad1.position.y = 0.02;
  entranceRoad1.position.z = 35;
  entranceRoad1.position.x = 15;
  scene.add(entranceRoad1);
  // 右侧白线
  const entranceRoadLine2 = new THREE.Mesh(
    entranceRoadLineGeometry,
    lineMaterial
  );
  entranceRoadLine2.rotation.x = -Math.PI / 2;
  entranceRoadLine2.position.y = 0.02;
  entranceRoadLine2.position.z = 35;
  entranceRoadLine2.position.x = 15;
  scene.add(entranceRoadLine2);

  // 对应进门道路
  const entranceRoad3Geometry = new THREE.PlaneGeometry(25, 5);
  const entranceRoad2 = new THREE.Mesh(entranceRoad3Geometry, roadMaterial);
  entranceRoad2.rotation.x = -Math.PI / 2;
  entranceRoad2.position.y = 0.01;
  entranceRoad2.position.z = 25;
  entranceRoad2.position.x = 0;
  scene.add(entranceRoad2);
  // 添加线
  const entranceRoad3Line = new THREE.PlaneGeometry(30, 0.2);
  const entranceRoadLine3 = new THREE.Mesh(entranceRoad3Line, lineMaterial);
  entranceRoadLine3.rotation.x = -Math.PI / 2;
  entranceRoadLine3.position.y = 0.1;
  entranceRoadLine3.position.z = 25;
  scene.add(entranceRoadLine3);

  // 添加树木
  // for (let i = -40; i <= 40; i += 10) {
  //   for (let j = -40; j <= 40; j += 10) {
  //     // 避免在建筑物和道路上放置树木
  //     if ((i > -12 && i < 12 && j > -12 && j < 12) || 
  //         (i > -25 && i < -15 && j > 10 && j < 20) ||
  //         (i > 20 && i < 30 && (j > 5 && j < 15 || j > -15 && j < -5))) {
  //       continue;
  //     }

  //     if (Math.random() > 0.6) {
  //       createTree(i, 0, j);
  //     }
  //   }
  // }
};

// 创建树木
const createTree = (x: any, y: any, z: any) => {
  // 树干
  const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.5, 2, 8);
  const trunkMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });
  const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
  trunk.position.set(x, y + 1, z);
  trunk.castShadow = true;

  // 树冠
  const leavesGeometry = new THREE.SphereGeometry(2, 8, 8);
  const leavesMaterial = new THREE.MeshStandardMaterial({ color: 0x228B22 });
  const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
  leaves.position.set(x, y + 3, z);
  leaves.castShadow = true;

  scene.add(trunk);
  scene.add(leaves);
};
// 创建椭圆操场
const createEllipticalPlayground = (x:any, y:any, z:any) => {
  // 椭圆跑道参数
  const a = 13; // 长轴半径
  const b = 18; // 短轴半径
  const trackWidth = 3; // 跑道宽度
  const innerA = a - trackWidth; // 内椭圆长轴
  const innerB = b - trackWidth; // 内椭圆短轴
  
  // 创建椭圆跑道
  const trackGeometry = new THREE.EllipseCurve(
    0, 0,            // 中心点
    a, b,            // 半径
    0, 2 * Math.PI,  // 起始角度和结束角度
    false,           // 是否顺时针
    0                // 旋转角度
  );
  
  const innerTrackGeometry = new THREE.EllipseCurve(
    0, 0,
    innerA, innerB,
    0, 2 * Math.PI,
    false,
    0
  );
  
  const trackPoints = trackGeometry.getPoints(100);
  const innerTrackPoints = innerTrackGeometry.getPoints(100);
  
  // 合并点集形成跑道形状
  const allPoints = trackPoints.concat(innerTrackPoints.reverse());
  
  // 创建跑道形状
  const trackShape = new THREE.Shape();
  trackShape.moveTo(trackPoints[0].x, trackPoints[0].y);
  for (let i = 1; i < trackPoints.length; i++) {
    trackShape.lineTo(trackPoints[i].x, trackPoints[i].y);
  }
  trackShape.lineTo(innerTrackPoints[0].x, innerTrackPoints[0].y);
  for (let i = 1; i < innerTrackPoints.length; i++) {
    trackShape.lineTo(innerTrackPoints[i].x, innerTrackPoints[i].y);
  }
  trackShape.lineTo(trackPoints[0].x, trackPoints[0].y);
  
  // 创建跑道网格
  const trackExtrudeSettings = {
    steps: 1,
    depth: 0.1,
    bevelEnabled: false
  };
  
  const trackGeometry3D = new THREE.ExtrudeGeometry(trackShape, trackExtrudeSettings);
  const trackMaterial = new THREE.MeshStandardMaterial({ 
    color: 0x654321,
    roughness: 0.9
  });
  const track = new THREE.Mesh(trackGeometry3D, trackMaterial);
  track.rotation.x = -Math.PI / 2;
  track.position.set(x, y, z);
  scene.add(track);
  
  // 创建内部足球场
  // 使用CircleGeometry并通过缩放实现椭圆
  const fieldGeometry = new THREE.CircleGeometry(1, 100);
  const fieldMaterial = new THREE.MeshStandardMaterial({ 
    color: 0x228B22,
    side: THREE.DoubleSide
  });
  const field = new THREE.Mesh(fieldGeometry, fieldMaterial);
  field.scale.set(innerA, innerB, 1); // 椭圆缩放
  field.rotation.x = -Math.PI / 2;
  field.position.set(x, y + 0.01, z);
  scene.add(field);
  
  // 添加足球场标记线
  const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff });
  
  // 中圈
  const centerCircleGeometry = new THREE.CircleGeometry(1, 32);
  const centerCircle = new THREE.Line(
    new THREE.EdgesGeometry(centerCircleGeometry),
    lineMaterial
  );
  centerCircle.scale.set(3, 3, 1); // 椭圆缩放
  centerCircle.rotation.x = -Math.PI / 2;
  centerCircle.position.set(x, y + 0.02, z);
  scene.add(centerCircle);
  
  // 中线
  const points = [];
  points.push(new THREE.Vector3(-innerA, 0, 0));
  points.push(new THREE.Vector3(innerA, 0, 0));
  const midlineGeometry = new THREE.BufferGeometry().setFromPoints(points);
  const midline = new THREE.Line(midlineGeometry, lineMaterial);
  midline.rotation.x = -Math.PI / 2;
  midline.position.set(x, y + 0.02, z);
  scene.add(midline);
  
  return { track, field };
};

// 动画循环
const animate = () => {
  animateId = requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
};

// 处理窗口大小变化
const onWindowResize = () => {
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
};

onMounted(() => {
  initScene();
  animate();
  window.addEventListener('resize', onWindowResize);
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', onWindowResize);
  cancelAnimationFrame(animateId);
  if (container.value && container.value.contains(renderer.domElement)) {
    container.value.removeChild(renderer.domElement);
  }
});
</script>

<template>
  <div ref="container" id="webglContainer" style=""></div>
</template>

<style scoped lang="less">
@import "@assets/styles/common.less";

.wrap {
  width: 100%;
  height: 100%;
}
</style>
