<template>
  <div class="main_box">
    <navbar title="录音测试"></navbar>
    <div style="margin-top: 50px"></div>
    <van-button v-if="!hasPermission && canRequestPermission" @click="requestMicrophonePermission" type="primary" style="margin: 20px">
      授权麦克风
    </van-button>
    <van-button v-if="hasPermission" :disabled="!canRecord||isRequestingPermission" @click="toggleRecording" type="primary" style="margin: 20px">
      {{ isRecording ? '结束录音' : '开始录音' }}
    </van-button>
    <!-- 播放区域 -->
    <div v-if="audioUrl" class="play-section">
      <van-button @click="playAudio" style="margin: 0 20px">播放</van-button>
      <audio ref="audioPlayer" :src="audioUrl" controls style="display: none"></audio>
    </div>
    <div style="margin: 20px">
      <span>录音结果：</span>
      <span>{{ text }}</span>
    </div>
    

    <!-- 状态提示 -->
    <p v-if="errorMessage" class="error">{{ errorMessage }}</p>
    <p v-else-if="!canRecord" class="warn">当前设备不支持录音或未通过 HTTPS 访问</p>
  </div>
</template>

<script>
import navbar from "../../../components/navbar/navbar.vue";
import { audioUpload, audioGet } from "@/service/api/record.js";
import {
  Tab,
  Tabs,
  Icon,
  Button,
  Search,
  RadioGroup,
  Radio,
  List,
  PullRefresh,
  Dialog,
  Toast,
} from "vant";
export default {
  name: 'AudioRecorder',
  components: {
    navbar: navbar,
    VanTab: Tab,
    VanTabs: Tabs,
    VanIcon: Icon,
    VanButton: Button,
    VanSearch: Search,
    VanRadioGroup: RadioGroup,
    VanRadio: Radio,
    VanList: List,
    VanPullRefresh: PullRefresh,
    VanToast: Toast,
    [Dialog.Component.name]: Dialog.Component,
  },
  data() {
    return {
      hasPermission: false,
      canRequestPermission: false,
      isRecording: false,
      audioUrl: null,
      mediaRecorder: null,
      stream: null,
      errorMessage: '',
      canRecord: false,
      stream: null,
      isRequestingPermission: false,
      Lame: null,
      error: '',
      isProcessing: false,
      recordedChunks: [],
      isPolling: false,
      startTime: null,
      pollTimer: null,
      text: ''
    }
  },
  async mounted() {
    this.checkCompatibility()
    // 懒加载lamejs，避免阻塞首屏
    try {
      const lameModule = await import('lamejs')
      this.Lame = lameModule.default
    } catch (err) {
      this.error = 'MP3 编码器加载失败'
      console.error(err)
    }
  },
  beforeUnmount() {
    // 组件销毁前清理资源
    this.stopRecordingSilent()
  },
  methods: {
    // 检查浏览器是否支持录音
    checkCompatibility() {
      const isHttps = location.protocol === 'http:';// s
      const hasMediaDevices = !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
      const inWeCom = /wxwork/i.test(navigator.userAgent);
      this.canRecord = isHttps && hasMediaDevices;//  && inWeCom
      this.canRequestPermission = this.canRecord
      console.log(this.canRequestPermission, !this.hasPermission)
    },
    // 主动请求麦克风权限
    async requestMicrophonePermission() {
      try {
        // 请求音频流
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true })

        // 保存stream引用
        this.stream = stream;
        this.hasPermission = true;
        this.errorMessage = '';

        console.log('麦克风权限已获得')
      } catch(err) {
        this.handleError('麦克风授权失败：'+(err.message||'用户拒绝或设备不支持'));
        this.hasPermission = false
      }
    },
    // 获取支持的 MIME 类型
  getSupportedMimeType() {
    const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
    if (isIOS) {
      // iOS 优先使用 MP4 (AAC)
      if (MediaRecorder.isTypeSupported('audio/mp4')) return 'audio/mp4';
      if (MediaRecorder.isTypeSupported('audio/aac')) return 'audio/aac';
    } else {
      // Android / 其他
      if (MediaRecorder.isTypeSupported('audio/webm')) return 'audio/webm';
      if (MediaRecorder.isTypeSupported('audio/ogg')) return 'audio/ogg';
    }
    return ''; // 使用默认
  },

  async toggleRecording() {
    if (this.isRecording) {
      this.stopRecording()
    } else {
      await this.startRecording()
    }
  },

  async convertToMp3() {
    this.isProcessing = true
    this.error = ''
    console.log(123456)
    try {
      const blob = new Blob(this.recordedChunks, { type: 'audio/webm' });
      const arrayBuffer = await blob.arrayBuffer();

      // 使用Web Audio API 解码为PCM
      const AudioContext = window.AudioContext || window.webkitAudioContext;
      const audioCtx = new AudioContext();
      const audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);

      // 转化为Int16 PCM(单声道)
      const channelData = audioBuffer.getChannelData(0);
      const samples = this.Float32ToInt16(channelData);

      // 创建MP3编码器
      const mp3Encoder = new this.Lame.Mp3Encoder(1, audioBuffer.sampleRate, 128);
      const maxSamples = 1152;
      const mp3Chunks = [];

      for (let i = 0; i < samples.length; i += maxSamples) {
        const chunk = samples.slice(i, i + maxSamples);
        const mp3Buf = mp3Encoder.encodeBuffer(chunk);
        if (mp3Buf.length > 0) mp3Chunks.push(mp3Buf);
      }

      const lastChunk = mp3Encoder.flush();
      if (lastChunk.length > 0) mp3Chunks.push(lastChunk);

      const mp3Array = this.concatTypedArray(mp3Chunks);
      const mp3Blob = new Blob([mp3Array], {type:'audio/mp3'})

      // 生成URL和File对象
      this.audioUrl = URL.createObjectURL(mp3Blob);
      const mp3File = new File([mp3Blob], `voice_${Date.now()}.mp3`, {type:'audio/mp3'})

      this.uploadMp3(mp3File)
    } catch (err) {
      this.error = 'MP3转码失败：' + (err.message || '');
      console.error(err)
    } finally {
      this.isProcessing = false;
      if(this.stream) {
        this.stream.getTracks().forEach(track => track.stop());
        this.stream = null
      }
    }
  },

  Float32ToInt16(float32Array) {
    const int16Array = new Int16Array(float32Array.length)
    for (let i = 0; i < float32Array.length; i++) {
      const s = Math.max(-1, Math.min(1, float32Array[i]));
      int16Array[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
    }
    return int16Array;
  },

  concatTypedArray(arrays) {
    let totalLength = 0;
    arrays.forEach(arr => totalLength += arr.length);
    const result = new Uint8Array(totalLength);
    let offset = 0;
    arrays.forEach(arr => {
      result.set(arr, offset);
      offset += arr.length;
    });
    return result;
  },

  uploadMp3(mp3File) {
    console.log(mp3File, this.audioUrl)
    const formData = new FormData()
    formData.append('file' ,mp3File)
    audioUpload(formData).then(res => {
      this.getText(res.msg)
    })
  },

  async getText(uuid) {
    if (this.isPolling) return;
    this.isPolling = true;
    this.startTime = Date.now();

    this.poll(uuid)
  },

  async poll(uuid) {
    try {
      if(Date.now() - this.startTime > 30000) {
        console.error('超时')
        this.error = '超时'
        this.isPolling = false;
        this.clearTimer()
        return;
      }
      audioGet(uuid).then(res => {
        if (res.code === '000') {
          if(this.isPolling) {
            this.pollTimer = setTimeout(() => {
              this.poll(uuid);
            }, 1000)
          }
        } else if (res.code === 200) {
          this.isProcessing = false;
          this.isPolling = false
          this.text = res.msg;
          console.log(this.text)
          this.clearTimer();
          this.$message.success('处理完成')
        }
      })
    } catch (err) {
      this.isPolling = false;
      this.clearTimer()
      console.error('轮询出错')
    }
  },

  clearTimer() {
    if (this.pollTimer) {
      clearTimeout(this.pollTimer);
      this.pollTimer = null
    }
  },

  // 开始录音
  async startRecording() {
    if (!this.Lame) {
      this.error = '编码器未就绪'
      return;
    }
    if (this.isRequestingPermission) return;

    this.errorMessage = '';
    this.isRequestingPermission = true;
    this.text = ''
    try {
      // 请求麦克风权限（必须由用户手势触发）
      this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });

      const mimeType = this.getSupportedMimeType();
      const options = mimeType ? { mimeType } : {};
      this.mediaRecorder = new MediaRecorder(this.stream, options);

      const audioChunks = [];

      this.mediaRecorder.ondataavailable = (event) => {
        if (event.data.size > 0) {
          audioChunks.push(event.data);
        }
      };
      this.recordedChunks = audioChunks

      this.mediaRecorder.onstop = () => {
        console.log(321)
        this.convertToMp3()
        const blob = new Blob(audioChunks, { type: mimeType || 'audio/webm' });
        this.audioUrl = URL.createObjectURL(blob);
        this.isRecording = false;

        this.isRequestingPermission = false
      };

      this.mediaRecorder.onerror = (e) => {
        this.handleError('录音过程中出错：' + (e.error?.message || '未知错误'));
        this.stopRecordingSilent();
      };

      // 开始录音
      this.mediaRecorder.start();
      this.isRecording = true;
      this.isRequestingPermission = false

      // 10 秒后自动停止
    //   setTimeout(() => {
    //     if (this.mediaRecorder && this.isRecording) {
    //       this.mediaRecorder.stop();
    //       this.stream?.getTracks().forEach(track => track.stop());
    //     }
    //   }, 10000);

    } catch (err) {
      this.handleError('无法访问麦克风：' + (err.message || '请检查权限设置'));
      this.isRecording = false;
      this.isRequestingPermission = false
    }
  },

  stopRecording() {
    if (this.mediaRecorder && this.isRecording) {
      this.mediaRecorder.stop()
    }
  },

  // 停止录音（无提示，用于 cleanup）
  stopRecordingSilent() {
    if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
      this.mediaRecorder.stop();
    }
    if (this.stream) {
      this.stream.getTracks().forEach(track => track.stop());
    }
    this.isRecording = false;
    this.isRequestingPermission = false
  },

  // 播放录音
  playAudio() {
    const player = this.$refs.audioPlayer;
    if (player) {
      player.currentTime = 0;
      console.log(player, this.audioUrl)
      player.play().catch(e => {
        console.warn('播放失败:', e);
      });
    }
  },

  // 错误处理
  handleError(message) {
    this.errorMessage = message;
    this.isRecording = false;
    // 可在此处上报错误日志
  }
  }
}
</script>

<style lang="less" scoped>
.main_box {
  position: relative;
  .backTop {
    position: fixed;
    bottom: 150px;
    right: 15px;
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: #4682ff;
    box-shadow: 0px -2px 6px 0px rgba(70, 130, 255, 1);
    color: #fff;
    transform: rotate(180deg);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    font-size: 20px;
    .heng {
      display: block;
      width: 15px;
      border: 1px solid #fff;
    }
  }
}
.audio-recorder {
  padding: 20px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

.btn {
  padding: 10px 20px;
  margin: 8px 0;
  border: none;
  border-radius: 4px;
  background: #f0f0f0;
  cursor: pointer;
}

.btn.primary {
  background: #07c160;
  color: white;
}

.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.play-section {
  margin-top: 16px;
}

.error {
  color: #f5222d;
  margin-top: 8px;
}

.warn {
  color: #faad14;
}
</style>