<template>
  <canvas
    ref="canvasRef"
    class="h-12 w-full rounded-lg opacity-60"
  />
</template>

<script setup lang="ts">
const canvasRef = ref<HTMLCanvasElement | null>(null)
const store = usePlayerStore()
const { getAudio } = useAudioPlayer()

let audioContext: AudioContext | null = null
let analyser: AnalyserNode | null = null
let source: MediaElementAudioSourceNode | null = null
let animId: number | null = null
let connected = false

function initAnalyser() {
  if (connected || !canvasRef.value) return

  try {
    const audio = getAudio()
    audioContext = new AudioContext()
    analyser = audioContext.createAnalyser()
    analyser.fftSize = 64
    source = audioContext.createMediaElementSource(audio)
    source.connect(analyser)
    analyser.connect(audioContext.destination)
    connected = true
  }
  catch {
    // Web Audio API might not be available
  }
}

function draw() {
  if (!canvasRef.value || !analyser) {
    animId = requestAnimationFrame(draw)
    return
  }

  const canvas = canvasRef.value
  const ctx = canvas.getContext('2d')
  if (!ctx) return

  const bufferLength = analyser.frequencyBinCount
  const dataArray = new Uint8Array(bufferLength)
  analyser.getByteFrequencyData(dataArray)

  canvas.width = canvas.offsetWidth * window.devicePixelRatio
  canvas.height = canvas.offsetHeight * window.devicePixelRatio
  ctx.scale(window.devicePixelRatio, window.devicePixelRatio)

  const width = canvas.offsetWidth
  const height = canvas.offsetHeight

  ctx.clearRect(0, 0, width, height)

  const barWidth = width / bufferLength
  const gap = 2

  for (let i = 0; i < bufferLength; i++) {
    const barHeight = (dataArray[i] / 255) * height
    const x = i * (barWidth + gap)

    const gradient = ctx.createLinearGradient(0, height, 0, height - barHeight)
    gradient.addColorStop(0, 'hsl(12, 76%, 48%)')
    gradient.addColorStop(1, 'hsl(36, 80%, 52%)')

    ctx.fillStyle = gradient
    ctx.fillRect(x, height - barHeight, barWidth, barHeight)
  }

  animId = requestAnimationFrame(draw)
}

watch(() => store.isPlaying, (playing) => {
  if (playing) {
    initAnalyser()
    if (!animId) draw()
    if (audioContext?.state === 'suspended') {
      audioContext.resume()
    }
  }
})

onUnmounted(() => {
  if (animId) cancelAnimationFrame(animId)
})
</script>
