<template>
  <div class="audio-asr-wrapper">
    <div class="content-header">
      <div class="title-info">
        <h2 class="main-title">音频 ASR 识别</h2>
        <p class="sub-title">支持多种格式音频上传，利用 GPU 加速提取语音文本</p>
      </div>
    </div>

    <el-row :gutter="20">
      <el-col :xs="24" :sm="24" :md="8" :lg="7">
        <el-card shadow="never" class="config-card">
          <div slot="header" class="card-header">
            <span><i class="el-icon-setting"></i> 任务配置</span>
          </div>

          <el-form label-position="top">
            <el-form-item label="音频上传">
              <el-upload
                class="audio-uploader-v2"
                drag
                action=""
                :auto-upload="false"
                :show-file-list="true"
                :limit="1"
                accept="audio/*"
                :on-change="handleFileChange"
              >
                <i class="el-icon-upload"></i>
                <div class="el-upload__text">拖拽音频到此处 或 <em>点击上传</em></div>
                <div class="el-upload__tip" slot="tip">建议格式：mp3, wav (不超过 50MB)</div>
              </el-upload>
            </el-form-item>

            <el-button
              type="primary"
              class="submit-btn"
              :loading="submitting"
              :disabled="!file"
              @click="submitAsrTask"
            >
              {{ submitting ? '正在上传...' : '提交识别任务' }}
            </el-button>
          </el-form>

          <transition name="el-zoom-in-top">
            <div v-if="taskId" class="task-monitor-box">
              <div class="monitor-header">
                <span class="status-dot" :class="status"></span>
                <span class="status-label">{{ statusText }}</span>
              </div>
              <div class="task-details">
                <p>任务 ID: <code>{{ taskId }}</code></p>
                <el-progress
                  v-if="status !== 'completed' && status !== 'error'"
                  :percentage="status === 'processing' ? 70 : 30"
                  :status="status === 'error' ? 'exception' : ''"
                  :stroke-width="8"
                  striped
                  striped-animated
                ></el-progress>
              </div>
            </div>
          </transition>
        </el-card>
      </el-col>

      <el-col :xs="24" :sm="24" :md="16" :lg="17">
        <el-card shadow="never" v-if="asrResult" class="result-card">
          <div slot="header" class="card-header-flex">
            <div class="header-left">
              <span class="result-title">识别结果</span>
              <el-tag size="mini" effect="plain" class="duration-tag">时长: {{ asrResult.duration.toFixed(1) }}s</el-tag>
              <el-button
                type="text"
                size="small"
                icon="el-icon-document"
                @click="showFullText = true"
              >全文预览</el-button>
            </div>
            <div class="custom-model-tag">
              <i class="el-icon-cpu"></i> GPU 识别加速
            </div>
          </div>

          <div class="audio-control-section">
            <audio ref="audioPlayer" controls :src="asrResult.audio_url" class="modern-audio-player"></audio>
          </div>

          <div class="srt-list-wrapper">
            <div class="srt-list-header">
              <span class="h-time">起始时间</span>
              <span class="h-text">识别内容</span>
            </div>
            <div class="srt-scroll-area">
              <div
                v-for="(item, index) in asrResult.srt"
                :key="index"
                class="srt-entry"
                @click="seekAudio(item.time)"
              >
                <div class="entry-time">
                  <span class="time-badge">{{ formatTimeLabel(item.time) }}</span>
                </div>
                <div class="entry-content">
                  <p class="text">{{ item.text }}</p>
                  <el-tooltip content="复制此行" placement="top">
                    <i class="el-icon-copy-document copy-icon" @click.stop="handleCopy(item.text)"></i>
                  </el-tooltip>
                </div>
              </div>
            </div>
          </div>
        </el-card>

        <div v-else class="empty-placeholder">
          <el-empty :description="emptyDescription">
            <template #image>
              <i class="el-icon-service" style="font-size: 60px; color: #dcdfe6;"></i>
            </template>
          </el-empty>
        </div>
      </el-col>
    </el-row>

    <el-dialog
      title="识别全文预览"
      :visible.sync="showFullText"
      width="50%"
      custom-class="full-text-dialog"
      append-to-body
    >
      <div class="full-text-body">
        {{ asrResult ? asrResult.text : '' }}
      </div>
      <div slot="footer">
        <el-button @click="showFullText = false">关闭</el-button>
        <el-button type="primary" icon="el-icon-document-copy" @click="handleCopy(asrResult.text)">复制全文</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  name: 'AudioAsrDetail',
  data() {
    return {
      submitting: false,
      file: null,
      taskId: '',
      status: '',
      asrResult: null,
      timer: null,
      showFullText: false
    };
  },
  computed: {
    statusText() {
      const maps = { 'queued': '队列中', 'processing': '正在提取语音...', 'completed': '识别成功', 'error': '识别失败' };
      return maps[this.status] || '等待操作';
    },
    emptyDescription() {
      if (this.status === 'processing' || this.status === 'queued') return '正在努力识别中，请稍后...';
      return '暂无数据，请在左侧上传音频文件';
    }
  },
  beforeDestroy() {
    this.stopPolling();
  },
  methods: {
    handleFileChange(file) {
      this.file = file.raw;
      this.taskId = '';
      this.status = '';
      this.asrResult = null;
      this.stopPolling();
    },
    async submitAsrTask() {
      this.submitting = true;
      try {
        const formData = new FormData();
        formData.append('file', this.file);
        const res = await axios.post('/api1/audio/asr', formData, {
          headers: { 'Content-Type': 'multipart/form-data' }
        });
        this.taskId = res.data.task_id;
        this.status = res.data.status;
        this.$message.success('任务已加入 GPU 队列');
        this.startPolling();
      } catch (error) {
        this.$message.error('提交失败');
      } finally {
        this.submitting = false;
      }
    },
    startPolling() {
      this.stopPolling();
      this.timer = setInterval(this.fetchAsrResult, 3000);
    },
    stopPolling() {
      if (this.timer) clearInterval(this.timer);
    },
    async fetchAsrResult() {
      try {
        const res = await axios.get('/api1/audio/result/' + this.taskId);
        if (res.data && (res.data.srt || res.data.text)) {
          this.asrResult = res.data;
          this.status = 'completed';
          this.stopPolling();
        }
      } catch (e) { /* 继续轮询 */ }
    },
    // 提取时间戳并跳转播放
    seekAudio(timeStr) {
      const player = this.$refs.audioPlayer;
      if (!player || !timeStr) return;
      // 假设格式为 "00:00:01,500 --> ..."
      const startPart = timeStr.split('-->')[0].trim().replace(',', '.');
      const parts = startPart.split(':');
      const seconds = (+parts[0]) * 3600 + (+parts[1]) * 60 + (+parts[2]);
      player.currentTime = seconds;
      player.play();
    },
    formatTimeLabel(timeStr) {
      return timeStr.split('-->')[0].trim().split(',')[0]; // 简化显示为 HH:mm:ss
    },
    async handleCopy(text) {
      try {
        await navigator.clipboard.writeText(text);
        this.$message.success('已复制到剪贴板');
      } catch (e) {
        const input = document.createElement('textarea');
        input.value = text;
        document.body.appendChild(input);
        input.select();
        document.execCommand('copy');
        document.body.removeChild(input);
        this.$message.success('已复制到剪贴板');
      }
    }
  }
};
</script>

<style scoped>
.audio-asr-wrapper {
  padding: 0 4px;
}

/* 标题区 */
.content-header {
  margin-bottom: 24px;
  padding-bottom: 16px;
  border-bottom: 1px solid #ebeef5;
}
.main-title {
  margin: 0;
  font-size: 20px;
  color: #303133;
}
.sub-title {
  margin: 8px 0 0;
  font-size: 13px;
  color: #909399;
}

/* 卡片通用 */
.config-card, .result-card {
  border-radius: 8px;
  border: 1px solid #ebeef5;
}

/* 上传区优化 */
.audio-uploader-v2 {
  width: 100%;
}
::v-deep .el-upload-dragger {
  width: 100%;
  height: 160px;
}
::v-deep .el-upload-dragger .el-icon-upload {
  margin: 20px 0 10px;
}

.submit-btn {
  width: 100%;
  padding: 12px;
  font-weight: bold;
}

/* 状态监控 */
.task-monitor-box {
  margin-top: 20px;
  padding: 16px;
  background: #f8f9fb;
  border-radius: 6px;
}
.monitor-header {
  display: flex;
  align-items: center;
  margin-bottom: 12px;
}
.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 8px;
  background: #909399;
}
.status-dot.processing { background: #409EFF; box-shadow: 0 0 5px #409EFF; }
.status-dot.completed { background: #67C23A; }
.status-label { font-size: 14px; font-weight: 500; }
.task-details { font-size: 12px; color: #606266; }
.task-details code { background: #eee; padding: 2px 4px; border-radius: 3px; }

/* 结果区 Header */
.card-header-flex {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.result-title {
  font-weight: bold;
  font-size: 16px;
}
.duration-tag {
  margin-left: 12px;
}

/* 播放器 */
.audio-control-section {
  background: #f0f2f5;
  padding: 12px;
  border-radius: 4px;
  margin-bottom: 20px;
}
.modern-audio-player {
  width: 100%;
}

/* SRT 列表 */
.srt-list-wrapper {
  border: 1px solid #f0f0f0;
  border-radius: 4px;
}
.srt-list-header {
  display: flex;
  padding: 10px 16px;
  background: #fafafa;
  border-bottom: 1px solid #f0f0f0;
  color: #909399;
  font-size: 13px;
  font-weight: 500;
}
.h-time { width: 120px; }
.srt-scroll-area {
  max-height: 480px;
  overflow-y: auto;
}
.srt-entry {
  display: flex;
  padding: 14px 16px;
  border-bottom: 1px solid #f9f9f9;
  cursor: pointer;
  transition: all 0.2s;
}
.srt-entry:hover {
  background-color: #f5f7fa;
}
.entry-time {
  width: 120px;
  flex-shrink: 0;
}
.time-badge {
  font-family: monospace;
  font-size: 12px;
  color: #409EFF;
  background: #ecf5ff;
  padding: 2px 6px;
  border-radius: 4px;
}
.entry-content {
  flex: 1;
  display: flex;
  justify-content: space-between;
}
.text {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: #303133;
}
.copy-icon {
  margin-left: 10px;
  color: #c0c4cc;
  cursor: pointer;
  visibility: hidden;
}
.srt-entry:hover .copy-icon {
  visibility: visible;
}
.copy-icon:hover {
  color: #409EFF;
}

/* 渐变标签 */
.custom-model-tag {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white !important;
  font-size: 12px;
  padding: 4px 12px;
  border-radius: 20px;
  font-weight: 500;
}

.full-text-body {
  white-space: pre-wrap;
  line-height: 1.8;
  background: #f8f9fb;
  padding: 20px;
  border-radius: 4px;
  max-height: 400px;
  overflow-y: auto;
}

.empty-placeholder {
  padding: 80px 0;
  background: #fff;
  border-radius: 8px;
}
</style>
