<template>
  <div ref="container" class="particle-container"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
import * as THREE from 'three';

// 定义Props
const props = defineProps({
  particleCount: { type: Number, default: 10000 }, // 每层粒子数量
  layerCount: { type: Number, default: 4 }, // 层数
  baseRadius: { type: Number, default: 200 }, // 基础圆环半径
  waveAmplitude: { type: Number, default: 18 }, // 波动振幅
  frequency: { type: Number, default: 6 }, // 波动频率（花瓣数）
  particleSize: { type: Number, default: 1 }, // 粒子大小
  rotationSpeed: { type: Number, default: 0.0005 }, // 整体旋转速度
  waveSpeed: { type: Number, default: 0.08 }, // 波动速度
  backgroundColor: { type: String, default: 'black' }, // 背景颜色
  colors: {
    type: Array as () => string[],
    default: () => [
      'hsl(180, 100%, 60%)',
      'hsl(190, 100%, 60%)',
      'hsl(200, 100%, 60%)',
      'hsl(210, 100%, 60%)',
    ],
  }, // 颜色数组 ，推荐使用hls数据，也可以使用rgb数据
});

// 元素容器和Three.js变量
const container = ref<HTMLDivElement | null>(null);
let scene: THREE.Scene, camera: THREE.PerspectiveCamera, renderer: THREE.WebGLRenderer;
let waveParticles: THREE.Points[] = [];
let animationId: number;
let time = 0; // 动画时间

// 初始化场景、相机和渲染器
function initScene() {
  if (!container.value) return;

  // 清理旧场景
  waveParticles = [];
  if (scene) {
    scene.clear();
    renderer.dispose();
  }

  scene = new THREE.Scene();
  scene.background = new THREE.Color(props.backgroundColor);

  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 2000);
  camera.position.z = 500;

  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  container.value.appendChild(renderer.domElement);

  createWaveLayers();
  animate();
}

// 创建波动层
function createWaveLayers() {
  for (let i = 0; i < props.layerCount; i++) {
    const geometry = new THREE.BufferGeometry();
    const positions = [];
    const sizes = [];

    for (let j = 0; j < props.particleCount; j++) {
      const angle = (j / props.particleCount) * Math.PI * 2; // 均匀分布在圆周上
      const offset = Math.sin(angle * props.frequency + i * 1.5) * props.waveAmplitude; // 花瓣波动

      const radius = props.baseRadius + offset; // 叠加振幅
      const x = Math.cos(angle) * radius;
      const y = Math.sin(angle) * radius;
      const z = (Math.random() - 0.5) * 30; // Z轴增加颗粒感

      positions.push(x, y, z);
      sizes.push(Math.random() * 2 + 1); // 粒子大小随机
    }

    geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
    geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1));

    const color = props.colors[i % props.colors.length];

    const material = new THREE.PointsMaterial({
      size: props.particleSize,
      // color: new THREE.Color(`hsl(${180 + i * 10}, 100%, 60%)`), // 层次颜色变化
      color: new THREE.Color(color),
      transparent: true,
      opacity: 0.8 - i * 0.2,
      blending: THREE.AdditiveBlending,
      depthWrite: false,
    });

    const points = new THREE.Points(geometry, material);
    waveParticles.push(points);
    scene.add(points);
  }
}

// 动画逻辑
function animate() {
  animationId = requestAnimationFrame(animate);
  time += props.waveSpeed;

  waveParticles.forEach((points, index) => {
    const positions = points.geometry.attributes.position.array;

    for (let i = 0; i < positions.length; i += 3) {
      const angle = Math.atan2(positions[i + 1], positions[i]);
      const baseRadius =
        props.baseRadius + Math.sin(angle * props.frequency + index * 1.5) * props.waveAmplitude;

      // 在初始位置基础上平滑地波动
      const offset = Math.sin(angle * props.frequency + time + index * 0.5) * props.waveAmplitude;

      positions[i] = Math.cos(angle) * (baseRadius + offset); // X轴更新
      positions[i + 1] = Math.sin(angle) * (baseRadius + offset); // Y轴更新
    }

    points.geometry.attributes.position.needsUpdate = true;

    // 控制每一层的旋转效果
    points.rotation.z += props.rotationSpeed * (index % 2 === 0 ? 1 : -1);
  });

  renderer.render(scene, camera);
}

// 处理窗口大小变化
function onResize() {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
}

// 监听Props变化，重新渲染
watch(props, () => {
  initScene();
});

// 生命周期管理
onMounted(() => {
  initScene();
  window.addEventListener('resize', onResize);
});

onBeforeUnmount(() => {
  cancelAnimationFrame(animationId);
  window.removeEventListener('resize', onResize);
  renderer.dispose();
  scene.clear();
});
</script>

<style scoped>
.particle-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
</style>
