<template>
  <div
    class="starfield-container"
    :style="{
      backgroundImage: computedBgImage,
      backgroundColor: backgroundType === 'color' ? backgroundColor : 'transparent',
    }"
  >
    <canvas ref="canvasRef"></canvas>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';

const props = defineProps({
  /**
   * 粒子数量，决定星空的密集程度
   */
  particleCount: {
    type: Number as PropType<number>,
    default: 200,
  },
  /**
   * 粒子飞行速度，数值越大速度越快
   */
  speed: {
    type: Number as PropType<number>,
    default: 1.5,
  },
  /**
   * 焦距 (Field of View)，影响透视效果的强弱
   */
  fov: {
    type: Number as PropType<number>,
    default: 300,
  },
  /**
   * 粒子距离观察者的最大深度
   */
  maxDepth: {
    type: Number as PropType<number>,
    default: 2000,
  },
  /**
   * 粒子距离观察者的最小深度，避免粒子太靠近导致异常放大
   */
  minDepth: {
    type: Number as PropType<number>,
    default: 250,
  },
  /**
   * 粒子显示的图像路径，如果为空则使用默认渐变圆点
   */
  imageSrc: {
    type: String as PropType<string>,
    default: '',
  },
  /**
   * 背景类型，可选值为：
   * - 'color': 使用纯色背景
   * - 'transparent': 使用透明背景
   * - 'image': 使用图片背景
   */
  backgroundType: {
    type: String as PropType<'color' | 'transparent' | 'image'>,
    default: 'color',
    validator: (value: string) => ['color', 'transparent', 'image'].includes(value),
  },
  /**
   * 纯色背景颜色，仅当 backgroundType 为 'color' 时生效
   */
  backgroundColor: {
    type: String as PropType<string>,
    default: 'black',
  },
  /**
   * 背景图片路径，仅当 backgroundType 为 'image' 时生效
   */
  backgroundImage: {
    type: String as PropType<string>,
    default: '',
  },
  /**
   * 粒子色值
   */
  particleColor: {
    type: String as PropType<string>,
    default: 'rgba(255, 255, 255, 0.5)',
  },
});

interface Particle {
  x: number;
  y: number;
  z: number;
}

const canvasRef = ref<HTMLCanvasElement | null>(null);
let ctx: CanvasRenderingContext2D | null = null;
let particles: Particle[] = [];
let animationFrameId: number | null = null;

const width = ref(0);
const height = ref(0);

// 动态计算背景图片样式
const computedBgImage = computed(() =>
  props.backgroundType === 'image' && props.backgroundImage
    ? `url(${props.backgroundImage})`
    : 'none',
);

// 初始化粒子
const initParticles = () => {
  particles = Array.from({ length: props.particleCount }, () => ({
    x: (Math.random() - 0.5) * width.value * 2,
    y: (Math.random() - 0.5) * height.value * 2,
    z: Math.random() * (props.maxDepth - props.minDepth) + props.minDepth,
  }));
};

// 动画绘制逻辑
const draw = () => {
  if (!ctx) return;
  ctx.clearRect(0, 0, width.value, height.value);

  for (const particle of particles) {
    particle.z -= props.speed;
    if (particle.z <= 0) {
      particle.z = Math.random() * (props.maxDepth - props.minDepth) + props.minDepth;
    }

    const sx = width.value / 2 + (particle.x / particle.z) * props.fov;
    const sy = height.value / 2 + (particle.y / particle.z) * props.fov;
    const size = (1 - particle.z / props.maxDepth) * 5;

    ctx.beginPath();
    ctx.arc(sx, sy, size, 0, Math.PI * 2);
    ctx.fillStyle = props.particleColor;
    ctx.fill();
  }

  animationFrameId = requestAnimationFrame(draw);
};

// 初始化画布
const resizeCanvas = () => {
  if (!canvasRef.value) return;
  canvasRef.value.width = canvasRef.value.offsetWidth;
  canvasRef.value.height = canvasRef.value.offsetHeight;

  width.value = canvasRef.value.width;
  height.value = canvasRef.value.height;

  initParticles();
};

onMounted(() => {
  const canvas = canvasRef.value;
  if (!canvas) return;
  ctx = canvas.getContext('2d');
  resizeCanvas();
  draw();
  window.addEventListener('resize', resizeCanvas);
});

onBeforeUnmount(() => {
  if (animationFrameId) cancelAnimationFrame(animationFrameId);
  window.removeEventListener('resize', resizeCanvas);
});
</script>

<style scoped>
.starfield-container {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background-size: cover;
  background-position: center;
}
canvas {
  width: 100%;
  height: 100%;
  display: block;
}
</style>
