<template>
  <canvas ref="canvasRef" class="ambient-bg-canvas fixed inset-0 w-full h-full z-0 pointer-events-none"></canvas>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { useTheme } from '../composables/useTheme'

const canvasRef = ref<HTMLCanvasElement | null>(null)
const { resolvedTheme } = useTheme()

const config = {
  starCount: 150,
  dustCount: 80,
  meteorChance: 0.003,
  orbCount: 3,
}

let running = false
let reduceMotion = false
let time = 0

interface Star {
  x: number
  y: number
  radius: number
  alpha: number
  fadingOut: boolean
  speed: number
}

interface Meteor {
  x: number
  y: number
  length: number
  speed: number
  angle: number
  alpha: number
  width: number
}

interface Wave {
  x: number
  y: number
  radius: number
  alpha: number
  lineWidth: number
  hue: number
}

interface Particle {
  x: number
  y: number
  vx: number
  vy: number
  life: number
  color: string
  size: number
}

interface Dust {
  x: number
  y: number
  radius: number
  alpha: number
  fadingOut: boolean
  speed: number
  baseAlpha: number
}

interface Orb {
  baseX: number
  baseY: number
  radius: number
  ampX: number
  ampY: number
  phaseX: number
  phaseY: number
  speed: number
  alpha: number
  color: string
}

let ctx: CanvasRenderingContext2D | null = null
let animationFrameId: number
let width = 0
let height = 0

const stars: Star[] = []
const meteors: Meteor[] = []
const waves: Wave[] = []
const particles: Particle[] = []
const dust: Dust[] = []
const orbs: Orb[] = []

const prefersReducedMotion = () =>
  typeof window !== 'undefined' &&
  window.matchMedia('(prefers-reduced-motion: reduce)').matches

const clearPools = () => {
  stars.length = 0
  meteors.length = 0
  waves.length = 0
  particles.length = 0
  dust.length = 0
  orbs.length = 0
}

const initStars = () => {
  stars.length = 0
  for (let i = 0; i < config.starCount; i++) {
    stars.push({
      x: Math.random() * width,
      y: Math.random() * height,
      radius: Math.random() * 1.5,
      alpha: Math.random(),
      fadingOut: Math.random() > 0.5,
      speed: Math.random() * 0.02 + 0.005,
    })
  }
}

const initDust = () => {
  dust.length = 0
  for (let i = 0; i < config.dustCount; i++) {
    const baseAlpha = Math.random() * 0.35 + 0.15
    dust.push({
      x: Math.random() * width,
      y: Math.random() * height,
      radius: Math.random() * 1.8 + 0.4,
      alpha: baseAlpha,
      fadingOut: Math.random() > 0.5,
      speed: Math.random() * 0.008 + 0.003,
      baseAlpha,
    })
  }
}

const initOrbs = () => {
  orbs.length = 0
  const palette = [
    'rgba(212, 179, 131, 0.22)',
    'rgba(196, 150, 90, 0.16)',
    'rgba(232, 200, 150, 0.18)',
  ]
  const placements = [
    { bx: 0.15, by: 0.2 },
    { bx: 0.82, by: 0.35 },
    { bx: 0.45, by: 0.78 },
  ]
  for (let i = 0; i < config.orbCount; i++) {
    const p = placements[i] || { bx: Math.random(), by: Math.random() }
    orbs.push({
      baseX: p.bx * width,
      baseY: p.by * height,
      radius: Math.min(width, height) * (0.28 + Math.random() * 0.12),
      ampX: 40 + Math.random() * 60,
      ampY: 30 + Math.random() * 50,
      phaseX: Math.random() * Math.PI * 2,
      phaseY: Math.random() * Math.PI * 2,
      speed: 0.00025 + Math.random() * 0.0002,
      alpha: 0.55 + Math.random() * 0.25,
      color: palette[i % palette.length],
    })
  }
}

const initForTheme = () => {
  clearPools()
  if (resolvedTheme.value === 'dark') {
    initStars()
  } else {
    initOrbs()
    initDust()
  }
}

const createMeteor = () => {
  meteors.push({
    x: Math.random() * width,
    y: 0,
    length: Math.random() * 80 + 20,
    speed: Math.random() * 10 + 5,
    angle: Math.PI / 4,
    alpha: 1,
    width: Math.random() * 1.5 + 0.5,
  })
}

const updateAndDrawMeteors = () => {
  if (Math.random() < config.meteorChance) createMeteor()

  for (let i = meteors.length - 1; i >= 0; i--) {
    const m = meteors[i]
    if (!ctx) break

    const endX = m.x - m.length * Math.cos(m.angle)
    const endY = m.y - m.length * Math.sin(m.angle)

    const gradient = ctx.createLinearGradient(m.x, m.y, endX, endY)
    gradient.addColorStop(0, `rgba(255, 255, 255, ${m.alpha})`)
    gradient.addColorStop(1, 'rgba(255, 255, 255, 0)')

    ctx.beginPath()
    ctx.moveTo(m.x, m.y)
    ctx.lineTo(endX, endY)
    ctx.lineWidth = m.width
    ctx.strokeStyle = gradient
    ctx.stroke()

    m.x += m.speed * Math.cos(m.angle)
    m.y += m.speed * Math.sin(m.angle)

    if (m.x > width + 100 || m.y > height + 100) {
      meteors.splice(i, 1)
    }
  }
}

const updateAndDrawWaves = (isLight: boolean) => {
  for (let i = waves.length - 1; i >= 0; i--) {
    const w = waves[i]
    if (!ctx) break

    ctx.beginPath()
    ctx.arc(w.x, w.y, w.radius, 0, Math.PI * 2)
    ctx.strokeStyle = isLight
      ? `hsla(${w.hue}, 45%, 48%, ${w.alpha * 0.85})`
      : `hsla(${w.hue}, 70%, 60%, ${w.alpha})`
    ctx.lineWidth = w.lineWidth
    ctx.stroke()

    w.radius += isLight ? 1.6 : 2
    w.alpha -= 0.02
    w.lineWidth *= 0.95

    if (w.alpha <= 0) waves.splice(i, 1)
  }
}

const updateAndDrawParticles = () => {
  for (let i = particles.length - 1; i >= 0; i--) {
    const p = particles[i]
    if (!ctx) break

    ctx.fillStyle = p.color
    ctx.beginPath()
    ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2)
    ctx.fill()

    p.x += p.vx
    p.y += p.vy
    p.vy += 0.05
    p.vx *= 0.96
    p.vy *= 0.96
    p.life -= 0.02
    p.size *= 0.96

    if (p.life <= 0) particles.splice(i, 1)
  }
}

const drawDark = () => {
  if (!ctx) return

  ctx.fillStyle = '#FFF'
  stars.forEach((star) => {
    if (!reduceMotion) {
      if (star.fadingOut) {
        star.alpha -= star.speed
        if (star.alpha < 0) {
          star.alpha = 0
          star.fadingOut = false
        }
      } else {
        star.alpha += star.speed
        if (star.alpha > 1) {
          star.alpha = 1
          star.fadingOut = true
        }
      }
    }

    ctx!.globalAlpha = star.alpha
    ctx!.beginPath()
    ctx!.arc(star.x, star.y, star.radius, 0, Math.PI * 2)
    ctx!.fill()
  })
  ctx.globalAlpha = 1

  if (!reduceMotion) {
    updateAndDrawMeteors()
  }
  updateAndDrawWaves(false)
  updateAndDrawParticles()
}

const drawLight = () => {
  if (!ctx) return

  // Aurora orbs
  orbs.forEach((orb) => {
    const x = reduceMotion
      ? orb.baseX
      : orb.baseX + Math.sin(time * orb.speed + orb.phaseX) * orb.ampX
    const y = reduceMotion
      ? orb.baseY
      : orb.baseY + Math.cos(time * orb.speed * 0.85 + orb.phaseY) * orb.ampY

    const mid = orb.color.replace(/,\s*[\d.]+\)$/, ', 0.08)')
    const gradient = ctx!.createRadialGradient(x, y, 0, x, y, orb.radius)
    gradient.addColorStop(0, orb.color)
    gradient.addColorStop(0.45, mid)
    gradient.addColorStop(1, 'rgba(212, 179, 131, 0)')

    ctx!.globalAlpha = orb.alpha
    ctx!.fillStyle = gradient
    ctx!.beginPath()
    ctx!.arc(x, y, orb.radius, 0, Math.PI * 2)
    ctx!.fill()
  })
  ctx.globalAlpha = 1

  // Gold dust
  dust.forEach((d) => {
    if (!reduceMotion) {
      if (d.fadingOut) {
        d.alpha -= d.speed
        if (d.alpha < d.baseAlpha * 0.25) {
          d.alpha = d.baseAlpha * 0.25
          d.fadingOut = false
        }
      } else {
        d.alpha += d.speed
        if (d.alpha > d.baseAlpha) {
          d.alpha = d.baseAlpha
          d.fadingOut = true
        }
      }
    }

    ctx!.globalAlpha = d.alpha
    ctx!.fillStyle = 'rgb(196, 155, 95)'
    ctx!.beginPath()
    ctx!.arc(d.x, d.y, d.radius, 0, Math.PI * 2)
    ctx!.fill()
  })
  ctx.globalAlpha = 1

  updateAndDrawWaves(true)
  updateAndDrawParticles()
}

const render = () => {
  if (!running || !ctx || !canvasRef.value) return

  ctx.clearRect(0, 0, width, height)
  if (!reduceMotion) time += 16

  if (resolvedTheme.value === 'dark') {
    drawDark()
  } else {
    drawLight()
  }

  animationFrameId = requestAnimationFrame(render)
}

const handleClick = (e: MouseEvent) => {
  if (!running || reduceMotion) return

  const isLight = resolvedTheme.value === 'light'
  const hue = isLight ? 35 + Math.floor(Math.random() * 12) : Math.floor(Math.random() * 360)

  waves.push({
    x: e.clientX,
    y: e.clientY,
    radius: 0,
    alpha: isLight ? 0.9 : 1,
    lineWidth: isLight ? 2.5 : 3,
    hue,
  })

  const particleCount = 10
  for (let i = 0; i < particleCount; i++) {
    const angle = ((Math.PI * 2) / particleCount) * i
    const speed = Math.random() * 3 + 1
    particles.push({
      x: e.clientX,
      y: e.clientY,
      vx: Math.cos(angle) * speed,
      vy: Math.sin(angle) * speed,
      life: 1.0,
      color: isLight
        ? `hsla(${hue}, 50%, 52%, 0.9)`
        : `hsla(${hue}, 80%, 70%, 1)`,
      size: Math.random() * 2 + 1,
    })
  }

  if (!isLight) createMeteor()
}

const handleResize = () => {
  if (!canvasRef.value) return
  width = window.innerWidth
  height = window.innerHeight
  canvasRef.value.width = width
  canvasRef.value.height = height
  initForTheme()
}

const startLoop = () => {
  if (running) return
  running = true
  render()
}

const stopLoop = () => {
  running = false
  cancelAnimationFrame(animationFrameId)
  if (ctx && canvasRef.value) {
    ctx.clearRect(0, 0, width, height)
  }
}

const syncMotionPreference = () => {
  reduceMotion = prefersReducedMotion()
}

let motionQuery: MediaQueryList | null = null
const onMotionChange = () => {
  syncMotionPreference()
}

onMounted(() => {
  if (!canvasRef.value) return
  ctx = canvasRef.value.getContext('2d')
  syncMotionPreference()
  handleResize()

  window.addEventListener('resize', handleResize)
  window.addEventListener('click', handleClick)

  motionQuery = window.matchMedia('(prefers-reduced-motion: reduce)')
  motionQuery.addEventListener('change', onMotionChange)

  // Always run ambient layer for both themes (static draw when reduced motion)
  startLoop()
})

watch(resolvedTheme, () => {
  clearPools()
  initForTheme()
  if (!running) startLoop()
})

onUnmounted(() => {
  stopLoop()
  window.removeEventListener('resize', handleResize)
  window.removeEventListener('click', handleClick)
  motionQuery?.removeEventListener('change', onMotionChange)
})
</script>

<style scoped>
canvas {
  display: block;
}
</style>
