<script setup lang="ts">
const canvasRef = ref<HTMLCanvasElement>()
let ctx: CanvasRenderingContext2D | null = null
let animId = 0
let stars: Star[] = []
let shootingStars: ShootingStar[] = []
let nextShootTime = 0

interface Star {
  x: number
  y: number
  size: number
  baseAlpha: number
  twinkleSpeed: number
  twinklePhase: number
}

interface ShootingStar {
  x: number
  y: number
  speed: number
  length: number
  alpha: number
  angle: number
}

function init() {
  const canvas = canvasRef.value
  if (!canvas || ctx) return
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
  ctx = canvas.getContext('2d')

  const count = Math.floor((canvas.width * canvas.height) / 2000)
  stars = Array.from({ length: count }, () => ({
    x: Math.random() * canvas.width,
    y: Math.random() * canvas.height,
    size: 0.3 + Math.random() * 2.0,
    baseAlpha: 0.3 + Math.random() * 0.7,
    twinkleSpeed: 0.2 + Math.random() * 0.8,
    twinklePhase: Math.random() * Math.PI * 2,
  }))
}

function scheduleShootingStar() {
  nextShootTime = Date.now() + 2000 + Math.random() * 8000
}

function spawnShootingStar(w: number, h: number) {
  const angle = Math.PI / 4 + (Math.random() - 0.5) * 0.3
  shootingStars.push({
    x: 0,
    y: Math.random() * h * 0.4,
    speed: 6 + Math.random() * 8,
    length: 60 + Math.random() * 100,
    alpha: 1,
    angle,
  })
}

function isDark(): boolean {
  return document.documentElement.classList.contains('dark')
}

function animate() {
  const canvas = canvasRef.value
  if (!canvas || !ctx) return

  if (!isDark()) {
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    animId = requestAnimationFrame(animate)
    return
  }

  const { width, height } = canvas
  ctx.clearRect(0, 0, width, height)
  const now = Date.now()

  // Stars
  for (const s of stars) {
    const alpha = s.baseAlpha * (0.5 + 0.5 * Math.sin(now * s.twinkleSpeed * 0.001 + s.twinklePhase))
    ctx.beginPath()
    ctx.arc(s.x, s.y, s.size, 0, Math.PI * 2)
    ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`
    ctx.fill()
  }

  // Shooting stars
  if (now > nextShootTime && shootingStars.length < 4) {
    spawnShootingStar(width, height)
    scheduleShootingStar()
  }

  for (let i = shootingStars.length - 1; i >= 0; i--) {
    const ss = shootingStars[i]
    ss.x += Math.cos(ss.angle) * ss.speed
    ss.y += Math.sin(ss.angle) * ss.speed
    ss.alpha -= 0.005

    if (ss.alpha <= 0 || ss.x > width + ss.length || ss.y > height) {
      shootingStars.splice(i, 1)
      continue
    }

    const tailX = ss.x - Math.cos(ss.angle) * ss.length
    const tailY = ss.y - Math.sin(ss.angle) * ss.length
    const gradient = ctx.createLinearGradient(tailX, tailY, ss.x, ss.y)
    gradient.addColorStop(0, `rgba(255, 255, 255, 0)`)
    gradient.addColorStop(1, `rgba(255, 255, 255, ${ss.alpha})`)
    ctx.beginPath()
    ctx.moveTo(tailX, tailY)
    ctx.lineTo(ss.x, ss.y)
    ctx.strokeStyle = gradient
    ctx.lineWidth = 1.5
    ctx.stroke()
  }

  animId = requestAnimationFrame(animate)
}

onMounted(async () => {
  if (typeof window === 'undefined' || window.matchMedia('(prefers-reduced-motion: reduce)').matches) return

  await nextTick()
  init()
  animate()

  const onResize = () => {
    const canvas = canvasRef.value
    if (!canvas) return
    canvas.width = window.innerWidth
    canvas.height = window.innerHeight
    const count = Math.floor((canvas.width * canvas.height) / 2000)
    stars = Array.from({ length: count }, () => ({
      x: Math.random() * canvas.width,
      y: Math.random() * canvas.height,
      size: 0.3 + Math.random() * 2.0,
      baseAlpha: 0.3 + Math.random() * 0.7,
      twinkleSpeed: 0.2 + Math.random() * 0.8,
      twinklePhase: Math.random() * Math.PI * 2,
    }))
  }
  window.addEventListener('resize', onResize)
})

const style = `position: fixed; inset: 0; z-index: 0; pointer-events: none;`
</script>

<template>
  <canvas ref="canvasRef" :style="style" />
</template>
