/**
 * 音频转换工具
 * 将录音数据转换为MP3格式
 */

// 动态导入lamejs库
let lamejs: any = null

const loadLamejs = async () => {
  if (!lamejs) {
    try {
      // 使用动态导入加载lamejs
      const lamejsModule = await import('lamejs')
      lamejs = lamejsModule.default || lamejsModule
    } catch (error) {
      console.error('Failed to load lamejs:', error)
      throw new Error('音频转换库加载失败')
    }
  }
  return lamejs
}

export interface AudioConverterOptions {
  sampleRate?: number
  bitRate?: number
  channels?: number
}

export class AudioConverter {
  private options: AudioConverterOptions

  constructor(options: AudioConverterOptions = {}) {
    this.options = {
      sampleRate: 44100,
      bitRate: 128,
      channels: 1,
      ...options,
    }
  }

  /**
   * 将AudioBuffer转换为MP3格式的Blob
   * @param audioBuffer 音频缓冲区
   * @returns Promise<Blob> MP3格式的Blob对象
   */
  async convertToMp3(audioBuffer: AudioBuffer): Promise<Blob> {
    try {
      const lame = await loadLamejs()

      // 获取音频数据
      const sampleRate = audioBuffer.sampleRate
      const channels = audioBuffer.numberOfChannels
      const length = audioBuffer.length

      // 创建左声道和右声道数据
      const leftChannel = new Int16Array(length)
      const rightChannel = channels > 1 ? new Int16Array(length) : leftChannel

      // 从AudioBuffer中提取数据
      const leftData = audioBuffer.getChannelData(0)
      for (let i = 0; i < length; i++) {
        leftChannel[i] = Math.max(-1, Math.min(1, leftData[i])) * 0x7fff
      }

      if (channels > 1) {
        const rightData = audioBuffer.getChannelData(1)
        for (let i = 0; i < length; i++) {
          rightChannel[i] = Math.max(-1, Math.min(1, rightData[i])) * 0x7fff
        }
      }

      // 创建MP3编码器
      const mp3Encoder = new lamejs.Mp3Encoder(channels, sampleRate, this.options.bitRate)

      // 编码音频数据
      const mp3Data: Int8Array[] = []
      const blockSize = 1152 // MP3编码的块大小

      for (let i = 0; i < length; i += blockSize) {
        const leftChunk = leftChannel.subarray(i, i + blockSize)
        const rightChunk = channels > 1 ? rightChannel.subarray(i, i + blockSize) : leftChunk

        const mp3buf = mp3Encoder.encodeBuffer(leftChunk, rightChunk)
        if (mp3buf.length > 0) {
          mp3Data.push(mp3buf)
        }
      }

      // 完成编码
      const finalMp3buf = mp3Encoder.flush()
      if (finalMp3buf.length > 0) {
        mp3Data.push(finalMp3buf)
      }

      // 合并所有MP3数据
      const totalLength = mp3Data.reduce((sum, chunk) => sum + chunk.length, 0)
      const mergedArray = new Uint8Array(totalLength)
      let offset = 0

      for (const chunk of mp3Data) {
        mergedArray.set(chunk, offset)
        offset += chunk.length
      }

      return new Blob([mergedArray], { type: 'audio/mp3' })
    } catch (error) {
      console.error('音频转换失败:', error)
      throw new Error('音频转换为MP3格式失败')
    }
  }

  /**
   * 将Blob转换为AudioBuffer
   * @param blob 音频Blob
   * @returns Promise<AudioBuffer> 音频缓冲区
   */
  async blobToAudioBuffer(blob: Blob): Promise<AudioBuffer> {
    try {
      const arrayBuffer = await blob.arrayBuffer()
      const audioContext = new AudioContext()
      return await audioContext.decodeAudioData(arrayBuffer)
    } catch (error) {
      console.error('Blob转换为AudioBuffer失败:', error)
      throw new Error('音频数据解析失败')
    }
  }

  /**
   * 将WebM/OGG格式的录音数据转换为MP3
   * @param audioBlob 原始录音Blob
   * @returns Promise<Blob> MP3格式的Blob
   */
  async convertRecordingToMp3(audioBlob: Blob): Promise<Blob> {
    try {
      // 首先将Blob转换为AudioBuffer
      const audioBuffer = await this.blobToAudioBuffer(audioBlob)

      // 然后转换为MP3
      return await this.convertToMp3(audioBuffer)
    } catch (error) {
      console.error('录音转换为MP3失败:', error)
      throw new Error('录音转换为MP3格式失败')
    }
  }

  /**
   * 检查浏览器是否支持MP3编码
   * @returns boolean 是否支持
   */
  static async isMp3Supported(): Promise<boolean> {
    try {
      await loadLamejs()
      return true
    } catch (error) {
      return false
    }
  }
}

/**
 * 创建音频转换器实例
 * @param options 转换选项
 * @returns AudioConverter 转换器实例
 */
export const createAudioConverter = (options?: AudioConverterOptions): AudioConverter => {
  return new AudioConverter(options)
}

/**
 * 快速转换录音为MP3
 * @param audioBlob 录音Blob
 * @param options 转换选项
 * @returns Promise<Blob> MP3格式的Blob
 */
export const convertToMp3 = async (
  audioBlob: Blob,
  options?: AudioConverterOptions
): Promise<Blob> => {
  const converter = createAudioConverter(options)
  return await converter.convertRecordingToMp3(audioBlob)
}
