<template>
  <div class="voice-message" @click="togglePlay">
    <!-- 波形动画 -->
    <div class="wave">
      <span 
        v-for="i in 5"
        :key="i"
        class="bar"
        :style="{
          height: isPlaying ? `${randomHeights[i-1]}px` : `3px`
        }"
      ></span>
    </div>
    
    <!-- 时长显示 -->
    <span class="duration">{{ computedDuration }}″</span>
    
    <!-- 隐藏的audio元素 -->
    <audio
      ref="audioEl"
      :src="src"
      preload="metadata"
      @loadedmetadata="handleMetadata"
      @ended="handleEnded"
      @error="handleError"
    ></audio>
  </div>
</template>

<script setup> 

const props = defineProps({
  src: String,
  isSender: Boolean
})

const audioEl = ref(null)
const isPlaying = ref(false)
const rawDuration = ref(0)
const randomHeights = ref([6, 9, 12])
const animationFrame = ref(null)

// 计算后的时长（处理Infinity情况）
const computedDuration = computed(() => {
  return isFinite(rawDuration.value) ? Math.round(rawDuration.value) : '--'
})

// 初始化加载
onMounted(() => {
  loadAudio()
})

// 监听URL变化
watch(() => props.src, () =>{
  loadAudio()
})

// 加载音频
const loadAudio = async () => {
  if (!props.src) return
  
  try {
    // 重置audio元素
    if (audioEl.value) {
      audioEl.value.pause()
      audioEl.value.currentTime = 0
      audioEl.value.src = props.src
      await audioEl.value.load()
    }
    
    // 备用方案：如果loadedmetadata未触发
    setTimeout(() => {
      if (rawDuration.value === 0) {
        getDurationFallback()
      }
    }, 500)
  } catch (err) {
    console.error('音频加载失败:', err)
    getDurationFallback()
  }
}

// 正常获取时长
const handleMetadata = () => {
  if (audioEl.value && isFinite(audioEl.value.duration)) {
    rawDuration.value = audioEl.value.duration
  } else {
    getDurationFallback()
  }
}

// 备用方案：使用Web Audio API
const getDurationFallback = async () => {
  try {
    const dur = await getAudioDuration(props.src)
    if (dur > 0) rawDuration.value = dur
  } catch (err) {
    console.error('备用方案获取时长失败:', err)
  }
}

// Web Audio API实现
const getAudioDuration = (url) => {
  return new Promise((resolve) => {
    if (!url) return resolve(0)
    
    const audioContext = new (window.AudioContext || window.webkitAudioContext)()
    const request = new XMLHttpRequest()
    
    request.open('GET', url, true)
    request.responseType = 'arraybuffer'
    
    request.onload = () => {
      audioContext.decodeAudioData(
        request.response,
        (buffer) => resolve(buffer.duration),
        () => resolve(0)
      )
    }
    
    request.onerror = () => resolve(0)
    request.send()
  })
}

// 播放控制
const togglePlay = () => {
  if (!audioEl.value) return
  
  if (isPlaying.value) {
    audioEl.value.pause()
  } else {
    audioEl.value.play()
  }
  isPlaying.value = !isPlaying.value
  updateWaveAnimation()
}

// 波形动画
const updateWaveAnimation = () => {
  if (isPlaying.value) {
    cancelAnimationFrame(animationFrame.value)
    const animate = () => {
      randomHeights.value = [
        Math.random() * 9 + 6,
        Math.random() * 12 + 6,
        Math.random() * 9 + 6,
        Math.random() * 12 + 6,
        Math.random() * 9 + 6,
      ]
      animationFrame.value = requestAnimationFrame(animate)
    }
    animate()
  } else {
    cancelAnimationFrame(animationFrame.value)
    randomHeights.value = [6, 9, 12]
  }
}

// 音频结束处理
const handleEnded = () => {
  isPlaying.value = false
  updateWaveAnimation()
}

// 错误处理
const handleError = () => {
  console.error('音频播放错误')
  isPlaying.value = false
  updateWaveAnimation()
}

// 清理资源
onUnmounted(() => {
  cancelAnimationFrame(animationFrame.value)
  if (audioEl.value) {
    audioEl.value.pause()
    audioEl.value.src = ''
    audioEl.value.remove()
  }
})
</script>

<style lang="less" scoped>
.voice-message {
  display: inline-flex;
  align-items: center;
  padding: 8px 12px;
  border-radius: 5px;
  background-color: v-bind("isSender ? '#F5F5F5': '#E5F7FF' ");
  cursor: pointer;
  user-select: none;
  max-width: 200px;
  margin-top: 8px;
}

.wave {
  display: flex;
  align-items: flex-end;
  height: 100%;
  margin: 0 8px;
  gap: 3px;
  align-items: center;
}

.bar {
  display: flex;
  width: 2.5px;
  background-color:  v-bind("isSender ? '#2B87EB': '#07C160' ");
  border-radius: 2px;
  transition: height 0.15s ease-out;
}

.duration {
  font-size: 12px;
  color: #666;
  min-width: 20px;
  text-align: center;
}
</style>