<template>
  <Teleport to="body">
    <Transition name="tts-player-slide">
      <div v-if="visible" class="tts-player">
        <div class="tts-player__inner">
        <div class="tts-player__controls">
          <button class="tts-player__btn" @click="skipBackward" title="快退5秒">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M1 4v6h6"/>
              <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/>
              <text x="12" y="15" font-size="8" font-weight="600" fill="currentColor" stroke="none" text-anchor="middle">5</text>
            </svg>
          </button>
          <button class="tts-player__btn tts-player__btn--primary" @click="togglePlay" :title="isPlaying ? '暂停' : '播放'">
            <Transition name="icon-fade" mode="out-in">
              <svg v-if="!isPlaying" key="play" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="none">
                <polygon points="5 3 19 12 5 21 5 3"/>
              </svg>
              <svg v-else key="pause" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="none">
                <rect x="6" y="4" width="4" height="16" rx="1"/>
                <rect x="14" y="4" width="4" height="16" rx="1"/>
              </svg>
            </Transition>
          </button>
          <button class="tts-player__btn" @click="skipForward" title="快进5秒">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M23 4v6h-6"/>
              <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/>
              <text x="12" y="15" font-size="8" font-weight="600" fill="currentColor" stroke="none" text-anchor="middle">5</text>
            </svg>
          </button>
        </div>

          <div class="tts-player__progress">
            <span class="tts-player__time">{{ currentTimeStr }}</span>
            <div class="tts-player__bar" @click="seek">
              <div class="tts-player__bar-fill" :style="{ width: progressPercent + '%' }">
                <div class="tts-player__bar-thumb"></div>
              </div>
            </div>
            <span class="tts-player__time">{{ durationStr }}</span>
          </div>

          <div class="tts-player__settings">
            <div class="tts-player__volume">
              <button class="tts-player__btn" @click="toggleMute" :title="isMuted ? '取消静音' : '静音'">
                <!-- 高音量：扬声器图标 + 两道向外扩散的声波弧线 -->
                <svg v-if="!isMuted && volume > 0.5" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <path d="M3 9l18-4v14l-18-4z"/>
                  <path d="M7 12c0-1.7.9-3.2 2.3-4.1"/>
                  <path d="M7 12c0-4.4 3.1-8.1 7.4-9.4"/>
                </svg>
                <!-- 中音量：扬声器图标 + 一道声波弧线 -->
                <svg v-else-if="volume > 0" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <path d="M3 9l18-4v14l-18-4z"/>
                  <path d="M7 12c0-1.7.9-3.2 2.3-4.1"/>
                </svg>
                <!-- 静音：扬声器图标 + X形交叉线 -->
                <svg v-else width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <path d="M3 9l18-4v14l-18-4z"/>
                  <line x1="7" y1="5" x2="13" y2="19"/>
                  <line x1="13" y1="5" x2="7" y2="19"/>
                </svg>
              </button>
              <input type="range" class="tts-player__slider" v-model.number="volume" min="0" max="1" step="0.05" title="音量">
            </div>

            <select class="tts-player__speed-select" v-model.number="playbackRate" title="播放速度">
              <option value="0.5">0.5x</option>
              <option value="0.75">0.75x</option>
              <option value="1">1x</option>
              <option value="1.25">1.25x</option>
              <option value="1.5">1.5x</option>
              <option value="2">2x</option>
            </select>

            <button class="tts-player__btn" @click="downloadAudio" title="下载音频">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>
              </svg>
            </button>

            <button class="tts-player__btn tts-player__btn--close" @click="$emit('close')" title="关闭">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
              </svg>
            </button>
          </div>
        </div>

        <audio ref="audioRef" :src="audioSrc" @timeupdate="onTimeUpdate" @ended="onEnded" @loadedmetadata="onLoadedMetadata" @play="onPlay" @pause="onPause"></audio>
      </div>
    </Transition>
  </Teleport>
</template>

<script setup>
import { ref, computed, watch, onUnmounted } from 'vue'

const props = defineProps({
  visible: { type: Boolean, default: false },
  audioBase64: { type: String, default: '' },
  format: { type: String, default: 'wav' },
  durationMs: { type: Number, default: 0 },
})

const emit = defineEmits(['close'])

const audioRef = ref(null)
const isPlaying = ref(false)
const currentTime = ref(0)
const duration = ref(0)
const volume = ref(1)
const isMuted = ref(false)
const playbackRate = ref(1)
let blobUrl = ''

const audioSrc = computed(() => {
  if (!props.audioBase64) return ''
  if (blobUrl) URL.revokeObjectURL(blobUrl)
  const byteChars = atob(props.audioBase64)
  const byteNumbers = new Array(byteChars.length)
  for (let i = 0; i < byteChars.length; i++) {
    byteNumbers[i] = byteChars.charCodeAt(i)
  }
  const byteArray = new Uint8Array(byteNumbers)
  const blob = new Blob([byteArray], { type: `audio/${props.format}` })
  blobUrl = URL.createObjectURL(blob)
  return blobUrl
})

const currentTimeStr = computed(() => formatTime(currentTime.value))
const durationStr = computed(() => formatTime(duration.value))
const progressPercent = computed(() => {
  if (!duration.value) return 0
  return Math.min(100, (currentTime.value / duration.value) * 100)
})

function formatTime(seconds) {
  if (!seconds || !isFinite(seconds)) return '0:00'
  const mins = Math.floor(seconds / 60)
  const secs = Math.floor(seconds % 60)
  return `${mins}:${secs.toString().padStart(2, '0')}`
}

function togglePlay() {
  const audio = audioRef.value
  if (!audio) return
  if (isPlaying.value) {
    audio.pause()
    isPlaying.value = false
  } else {
    audio.play().then(() => {
      isPlaying.value = true
    }).catch(() => {})
  }
}

function skipBackward() {
  const audio = audioRef.value
  if (!audio) return
  audio.currentTime = Math.max(0, audio.currentTime - 5)
}

function skipForward() {
  const audio = audioRef.value
  if (!audio) return
  audio.currentTime = Math.min(duration.value, audio.currentTime + 5)
}

function seek(event) {
  const audio = audioRef.value
  if (!audio || !duration.value) return
  const rect = event.currentTarget.getBoundingClientRect()
  const ratio = (event.clientX - rect.left) / rect.width
  audio.currentTime = Math.max(0, Math.min(duration.value, ratio * duration.value))
}

function toggleMute() {
  isMuted.value = !isMuted.value
  if (audioRef.value) {
    audioRef.value.muted = isMuted.value
  }
}

function downloadAudio() {
  if (!blobUrl) return
  const a = document.createElement('a')
  a.href = blobUrl
  a.download = `tts-${Date.now()}.${props.format}`
  a.click()
}

function onTimeUpdate() {
  const audio = audioRef.value
  if (!audio) return
  currentTime.value = audio.currentTime
}

function onLoadedMetadata() {
  const audio = audioRef.value
  if (!audio) return
  duration.value = audio.duration || (props.durationMs / 1000)
  audio.volume = volume.value
  audio.playbackRate = playbackRate.value
  audio.play().then(() => {
    isPlaying.value = true
  }).catch(() => {
    isPlaying.value = false
  })
}

function onEnded() {
  isPlaying.value = false
  currentTime.value = 0
}

// 监听音频实际播放状态（用户可能通过其他方式暂停）
function onPlay() {
  isPlaying.value = true
}

function onPause() {
  isPlaying.value = false
}

watch(volume, (val) => {
  if (audioRef.value) {
    audioRef.value.volume = val
    isMuted.value = val === 0
  }
})

watch(playbackRate, (val) => {
  if (audioRef.value) {
    audioRef.value.playbackRate = val
  }
})

watch(() => props.visible, (val) => {
  if (val) {
    // 打开播放器时重置状态，等待音频加载完成后才真正播放
    isPlaying.value = false
    currentTime.value = 0
  } else {
    if (audioRef.value) {
      audioRef.value.pause()
      audioRef.value.currentTime = 0
    }
    isPlaying.value = false
  }
})

onUnmounted(() => {
  if (audioRef.value) {
    audioRef.value.pause()
  }
  if (blobUrl) {
    URL.revokeObjectURL(blobUrl)
    blobUrl = ''
  }
})
</script>

<style scoped>
.tts-player {
  position: fixed;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 99999;
  max-width: 720px;
  width: calc(100% - 32px);
  padding: 12px 16px;
  background: var(--panel-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--panel-border);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15), 0 2px 8px rgba(0, 0, 0, 0.1);
}

.tts-player__inner {
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: 1200px;
  margin: 0 auto;
}

.tts-player__controls {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.tts-player__btn {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--app-text);
  cursor: pointer;
  transition: all 0.15s ease;
}

.tts-player__btn:hover {
  background: rgba(128, 128, 128, 0.15);
}

.tts-player__btn--primary {
  width: 36px;
  height: 36px;
  background: var(--btn-hover-bg);
  color: var(--btn-hover-fg);
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.tts-player__btn--primary:hover {
  transform: scale(1.08);
  filter: brightness(1.1);
}

.tts-player__btn--primary:active {
  transform: scale(0.95);
}

.tts-player__btn--close:hover {
  background: rgba(220, 38, 38, 0.15);
  color: var(--danger-text);
}

.tts-player__progress {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.tts-player__time {
  font-size: 11px;
  color: var(--muted-text);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
  min-width: 36px;
}

.tts-player__bar {
  flex: 1;
  height: 4px;
  background: rgba(128, 128, 128, 0.2);
  border-radius: 2px;
  cursor: pointer;
  position: relative;
  transition: height 0.1s ease;
}

.tts-player__bar:hover {
  height: 6px;
}

.tts-player__bar:hover .tts-player__bar-thumb {
  opacity: 1;
}

.tts-player__bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--btn-hover-bg), #60a5fa);
  border-radius: 2px;
  position: relative;
  transition: width 0.1s linear;
}

.tts-player__bar-thumb {
  position: absolute;
  right: -5px;
  top: 50%;
  transform: translateY(-50%);
  width: 10px;
  height: 10px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  opacity: 0;
  transition: opacity 0.1s ease;
}

.tts-player__settings {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.tts-player__volume {
  display: flex;
  align-items: center;
  gap: 4px;
}

.tts-player__slider {
  width: 60px;
  height: 4px;
  -webkit-appearance: none;
  appearance: none;
  background: rgba(128, 128, 128, 0.2);
  border-radius: 2px;
  outline: none;
  cursor: pointer;
}

.tts-player__slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 12px;
  height: 12px;
  background: var(--btn-hover-bg);
  border-radius: 50%;
  cursor: pointer;
}

.tts-player__slider::-moz-range-thumb {
  width: 12px;
  height: 12px;
  background: var(--btn-hover-bg);
  border-radius: 50%;
  border: none;
  cursor: pointer;
}

.tts-player__speed-select {
  padding: 2px 6px;
  border: 1px solid var(--panel-border);
  border-radius: 4px;
  background: transparent;
  color: var(--app-text);
  font-size: 11px;
  cursor: pointer;
  outline: none;
}

.tts-player__speed-select:hover {
  border-color: var(--btn-hover-bg);
}

.tts-player-slide-enter-active,
.tts-player-slide-leave-active {
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.25s ease;
}

.tts-player-slide-enter-from,
.tts-player-slide-leave-to {
  transform: translateX(-50%) translateY(24px);
  opacity: 0;
}

.icon-fade-enter-active,
.icon-fade-leave-active {
  transition: all 0.15s ease;
}

.icon-fade-enter-from,
.icon-fade-leave-to {
  opacity: 0;
  transform: scale(0.7);
}
</style>
