<template>
  <div ref="earthContainer" class="earth-container"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// 地球纹理URL
import earthBlueMarble from '../../assets/images/earth-blue-marble.jpg';

const earthContainer = ref<HTMLDivElement | null>(null);

let scene: THREE.Scene | null = null;
let camera: THREE.PerspectiveCamera | null = null;
let renderer: THREE.WebGLRenderer | null = null;
let controls: OrbitControls | null = null;
let earth: THREE.Mesh | null = null;
let markers: THREE.Mesh[] = [];
let animationId: number | null = null;

// 城市数据 - 红色主要城市
const primaryCities = [
  { name: '广州', lat: 23.1291, lng: 113.2644, color: 0xFA2D30 },
];

// 城市数据 - 黄色次要城市
const secondaryCities = [
  { name: '北京', lat: 39.9042, lng: 116.4074, color: 0xFFF963 },
  { name: '上海', lat: 31.2304, lng: 121.4737, color: 0xFFF963 },
  { name: '香港', lat: 22.3964, lng: 114.1095, color: 0xFFF963 },
  { name: '新加坡', lat: 1.3521, lng: 103.8198, color: 0xFFF963 },
  { name: '东京', lat: 35.6824, lng: 139.759, color: 0xFFF963 },
  { name: '伦敦', lat: 51.5074, lng: -0.1278, color: 0xFFF963 },
  { name: '迪拜', lat: 25.276987, lng: 55.296249, color: 0xFFF963 },
  { name: '纽约', lat: 40.748817, lng: -73.985428, color: 0xFFF963 },
  { name: '旧金山', lat: 37.7749, lng: -122.4194, color: 0xFFF963 },
  { name: '惉尼', lat: -33.8688, lng: 151.2093, color: 0xFFF963 },
  { name: '巴黎', lat: 48.8566, lng: 2.3522, color: 0xFFF963 },
];

const EARTH_RADIUS = 1.0;

const initScene = () => {
  if (!earthContainer.value) return;

  const width = earthContainer.value.clientWidth;
  const height = earthContainer.value.clientHeight;

  // 创建场景
  scene = new THREE.Scene();

  // 创建相机
  camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100);
  camera.position.set(0.0, 1.5, 3.0);

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({
    antialias: true,
    alpha: true,
  });
  renderer.setSize(width, height);
  renderer.setPixelRatio(window.devicePixelRatio);
  earthContainer.value.appendChild(renderer.domElement);

  // 创建 OrbitControls
  controls = new OrbitControls(camera, renderer.domElement);
  controls.autoRotate = true;
  controls.autoRotateSpeed = -1.0;
  controls.enablePan = false;
  controls.enableZoom = false;
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;

  // 添加光源
  addLights();

  // 创建地球
  createEarth();

  // 创建大气层
  createAtmosphere();
};

const addLights = () => {
  if (!scene) return;

  // 环境光
  const ambient = new THREE.AmbientLight(0xffffff, 1);
  scene.add(ambient);

  // 方向光
  const directional = new THREE.DirectionalLight(0xffffff, 0.5);
  directional.position.set(5.0, 2.0, 5.0).normalize();
  scene.add(directional);
};

const createEarth = () => {
  if (!scene) return;

  const loader = new THREE.TextureLoader();

  loader.load(earthBlueMarble, (texture) => {
    if (!scene) return;

    // 设置各向异性过滤
    if (renderer) {
      texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
    }

    const geometry = new THREE.SphereGeometry(EARTH_RADIUS, 64, 48);
    const material = new THREE.MeshStandardMaterial({
      color: 0xFFFFFF,
      map: texture,
      roughness: 0.6,
      metalness: 0.1,
      side: THREE.DoubleSide,
    });

    earth = new THREE.Mesh(geometry, material);
    scene.add(earth);

    // 地球加载完成后添加标记点
    createMarkers();
  });
};

const createAtmosphere = () => {
  if (!scene) return;

  const atmosphereGeometry = new THREE.SphereGeometry(1.05, 64, 48);
  const atmosphereMaterial = new THREE.ShaderMaterial({
    vertexShader: `
      varying vec3 vertexNormal;
      void main() {
        vertexNormal = normalize(normalMatrix * normal);
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
    fragmentShader: `
      varying vec3 vertexNormal;
      void main() {
        float intensity = pow(0.6 - dot(vertexNormal, vec3(0, 0, 1.0)), 2.0);
        gl_FragColor = vec4(0.3, 0.6, 1.0, 0.8) * intensity;
      }
    `,
    blending: THREE.AdditiveBlending,
    side: THREE.BackSide,
    transparent: true,
  });

  const atmosphere = new THREE.Mesh(atmosphereGeometry, atmosphereMaterial);
  atmosphere.scale.set(1.1, 1.1, 1.1);
  atmosphere.position.x = -0.02;
  atmosphere.position.y = 0.02;
  scene.add(atmosphere);
};

// 经纬度转换为3D坐标
const latLngToVector3 = (lat: number, lng: number, radius: number): THREE.Vector3 => {
  const phi = (90 - lat) * (Math.PI / 180);
  const theta = (lng + 180) * (Math.PI / 180);

  const x = -radius * Math.sin(phi) * Math.cos(theta);
  const y = radius * Math.cos(phi);
  const z = radius * Math.sin(phi) * Math.sin(theta);

  return new THREE.Vector3(x, y, z);
};

// 创建标记点
const createMarkers = () => {
  if (!scene) return;

  const markerRadius = 1.06;

  // 创建主要城市标记（红色，较大）
  primaryCities.forEach((city) => {
    const marker = createCityMarker(city.lat, city.lng, markerRadius, city.color, 0.02, true);
    if (marker) {
      scene!.add(marker);
      markers.push(marker);
    }
  });

  // 创建次要城市标记（黄色，较小）
  secondaryCities.forEach((city) => {
    const marker = createCityMarker(city.lat, city.lng, markerRadius, city.color, 0.01, false);
    if (marker) {
      scene!.add(marker);
      markers.push(marker);
    }
  });
};

// 创建城市标记
const createCityMarker = (
  lat: number,
  lng: number,
  radius: number,
  color: number,
  size: number,
  hasRing: boolean
): THREE.Mesh | null => {
  // 创建圆形标记
  const geometry = new THREE.CircleGeometry(size, 32);
  const material = new THREE.MeshBasicMaterial({
    color: color,
    side: THREE.DoubleSide,
  });
  const marker = new THREE.Mesh(geometry, material);

  // 添加外环
  if (hasRing) {
    const ringGeometry = new THREE.RingGeometry(size * 1.2, size * 1.7, 32);
    const ringMaterial = new THREE.MeshBasicMaterial({
      color: color,
      side: THREE.DoubleSide,
    });
    const ring = new THREE.Mesh(ringGeometry, ringMaterial);
    marker.add(ring);
  } else {
    // 次要城市添加较小的外环
    const ringGeometry = new THREE.RingGeometry(size * 1.5, size * 1.8, 32);
    const ringMaterial = new THREE.MeshBasicMaterial({
      color: 0x898A51,
      side: THREE.DoubleSide,
    });
    const ring = new THREE.Mesh(ringGeometry, ringMaterial);
    marker.add(ring);
  }

  // 计算位置
  const position = latLngToVector3(lat, lng, radius);
  marker.position.copy(position);

  // 让标记朝向球心外侧
  marker.lookAt(new THREE.Vector3(0, 0, 0));
  marker.rotateX(Math.PI);

  return marker;
};

const animate = () => {
  if (!scene || !camera || !renderer) return;

  animationId = requestAnimationFrame(animate);

  // 更新控制器
  if (controls) {
    controls.update();
  }

  // 让标记点始终面向相机
  markers.forEach((marker) => {
    marker.quaternion.copy(camera!.quaternion);
  });

  renderer.render(scene, camera);
};

const onResize = () => {
  if (!earthContainer.value || !camera || !renderer) return;

  const width = earthContainer.value.clientWidth;
  const height = earthContainer.value.clientHeight;

  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
};

const dispose = () => {
  if (animationId) {
    cancelAnimationFrame(animationId);
  }

  if (controls) {
    controls.dispose();
  }

  // 清理标记
  markers.forEach((marker) => {
    marker.geometry?.dispose();
    if (marker.material instanceof THREE.Material) {
      marker.material.dispose();
    }
  });
  markers = [];

  // 清理地球
  if (earth) {
    earth.geometry?.dispose();
    if (earth.material instanceof THREE.Material) {
      earth.material.dispose();
    }
  }

  if (renderer) {
    renderer.dispose();
    if (earthContainer.value && renderer.domElement) {
      earthContainer.value.removeChild(renderer.domElement);
    }
  }

  scene = null;
  camera = null;
  renderer = null;
  controls = null;
  earth = null;
};

onMounted(async () => {
  await nextTick();
  initScene();
  animate();
  window.addEventListener('resize', onResize);
});

onUnmounted(() => {
  dispose();
  window.removeEventListener('resize', onResize);
});
</script>

<style scoped>
.earth-container {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 50;
}
</style>
