<template>
  <div class="audio-recorder">
    <!-- 录制状态显示 -->
    <div class="recorder-status" v-if="isRecording || hasRecording">
      <div class="status-info">
        <div class="status-icon">
          <div v-if="isRecording" class="recording-dot"></div>
          <div v-else-if="hasRecording" class="playback-icon">▶</div>
        </div>
        <div class="status-text">
          <span v-if="isRecording">正在录制...</span>
          <span v-else-if="hasRecording">录制完成</span>
        </div>
        <div class="recording-time" v-if="isRecording || hasRecording">
          {{ formatTime(recordingTime) }}
        </div>
      </div>
    </div>

    <!-- 音频可视化 -->
    <div class="audio-visualizer" v-if="isRecording || hasRecording">
      <div class="visualizer-container">
        <div
          v-for="(bar, index) in audioBars"
          :key="index"
          class="audio-bar"
          :style="{ height: bar.height + 'px' }"
        ></div>
      </div>
    </div>

    <!-- 控制按钮 -->
    <div class="recorder-controls">
      <button
        v-if="!isRecording && !hasRecording"
        @click="startRecording"
        class="record-btn start-btn"
        :disabled="!isSupported"
      >
        <div class="btn-icon">🎤</div>
        <span>开始录制</span>
      </button>

      <button
        v-if="isRecording"
        @click="stopRecording"
        class="record-btn stop-btn"
      >
        <div class="btn-icon">⏹</div>
        <span>停止录制</span>
      </button>

      <div v-if="hasRecording" class="playback-controls">
        <button @click="playRecording" class="control-btn play-btn" :disabled="isPlaying">
          <div class="btn-icon">{{ isPlaying ? '⏸' : '▶' }}</div>
        </button>
        
        <button @click="pauseRecording" class="control-btn pause-btn" :disabled="!isPlaying">
          <div class="btn-icon">⏸</div>
        </button>
        
        <button @click="downloadRecording" class="control-btn download-btn">
          <div class="btn-icon">💾</div>
        </button>
        
        <button @click="deleteRecording" class="control-btn delete-btn">
          <div class="btn-icon">🗑</div>
        </button>
      </div>
    </div>

    <!-- 音频播放器 -->
    <audio
      ref="audioPlayer"
      @ended="onPlaybackEnded"
      @timeupdate="onTimeUpdate"
      style="display: none"
    ></audio>

    <!-- 错误提示 -->
    <div v-if="error" class="error-message">
      {{ error }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from 'vue'

// 定义事件
const emit = defineEmits<{
  'recording-started': []
  'recording-stopped': [audioBlob: Blob]
  'recording-deleted': []
}>()

// 响应式数据
const isRecording = ref(false)
const hasRecording = ref(false)
const isPlaying = ref(false)
const recordingTime = ref(0)
const error = ref('')
const isSupported = ref(false)

// 音频相关
let mediaRecorder: MediaRecorder | null = null
let audioChunks: Blob[] = []
let audioBlob: Blob | null = null
let recordingStartTime = 0
let recordingTimer: number | null = null

// 音频可视化
const audioBars = ref<Array<{ height: number }>>([])
let animationFrame: number | null = null
let audioContext: AudioContext | null = null
let analyser: AnalyserNode | null = null
let microphone: MediaStreamAudioSourceNode | null = null
let dataArray: Uint8Array | null = null

// DOM 引用
const audioPlayer = ref<HTMLAudioElement>()

// 计算属性
const formatTime = (seconds: number): string => {
  const mins = Math.floor(seconds / 60)
  const secs = Math.floor(seconds % 60)
  return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}

// 检查浏览器支持
const checkSupport = () => {
  isSupported.value = !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia)
  if (!isSupported.value) {
    error.value = '您的浏览器不支持音频录制功能'
  }
}

// 初始化音频可视化
const initAudioVisualizer = async () => {
  if (!isRecording.value) return

  try {
    audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()
    analyser = audioContext.createAnalyser()
    analyser.fftSize = 256

    const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
    microphone = audioContext.createMediaStreamSource(stream)
    microphone.connect(analyser)

    dataArray = new Uint8Array(analyser.frequencyBinCount)
    updateVisualizer()
  } catch (err) {
    console.error('初始化音频可视化失败:', err)
  }
}

// 更新音频可视化
const updateVisualizer = () => {
  if (!analyser || !dataArray || !isRecording.value) return

  analyser.getByteFrequencyData(dataArray)
  
  // 创建音频条
  const barCount = 20
  const newBars: Array<{ height: number }> = []
  
  for (let i = 0; i < barCount; i++) {
    const dataIndex = Math.floor((i / barCount) * dataArray.length)
    const value = dataArray[dataIndex]
    const height = Math.max(4, (value / 255) * 60) // 最小高度4px，最大60px
    newBars.push({ height })
  }
  
  audioBars.value = newBars
  animationFrame = requestAnimationFrame(updateVisualizer)
}

// 停止音频可视化
const stopAudioVisualizer = () => {
  if (animationFrame) {
    cancelAnimationFrame(animationFrame)
    animationFrame = null
  }
  
  if (microphone) {
    microphone.disconnect()
    microphone = null
  }
  
  if (audioContext) {
    audioContext.close()
    audioContext = null
  }
  
  audioBars.value = []
}

// 开始录制
const startRecording = async () => {
  try {
    error.value = ''
    
    const stream = await navigator.mediaDevices.getUserMedia({ 
      audio: {
        echoCancellation: true,
        noiseSuppression: true,
        autoGainControl: true
      } 
    })
    
    mediaRecorder = new MediaRecorder(stream, {
      mimeType: 'audio/webm;codecs=opus'
    })
    
    audioChunks = []
    
    mediaRecorder.ondataavailable = (event) => {
      if (event.data.size > 0) {
        audioChunks.push(event.data)
      }
    }
    
    mediaRecorder.onstop = () => {
      audioBlob = new Blob(audioChunks, { type: 'audio/webm' })
      hasRecording.value = true
      emit('recording-stopped', audioBlob)
      
      // 停止所有音频流
      stream.getTracks().forEach(track => track.stop())
    }
    
    mediaRecorder.start(100) // 每100ms收集一次数据
    isRecording.value = true
    recordingStartTime = Date.now()
    recordingTime.value = 0
    
    // 开始计时
    recordingTimer = window.setInterval(() => {
      recordingTime.value = Math.floor((Date.now() - recordingStartTime) / 1000)
    }, 1000)
    
    // 初始化音频可视化
    await initAudioVisualizer()
    
    emit('recording-started')
  } catch (err) {
    console.error('开始录制失败:', err)
    error.value = '无法访问麦克风，请检查权限设置'
  }
}

// 停止录制
const stopRecording = () => {
  if (mediaRecorder && isRecording.value) {
    mediaRecorder.stop()
    isRecording.value = false
    
    if (recordingTimer) {
      clearInterval(recordingTimer)
      recordingTimer = null
    }
    
    stopAudioVisualizer()
  }
}

// 播放录制
const playRecording = () => {
  if (audioBlob && audioPlayer.value) {
    const audioUrl = URL.createObjectURL(audioBlob)
    audioPlayer.value.src = audioUrl
    audioPlayer.value.play()
    isPlaying.value = true
  }
}

// 暂停播放
const pauseRecording = () => {
  if (audioPlayer.value) {
    audioPlayer.value.pause()
    isPlaying.value = false
  }
}

// 播放结束
const onPlaybackEnded = () => {
  isPlaying.value = false
}

// 时间更新
const onTimeUpdate = () => {
  // 可以在这里添加播放进度更新逻辑
}

// 下载录制
const downloadRecording = () => {
  if (audioBlob) {
    const url = URL.createObjectURL(audioBlob)
    const a = document.createElement('a')
    a.href = url
    a.download = `recording-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.webm`
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
    URL.revokeObjectURL(url)
  }
}

// 删除录制
const deleteRecording = () => {
  hasRecording.value = false
  audioBlob = null
  isPlaying.value = false
  
  if (audioPlayer.value) {
    audioPlayer.value.src = ''
  }
  
  emit('recording-deleted')
}

// 组件挂载
onMounted(() => {
  checkSupport()
})

// 组件卸载
onUnmounted(() => {
  if (isRecording.value) {
    stopRecording()
  }
  stopAudioVisualizer()
  
  if (recordingTimer) {
    clearInterval(recordingTimer)
  }
})

// 暴露方法给父组件
defineExpose({
  startRecording,
  stopRecording,
  playRecording,
  pauseRecording,
  downloadRecording,
  deleteRecording,
  hasRecording: computed(() => hasRecording.value),
  isRecording: computed(() => isRecording.value),
  audioBlob: computed(() => audioBlob)
})
</script>

<style scoped>
.audio-recorder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  padding: 20px;
  background: #f8f9fa;
  border-radius: 12px;
  border: 1px solid #e9ecef;
}

.recorder-status {
  width: 100%;
  max-width: 300px;
}

.status-info {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.status-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
}

.recording-dot {
  width: 12px;
  height: 12px;
  background: #ff4757;
  border-radius: 50%;
  animation: pulse 1s infinite;
}

.playback-icon {
  color: #2ed573;
  font-size: 16px;
}

.status-text {
  flex: 1;
  font-weight: 500;
  color: #2c3e50;
}

.recording-time {
  font-family: 'Courier New', monospace;
  font-weight: 600;
  color: #7f8c8d;
  background: #ecf0f1;
  padding: 4px 8px;
  border-radius: 4px;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

.audio-visualizer {
  width: 100%;
  max-width: 300px;
  height: 80px;
  background: white;
  border-radius: 8px;
  padding: 16px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.visualizer-container {
  display: flex;
  align-items: end;
  justify-content: center;
  gap: 2px;
  height: 100%;
}

.audio-bar {
  width: 8px;
  background: linear-gradient(to top, #ff6b6b, #ffa726);
  border-radius: 4px;
  transition: height 0.1s ease;
  min-height: 4px;
}

.recorder-controls {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
}

.record-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 24px;
  border: none;
  border-radius: 8px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  min-width: 140px;
  justify-content: center;
}

.start-btn {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
}

.start-btn:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}

.stop-btn {
  background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
  color: white;
}

.stop-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(255, 107, 107, 0.4);
}

.record-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none !important;
}

.playback-controls {
  display: flex;
  gap: 8px;
}

.control-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  transition: all 0.2s ease;
}

.play-btn {
  background: linear-gradient(135deg, #2ed573 0%, #1e90ff 100%);
  color: white;
}

.pause-btn {
  background: linear-gradient(135deg, #ffa726 0%, #ff6b6b 100%);
  color: white;
}

.download-btn {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
}

.delete-btn {
  background: linear-gradient(135deg, #ff4757 0%, #c44569 100%);
  color: white;
}

.control-btn:hover:not(:disabled) {
  transform: scale(1.1);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

.control-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none !important;
}

.btn-icon {
  font-size: 16px;
}

.error-message {
  color: #e74c3c;
  background: #fdf2f2;
  border: 1px solid #fecaca;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 14px;
  text-align: center;
  max-width: 300px;
}
</style>
