declare global {
  interface Window {
    lamejs: any
  }
}

export async function loadLameJS(): Promise<boolean> {
  if (typeof window === "undefined") return false

  if (window.lamejs) {
    return true
  }

  return new Promise<boolean>((resolve) => {
    const script = document.createElement("script")
    script.src = "https://cdn.jsdelivr.net/npm/lamejs@1.2.1/lame.min.js"
    script.onload = () => resolve(true)
    script.onerror = () => {
      console.error("[v0] Failed to load lamejs")
      resolve(false)
    }
    document.head.appendChild(script)
  })
}

interface CompressionResult {
  blob: Blob
  originalSize: number
  compressedSize: number
  ratio: number
}

export async function compressAudioToTarget(file: File, targetSizeBytes = 2940000): Promise<CompressionResult> {
  console.log("[v0] Starting silent audio compression:", {
    filename: file.name,
    originalSize: (file.size / (1024 * 1024)).toFixed(2) + "MB",
    targetSize: (targetSizeBytes / (1024 * 1024)).toFixed(2) + "MB",
  })

  // Load lamejs if not already loaded
  const loaded = await loadLameJS()
  if (!loaded) {
    throw new Error("Failed to load MP3 encoder")
  }

  return new Promise((resolve, reject) => {
    const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()
    const reader = new FileReader()

    reader.onload = async (e) => {
      try {
        const arrayBuffer = e.target?.result as ArrayBuffer
        const audioBuffer = await audioContext.decodeAudioData(arrayBuffer)

        // Calculate compression settings to achieve target size
        const durationSeconds = audioBuffer.duration
        const targetBitrateKbps = Math.min(
          64, // Max 64kbps for aggressive compression to hit 2.8MB target
          Math.floor((targetSizeBytes * 8) / (durationSeconds * 1000)),
        )

        const settings = {
          bitrate: Math.max(32, targetBitrateKbps), // Min 32kbps for acceptable quality
          sampleRate: 22050, // Lower sample rate for smaller size
          channels: 1, // Mono for maximum compression
        }

        console.log("[v0] Compression settings:", settings)

        // Create offline context for resampling
        const offlineContext = new OfflineAudioContext(
          settings.channels,
          Math.ceil(audioBuffer.duration * settings.sampleRate),
          settings.sampleRate,
        )

        const source = offlineContext.createBufferSource()
        source.buffer = audioBuffer

        // Convert to mono
        const merger = offlineContext.createChannelMerger(1)
        source.connect(merger)
        merger.connect(offlineContext.destination)

        source.start(0)
        const renderedBuffer = await offlineContext.startRendering()

        // Encode to MP3
        const mp3Blob = encodeMP3(renderedBuffer, settings.bitrate)

        audioContext.close()

        const result: CompressionResult = {
          blob: mp3Blob,
          originalSize: file.size,
          compressedSize: mp3Blob.size,
          ratio: mp3Blob.size / file.size,
        }

        console.log("[v0] Compression complete:", {
          originalSize: (result.originalSize / (1024 * 1024)).toFixed(2) + "MB",
          compressedSize: (result.compressedSize / (1024 * 1024)).toFixed(2) + "MB",
          ratio: (result.ratio * 100).toFixed(1) + "%",
          reduction: ((1 - result.ratio) * 100).toFixed(1) + "%",
        })

        resolve(result)
      } catch (error) {
        audioContext.close()
        reject(error)
      }
    }

    reader.onerror = () => reject(new Error("Failed to read file"))
    reader.readAsArrayBuffer(file)
  })
}

function encodeMP3(audioBuffer: AudioBuffer, bitrate: number): Blob {
  const numChannels = audioBuffer.numberOfChannels
  const sampleRate = audioBuffer.sampleRate
  const samples = audioBuffer.length

  // Initialize MP3 encoder
  const mp3encoder = new window.lamejs.Mp3Encoder(numChannels, sampleRate, bitrate)
  const mp3Data: Int8Array[] = []

  // Get audio data
  const left = audioBuffer.getChannelData(0)
  const right = numChannels > 1 ? audioBuffer.getChannelData(1) : null

  // Convert Float32 to Int16
  const leftInt16 = new Int16Array(samples)
  const rightInt16 = right ? new Int16Array(samples) : null

  for (let i = 0; i < samples; i++) {
    leftInt16[i] = Math.max(-32768, Math.min(32767, Math.floor(left[i] * 32767)))
    if (rightInt16 && right) {
      rightInt16[i] = Math.max(-32768, Math.min(32767, Math.floor(right[i] * 32767)))
    }
  }

  // Encode in chunks
  const sampleBlockSize = 1152
  for (let i = 0; i < samples; i += sampleBlockSize) {
    const leftChunk = leftInt16.subarray(i, i + sampleBlockSize)
    const rightChunk = rightInt16 ? rightInt16.subarray(i, i + sampleBlockSize) : null

    let mp3buf: Int8Array
    if (numChannels === 1) {
      mp3buf = mp3encoder.encodeBuffer(leftChunk)
    } else {
      mp3buf = mp3encoder.encodeBuffer(leftChunk, rightChunk)
    }

    if (mp3buf.length > 0) {
      mp3Data.push(mp3buf)
    }
  }

  // Flush remaining data
  const mp3buf = mp3encoder.flush()
  if (mp3buf.length > 0) {
    mp3Data.push(mp3buf)
  }

  // Combine all chunks
  const totalLength = mp3Data.reduce((sum, chunk) => sum + chunk.length, 0)
  const mp3Array = new Uint8Array(totalLength)
  let offset = 0
  for (const chunk of mp3Data) {
    mp3Array.set(chunk, offset)
    offset += chunk.length
  }

  return new Blob([mp3Array], { type: "audio/mp3" })
}
