<template>
  <div>
    <a-button type="primary" @click="startRecording" :disabled="isRecording">开始录音</a-button>
    <a-button type="primary" @click="stopRecording" :disabled="!isRecording">停止录音</a-button>
    <!--    <audio v-if="audioUrl" :src="audioUrl" controls></audio>-->
  </div>
</template>

<script>
import { getConfigByName } from '@vue2-client/services/api/common'
export default {
  name: 'PersonSetting',
  data () {
    return {
      isRecording: false, // 标识是否正在录音
      mediaRecorder: null, // MediaRecorder 实例
      audioChunks: [], // 存储录音数据块
      audioUrl: null, // 录音生成的 URL
      inputData: '',
      config: {}
    }
  },
  props: {},
  watch: {},
  components: {},
  created () {
    getConfigByName('V4RecodingConfig', undefined, (x) => {
      Object.assign(this.config, x)
    })
  },
  methods: {
    async startRecording () {
      this.inputData = ''
      this.audioChunks = []
      const url = this.config.webSocketURL ? this.config.webSocketURL : 'ws://192.168.50.67:31090/websocket/bash' // WebSocket地址
      this.setupWebSocket(url)

      // 等待 WebSocket 连接成功
      await this.waitForWebSocketConnection()

      this.isRecording = true

      // 初始化 AudioContext
      this.audioContext = new (window.AudioContext || window.webkitAudioContext)()

      if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
        throw new Error(
          '录音软件不支持您的浏览器！请使用现代浏览器或确保您正在使用 HTTPS。'
        )
      }

      // 获取麦克风输入流
      this.audioStream = await navigator.mediaDevices.getUserMedia({ audio: true })

      // 设置音频处理流程
      this.setupAudioProcessing()
    },
    setupWebSocket (url) {
      this.ws = new WebSocket(url)

      this.ws.onmessage = (event) => {
        const data = JSON.parse(event.data)
        console.log('Result:', data.result)
        if (data.result !== undefined) {
          this.inputData += data.result
        }
        if (!this.isRecording) {
          this.ws.close()
          this.resRecordingData()
        }
      }

      this.ws.onclose = () => console.log('WebSocket closed.')
      this.ws.onerror = (error) => console.error('WebSocket error:', error)
    },

    waitForWebSocketConnection () {
      return new Promise((resolve, reject) => {
        this.ws.onopen = () => {
          console.log('WebSocket 连接成功')
          resolve()
        }

        this.ws.onerror = (error) => {
          reject(new Error('WebSocket 连接失败: ' + error.message))
        }
      })
    },

    setupAudioProcessing () {
      try {
        const source = this.audioContext.createMediaStreamSource(this.audioStream)
        const processor = this.audioContext.createScriptProcessor(4096, 1, 1)

        processor.onaudioprocess = (e) => {
          if (!this.isRecording) return

          const inputData = e.inputBuffer.getChannelData(0)

          // 收集音频数据块

          // Resample to 16000 Hz if needed
          const resampledData = this.resample(inputData, this.audioContext.sampleRate, 16000)

          this.audioChunks.push(new Float32Array(resampledData))

          // Convert to 16-bit PCM and send via WebSocket
          const byteArray = this.convertTo16BitPCM(resampledData)
          this.ws.send(byteArray)
        }

        source.connect(processor)
        processor.connect(this.audioContext.destination)
      } catch (error) {
        console.error('Error setting up audio processing:', error)
        throw error
      }
    },

    stopRecording () {
      this.isRecording = false

      // 停止麦克风流
      if (this.audioStream) {
        this.audioStream.getTracks().forEach((track) => track.stop())
      }

      // 合并音频数据块并保存为文件
      // this.saveAudioFile()

      // 关闭 WebSocket
      // if (this.ws) {
      //   this.ws.close()
      // }

      if (this.audioContext) {
        this.audioContext.close()
      }
    },

    saveAudioFile () {
      // 合并所有音频块
      const audioBuffer = this.mergeAudioChunks(this.audioChunks)

      // 转换为 WAV 格式
      const wavBlob = this.encodeWAV(audioBuffer, 16000)

      // 创建下载链接并触发下载
      const url = URL.createObjectURL(wavBlob)
      const a = document.createElement('a')
      a.style.display = 'none'
      a.href = url
      a.download = 'recording.wav'
      document.body.appendChild(a)
      a.click()
      window.URL.revokeObjectURL(url)
    },

    mergeAudioChunks (chunks) {
      const length = chunks.reduce((sum, chunk) => sum + chunk.length, 0)
      const result = new Float32Array(length)
      let offset = 0
      for (const chunk of chunks) {
        result.set(chunk, offset)
        offset += chunk.length
      }
      return result
    },

    encodeWAV (samples, sampleRate) {
      const buffer = new ArrayBuffer(44 + samples.length * 2) // 每个样本占2字节
      const view = new DataView(buffer)

      const writeString = (view, offset, string) => {
        for (let i = 0; i < string.length; i++) {
          view.setUint8(offset + i, string.charCodeAt(i))
        }
      }

      // WAV文件头
      writeString(view, 0, 'RIFF') // ChunkID
      view.setUint32(4, 36 + samples.length * 2, true) // ChunkSize
      writeString(view, 8, 'WAVE') // Format

      // fmt子块
      writeString(view, 12, 'fmt ') // Subchunk1ID
      view.setUint32(16, 16, true) // Subchunk1Size (PCM格式固定为16)
      view.setUint16(20, 1, true) // AudioFormat (PCM为1)
      view.setUint16(22, 1, true) // NumChannels (单声道为1)
      view.setUint32(24, sampleRate, true) // SampleRate
      view.setUint32(28, sampleRate * 2, true) // ByteRate (SampleRate * NumChannels * BitsPerSample/8)
      view.setUint16(32, 2, true) // BlockAlign (NumChannels * BitsPerSample/8)
      view.setUint16(34, 16, true) // BitsPerSample

      // data子块
      writeString(view, 36, 'data') // Subchunk2ID
      view.setUint32(40, samples.length * 2, true) // Subchunk2Size

      // 写入PCM数据
      let offset = 44
      for (let i = 0; i < samples.length; i++) {
        const s = Math.max(-1, Math.min(1, samples[i])) // 限制范围为[-1, 1]
        view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true) // 转换为16位PCM
        offset += 2
      }

      return new Blob([buffer], { type: 'audio/wav' })
    },

    resample (data, inputSampleRate, outputSampleRate) {
      if (inputSampleRate === outputSampleRate) {
        return data
      }
      const sampleRateRatio = inputSampleRate / outputSampleRate
      const newLength = Math.round(data.length / sampleRateRatio)
      const resampledData = new Float32Array(newLength)
      for (let i = 0; i < newLength; i++) {
        const index = Math.round(i * sampleRateRatio)
        resampledData[i] = data[index]
      }
      return resampledData
    },
    convertTo16BitPCM (data) {
      const output = new Int16Array(data.length)
      for (let i = 0; i < data.length; i++) {
        output[i] = Math.max(-1, Math.min(1, data[i])) * 0x7FFF
      }
      return new Uint8Array(output.buffer)
    },
    getRecordingData () {
      return this.inputData
    },
    resRecordingData () {
      this.$emit('recordingData', this.inputData)
    }
  }
}

</script>

<style lang="less" scoped>

</style>
