<script setup lang="ts">
/**
 * GalaxyBackground – Canvas Starfield + Aurora Blobs
 *
 * Ported from assets/galaxy.js (design_handoff_nexus_v2).
 * Auto-mounts onMounted; cleans up onUnmounted.
 * Fixed overlay with z-index:0 and pointer-events:none.
 */
import { onMounted, onUnmounted, ref } from 'vue'

const rootRef = ref<HTMLElement | null>(null)

interface Star {
  x: number
  y: number
  r: number
  a: number
  tw: number
  ph: number
  hue: number
  dx: number
  dy: number
}

interface Shoot {
  x: number
  y: number
  len: number
  sp: number
  ang: number
  life: number
}

let resizeObserver: ResizeObserver | null = null
let animFrameId = 0
let canvas: HTMLCanvasElement | null = null
let ctx: CanvasRenderingContext2D | null = null

function mount(root: HTMLElement) {
  canvas = document.createElement('canvas')
  root.appendChild(canvas)
  ctx = canvas.getContext('2d')
  if (!ctx) return

  const dpr = Math.min(window.devicePixelRatio || 1, 2)
  let stars: Star[] = []
  let shoots: Shoot[] = []
  let W = 0
  let H = 0
  let t = 0

  function resize() {
    const r = root.getBoundingClientRect()
    W = r.width
    H = r.height
    canvas!.width = W * dpr
    canvas!.height = H * dpr
    ctx!.setTransform(dpr, 0, 0, dpr, 0, 0)

    const count = Math.round((W * H) / 5200)
    stars = []
    for (let i = 0; i < count; i++) {
      stars.push({
        x: Math.random() * W,
        y: Math.random() * H,
        r: Math.random() * 1.3 + 0.25,
        a: Math.random() * 0.6 + 0.2,
        tw: Math.random() * 0.025 + 0.004,
        ph: Math.random() * Math.PI * 2,
        hue: Math.random() < 0.5 ? 230 : 270,
        dx: (Math.random() - 0.5) * 0.04,
        dy: (Math.random() - 0.5) * 0.04,
      })
    }
  }

  function spawnShoot() {
    const fromLeft = Math.random() < 0.6
    shoots.push({
      x: fromLeft ? -40 : W * (0.4 + Math.random() * 0.5),
      y: Math.random() * H * 0.5,
      len: 90 + Math.random() * 120,
      sp: 6 + Math.random() * 5,
      ang: Math.random() * 0.3 + 0.15,
      life: 1,
    })
  }

  function frame() {
    ctx!.clearRect(0, 0, W, H)
    t += 1

    // Draw stars
    for (let i = 0; i < stars.length; i++) {
      const s = stars[i]
      s.ph += s.tw
      const a = s.a * (0.55 + 0.45 * Math.sin(s.ph))
      s.x += s.dx
      s.y += s.dy
      if (s.x < 0) s.x = W
      if (s.x > W) s.x = 0
      if (s.y < 0) s.y = H
      if (s.y > H) s.y = 0

      ctx!.beginPath()
      ctx!.fillStyle = `hsla(${s.hue},90%,82%,${a})`
      ctx!.arc(s.x, s.y, s.r, 0, Math.PI * 2)
      ctx!.fill()

      // Glow for larger stars
      if (s.r > 1) {
        ctx!.beginPath()
        ctx!.fillStyle = `hsla(${s.hue},95%,80%,${a * 0.12})`
        ctx!.arc(s.x, s.y, s.r * 3.5, 0, Math.PI * 2)
        ctx!.fill()
      }
    }

    // Shooting stars
    if (Math.random() < 0.004 && shoots.length < 2) spawnShoot()
    for (let j = shoots.length - 1; j >= 0; j--) {
      const sh = shoots[j]
      sh.x += Math.cos(sh.ang) * sh.sp
      sh.y += Math.sin(sh.ang) * sh.sp
      sh.life -= 0.006

      const ex = sh.x - Math.cos(sh.ang) * sh.len
      const ey = sh.y - Math.sin(sh.ang) * sh.len
      const g = ctx!.createLinearGradient(sh.x, sh.y, ex, ey)
      g.addColorStop(0, `rgba(200,210,255,${0.9 * sh.life})`)
      g.addColorStop(1, 'rgba(160,120,255,0)')

      ctx!.strokeStyle = g
      ctx!.lineWidth = 2
      ctx!.lineCap = 'round'
      ctx!.beginPath()
      ctx!.moveTo(sh.x, sh.y)
      ctx!.lineTo(ex, ey)
      ctx!.stroke()

      if (sh.life <= 0 || sh.x > W + 60 || sh.y > H + 60) shoots.splice(j, 1)
    }

    animFrameId = requestAnimationFrame(frame)
  }

  resizeObserver = new ResizeObserver(() => resize())
  resizeObserver.observe(root)
  resize()
  frame()
}

function cleanup() {
  if (resizeObserver) {
    resizeObserver.disconnect()
    resizeObserver = null
  }
  if (animFrameId) {
    cancelAnimationFrame(animFrameId)
    animFrameId = 0
  }
  if (canvas && canvas.parentNode) {
    canvas.parentNode.removeChild(canvas)
  }
  canvas = null
  ctx = null
}

onMounted(() => {
  if (rootRef.value) mount(rootRef.value)
})

onUnmounted(() => {
  cleanup()
})
</script>

<template>
  <div ref="rootRef" class="galaxy-bg">
    <div class="aurora a1"></div>
    <div class="aurora a2"></div>
    <div class="aurora a3"></div>
  </div>
</template>

<style scoped>
.galaxy-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background:
    radial-gradient(1200px 800px at 18% -8%, rgba(79,124,255,.20), transparent 60%),
    radial-gradient(1000px 760px at 92% 8%, rgba(181,87,246,.18), transparent 60%),
    radial-gradient(900px 700px at 60% 110%, rgba(70,60,180,.20), transparent 60%),
    linear-gradient(180deg, #070512, #0a0818 60%, #060410);
  pointer-events: none;
}
.galaxy-bg canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.aurora {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.5;
  mix-blend-mode: screen;
  will-change: transform;
}
.a1 {
  width: 46vw;
  height: 46vw;
  left: -8vw;
  top: -14vw;
  background: radial-gradient(circle, rgba(79,124,255,.55), transparent 65%);
  animation: drift1 26s ease-in-out infinite;
}
.a2 {
  width: 40vw;
  height: 40vw;
  right: -10vw;
  top: 2vw;
  background: radial-gradient(circle, rgba(181,87,246,.5), transparent 65%);
  animation: drift2 32s ease-in-out infinite;
}
.a3 {
  width: 42vw;
  height: 42vw;
  left: 34vw;
  bottom: -18vw;
  background: radial-gradient(circle, rgba(95,80,220,.45), transparent 65%);
  animation: drift3 30s ease-in-out infinite;
}
@keyframes drift1 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(8vw, 6vw) scale(1.12); }
}
@keyframes drift2 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(-7vw, 5vw) scale(1.1); }
}
@keyframes drift3 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(4vw, -6vw) scale(1.15); }
}
</style>
