/**
 * Create WAV buffer from audio data
 */
export function createWAVBuffer(audioData: Float32Array, sampleRate: number): ArrayBuffer {
  const length = audioData.length
  const buffer = new ArrayBuffer(44 + length * 2)
  const view = new DataView(buffer)

  // WAV header
  writeString(view, 0, 'RIFF')
  view.setUint32(4, 36 + length * 2, true) // file length - 8
  writeString(view, 8, 'WAVE')
  writeString(view, 12, 'fmt ')
  view.setUint32(16, 16, true) // format chunk length
  view.setUint16(20, 1, true) // PCM format
  view.setUint16(22, 1, true) // mono
  view.setUint32(24, sampleRate, true)
  view.setUint32(28, sampleRate * 2, true) // byte rate
  view.setUint16(32, 2, true) // block align
  view.setUint16(34, 16, true) // bits per sample
  writeString(view, 36, 'data')
  view.setUint32(40, length * 2, true) // data chunk length

  // Convert float samples to 16-bit PCM
  let offset = 44
  for (let i = 0; i < length; i++) {
    const sample = Math.max(-1, Math.min(1, audioData[i]))
    view.setInt16(offset, sample * 0x7FFF, true)
    offset += 2
  }

  return buffer
}

function writeString(view: DataView, offset: number, string: string) {
  for (let i = 0; i < string.length; i++) {
    view.setUint8(offset + i, string.charCodeAt(i))
  }
}

/**
 * Download audio as WAV file
 */
export function downloadWAV(audioData: Float32Array, sampleRate: number, filename: string) {
  const buffer = createWAVBuffer(audioData, sampleRate)
  const blob = new Blob([buffer], { type: 'audio/wav' })
  const url = URL.createObjectURL(blob)

  const a = document.createElement('a')
  a.href = url
  a.download = filename
  a.click()

  URL.revokeObjectURL(url)
}

/**
 * Play audio in browser
 */
export async function playAudio(audioData: Float32Array, sampleRate: number): Promise<void> {
  const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()

  if (audioContext.sampleRate !== sampleRate) {
    console.warn(`Audio context sample rate (${audioContext.sampleRate}) differs from data sample rate (${sampleRate})`)
  }

  const buffer = audioContext.createBuffer(1, audioData.length, sampleRate)
  buffer.copyToChannel(audioData, 0)

  const source = audioContext.createBufferSource()
  source.buffer = buffer
  source.connect(audioContext.destination)
  source.start()

  return new Promise(resolve => {
    source.onended = () => resolve()
  })
}