<template>
  <div class="app-container">
    <!-- 注意事项 -->
    <el-card class="tips-card" shadow="hover">
      <div class="tips-header">
        <i class="el-icon-warning-outline tips-icon"></i>
        <span class="tips-title">语音克隆注意事项</span>
      </div>
      <el-row :gutter="32" class="tips-content">
        <el-col :span="12">
          <div class="tip-item">
            <div class="tip-num">1</div>
            <div class="tip-text">
              <div class="tip-label">音色限制</div>
              <div class="tip-desc">
                <div class="tip-warning-box">
                  <i class="el-icon-info"></i>
                  <span>每个音色最多只能上传并训练 <strong>10</strong> 次</span>
                </div>
              </div>
            </div>
          </div>
        </el-col>
        <el-col :span="12">
          <div class="tip-item">
            <div class="tip-num">2</div>
            <div class="tip-text">
              <div class="tip-label">录制要求</div>
              <div class="tip-desc">
                预先录制 <strong>20~30秒</strong> 左右的声音，确保环境安静且无噪音
              </div>
            </div>
          </div>
          <div class="tip-item tip-sub">
            <div class="tip-sub-label">推荐录制方式：</div>
            <div class="tip-sub-list">
              <span class="tip-tag"><i class="el-icon-monitor"></i> 电脑+耳机，使用自带录音机</span>
              <span class="tip-tag"><i class="el-icon-mobile-phone"></i> 手机录音后传到电脑</span>
            </div>
          </div>
        </el-col>
      </el-row>
    </el-card>

    <!-- 声音克隆表单 -->
    <el-card class="box-card" style="margin-bottom: 16px;">
      <div slot="header"><span>声音克隆配置</span></div>
      <el-form ref="cloneForm" :model="cloneForm" :rules="cloneRules" label-width="120px">
        <el-form-item label="音色名称" prop="voice_name">
          <el-input
            v-model="cloneForm.voice_name"
            placeholder="请输入音色名称"
            style="width: 320px;"
          />
        </el-form-item>

        <el-form-item label="声音ID" prop="speaker_id">
          <el-input
            v-model="cloneForm.speaker_id"
            placeholder="请输入声音ID"
            style="width: 320px;"
          />
        </el-form-item>

        <el-form-item label="模型类型" prop="model_type">
          <el-select
            v-model="cloneForm.model_type"
            placeholder="请选择模型类型"
            style="width: 400px;"
            @change="onModelTypeChange"
          >
            <el-option :value="1" label="声音复刻ICL1.0效果" />
            <!-- <el-option :value="2" label="DiT标准版效果（音色、不还原用户的风格）" />
            <el-option :value="3" label="DiT还原版效果（音色、还原用户口音、语速等风格）" /> -->
            <el-option :value="4" label="声音复刻ICL2.0效果" />
          </el-select>
        </el-form-item>

        <el-form-item label="语言" prop="language">
          <el-select
            v-model="cloneForm.language"
            placeholder="请选择语言"
            style="width: 240px;"
          >
            <el-option
              v-for="item in languageOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>

        <el-form-item label="音频文件">
          <el-upload
            ref="audioUpload"
            action="#"
            :auto-upload="false"
            :on-change="onAudioFileChange"
            :on-remove="onAudioFileRemove"
            :file-list="audioFileList"
            accept=".wav,.mp3,.ogg,.m4a,.aac"
            :limit="1"
            :on-exceed="onFileExceed"
          >
            <el-button size="small" type="primary" icon="el-icon-upload">
              选择音频文件
            </el-button>
            <div slot="tip" class="el-upload__tip" style="color: #909399;">
              支持 wav、mp3、ogg、m4a、aac 格式，推荐 20-30 秒录音
            </div>
          </el-upload>
        </el-form-item>

        <el-form-item>
          <el-button
            type="success"
            icon="el-icon-upload2"
            :loading="uploadLoading"
            @click="handleUploadAndTrain"
          >
            {{ uploadLoading ? '上传训练中，约15-30秒...' : '上传并训练' }}
          </el-button>
          <el-button
            type="primary"
            icon="el-icon-headset"
            plain
            @click="handleOpenTestPanel"
          >
            测试已有声音
          </el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <!-- TTS测试区域（上传训练成功后 或 点击测试按钮后显示） -->
    <el-card v-if="showTtsArea" class="box-card">
      <div slot="header" class="tts-card-header">
        <span>TTS语音合成测试</span>
        <el-button v-if="isManualTest" type="text" icon="el-icon-close" @click="showTtsArea = false">关闭</el-button>
      </div>
      <el-form ref="ttsForm" :model="ttsForm" label-width="120px">
        <!-- 手动测试时需要输入声音ID -->
        <el-form-item v-if="isManualTest" label="声音ID" prop="test_speaker_id">
          <el-input
            v-model="ttsForm.test_speaker_id"
            placeholder="请输入要测试的声音ID"
            style="width: 320px;"
          />
        </el-form-item>

        <el-form-item label="测试文本" prop="tts_text">
          <el-input
            v-model="ttsForm.tts_text"
            type="textarea"
            :rows="5"
            placeholder="请输入测试语音合成的文本"
            style="width: 480px;"
          />
        </el-form-item>

        <el-form-item label="语言" prop="language_test">
          <el-select
            v-model="ttsForm.language_test"
            placeholder="请选择语言"
            style="width: 240px;"
          >
            <el-option
              v-for="item in ttsLanguageOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
          <el-button
            type="primary"
            icon="el-icon-video-play"
            style="margin-left: 12px;"
            :loading="ttsLoading"
            :disabled="isManualTest && !ttsForm.test_speaker_id"
            @click="handleTtsTest"
          >
            {{ ttsLoading ? '合成中...' : '开始合成' }}
          </el-button>
        </el-form-item>

        <el-form-item v-if="audioSrc" label="播放">
          <audio ref="audioPlayer" controls :src="audioSrc" style="margin-top: 4px;" />
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script>
import { uploadAndTrain, doubaoTtsTest } from '@/api/company/voiceClone'

export default {
  name: 'VoiceClone',
  data() {
    return {
      // 声音克隆表单
      cloneForm: {
        voice_name: '',
        speaker_id: '',
        model_type: null,
        language: 0
      },
      cloneRules: {
        voice_name: [{ required: true, message: '请输入音色名称', trigger: 'blur' }],
        speaker_id: [{ required: true, message: '请输入声音ID', trigger: 'blur' }],
        model_type: [{ required: true, message: '请选择模型类型', trigger: 'change' }],
        language: [{ required: true, message: '请选择语言', trigger: 'change' }]
      },

      // 音频文件列表
      audioFileList: [],
      selectedFile: null,

      // 上传训练loading
      uploadLoading: false,

      // 是否显示TTS测试区域
      showTtsArea: false,

      // 是否为手动测试模式（区别于上传训练成功后的自动显示）
      isManualTest: false,

      // TTS测试表单
      ttsForm: {
        tts_text: '',
        language_test: 0,
        test_speaker_id: '' // 手动测试时的声音ID
      },

      // TTS testing loading
      ttsLoading: false,

      // 播放音频src（base64）
      audioSrc: ''
    }
  },

  computed: {
    // 根据模型类型动态计算语言选项
    languageOptions() {
      const modelType = this.cloneForm.model_type
      const options = [
        { value: 0, label: '中文' },
        { value: 1, label: '英文' }
      ]
      if (modelType <= 2) {
        options.push(
          { value: 2, label: '日语' },
          { value: 3, label: '西班牙语' },
          { value: 4, label: '印尼语' },
          { value: 5, label: '葡萄牙语' }
        )
      }
      if (modelType === 2) {
        options.push(
          { value: 6, label: '德语' },
          { value: 7, label: '法语' }
        )
      }
      return options
    },
    // TTS测试语言选项（手动测试时显示全部语言）
    ttsLanguageOptions() {
      return [
        { value: 0, label: '中文' },
        { value: 1, label: '英文' },
        { value: 2, label: '日语' },
        { value: 3, label: '西班牙语' },
        { value: 4, label: '印尼语' },
        { value: 5, label: '葡萄牙语' },
        { value: 6, label: '德语' },
        { value: 7, label: '法语' }
      ]
    }
  },

  methods: {
    // 模型类型变更，重置语言为中文
    onModelTypeChange() {
      const validValues = this.languageOptions.map(o => o.value)
      if (!validValues.includes(this.cloneForm.language)) {
        this.cloneForm.language = 0
      }
      if (!validValues.includes(this.ttsForm.language_test)) {
        this.ttsForm.language_test = 0
      }
    },

    // 音频文件选择
    onAudioFileChange(file) {
      this.selectedFile = file.raw
      this.audioFileList = [file]
    },

    // 音频文件移除
    onAudioFileRemove() {
      this.selectedFile = null
      this.audioFileList = []
    },

    // 超出文件数量限制
    onFileExceed() {
      this.$message.warning('每次只能上传一个音频文件，请先移除已选文件')
    },

    // 打开手动测试面板
    handleOpenTestPanel() {
      this.isManualTest = true
      this.showTtsArea = true
      this.ttsForm.test_speaker_id = ''
      this.ttsForm.tts_text = ''
      this.ttsForm.language_test = 0
      this.audioSrc = ''
    },

    // 上传并训练
    handleUploadAndTrain() {
      this.$refs.cloneForm.validate(valid => {
        if (!valid) return
        if (!this.selectedFile) {
          this.$message.error('请选择音频文件')
          return
        }
        this.uploadLoading = true

        const formData = new FormData()
        formData.append('file', this.selectedFile)
        formData.append('voice_name', this.cloneForm.voice_name)
        formData.append('speaker_id', this.cloneForm.speaker_id)
        formData.append('language', this.cloneForm.language)
        formData.append('model_type', this.cloneForm.model_type)

        uploadAndTrain(formData).then(res => {
          if (res.code === 200) {
            this.$message.success(res.msg || '上传训练成功！')
            this.isManualTest = false // 上传训练成功后的测试模式
            this.showTtsArea = true
          } else {
            this.$message.error(res.msg || '上传训练失败，请重试')
          }
        }).catch(() => {
          this.$message.error('上传训练失败，请重试')
        }).finally(() => {
          this.uploadLoading = false
        })
      })
    },

    // TTS测试
    handleTtsTest() {
      if (this.ttsLoading) {
        this.$message.warning('请等待合成完成！')
        return
      }
      if (!this.ttsForm.tts_text || this.ttsForm.tts_text.trim() === '') {
        this.$message.error('请输入测试文本')
        return
      }

      // 获取声音ID：手动测试用输入框的值，自动测试用表单的值
      const speakerId = this.isManualTest ? this.ttsForm.test_speaker_id : this.cloneForm.speaker_id
      if (!speakerId || speakerId.trim() === '') {
        this.$message.error('请输入声音ID')
        return
      }

      this.ttsLoading = true

      const formData = new FormData()
      formData.append('speakerId', speakerId)
      formData.append('language', this.ttsForm.language_test)
      formData.append('text', this.ttsForm.tts_text)

      doubaoTtsTest(formData).then(res => {
        if (res.code === 200) {
          this.$message.success('TTS合成成功！')
          // res.data 是 JSON 字符串 {"code":3000,"data":"...base64..."}
          try {
            const audioJson = JSON.parse(res.data)
            if (audioJson.code === 3000 && audioJson.data) {
              this.audioSrc = 'data:audio/mp3;base64,' + audioJson.data
              this.$nextTick(() => {
                this.$refs.audioPlayer && this.$refs.audioPlayer.play()
              })
            }
          } catch (e) {
            this.$message.warning('音频解析失败')
          }
        } else {
          this.$message.error(res.msg || 'TTS测试失败，请重试')
        }
      }).catch(() => {
        this.$message.error('TTS测试失败，请重试')
      }).finally(() => {
        this.ttsLoading = false
      })
    }
  }
}
</script>

<style scoped>
.box-card {
  margin-bottom: 16px;
}

/* TTS测试卡片头部 */
.tts-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* 注意事项卡片样式 */
.tips-card {
  margin-bottom: 20px;
  border-left: 4px solid #409EFF;
}

.tips-card /deep/ .el-card__body {
  padding: 16px 20px;
}

.tips-header {
  display: flex;
  align-items: center;
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px dashed #EBEEF5;
}

.tips-icon {
  font-size: 22px;
  color: #409EFF;
  margin-right: 10px;
}

.tips-title {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.tips-content {
  margin: 0;
}

.tip-item {
  display: flex;
  align-items: flex-start;
  margin-bottom: 12px;
}

.tip-item:last-child {
  margin-bottom: 0;
}

.tip-num {
  width: 24px;
  height: 24px;
  background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
  border-radius: 50%;
  color: #fff;
  font-size: 13px;
  font-weight: bold;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 12px;
  flex-shrink: 0;
}

.tip-text {
  flex: 1;
}

.tip-label {
  font-size: 14px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 4px;
}

.tip-desc {
  font-size: 13px;
  color: #606266;
  line-height: 1.6;
}

.tip-desc strong {
  color: #409EFF;
}

.link-btn {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  background: #ecf5ff;
  border-radius: 4px;
  color: #409EFF;
  font-size: 12px;
  margin: 0 4px;
  transition: all 0.3s;
}

.link-btn:hover {
  background: #409EFF;
  color: #fff;
}

.link-btn i {
  margin-left: 2px;
}

.tip-warning {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 6px;
  background: #fef0f0;
  border-radius: 3px;
  color: #f56c6c;
  font-size: 12px;
}

.tip-warning-box {
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  background: linear-gradient(135deg, #fff6f6 0%, #fef0f0 100%);
  border: 1px solid #fbc4c4;
  border-radius: 6px;
  color: #f56c6c;
  font-size: 13px;
}

.tip-warning-box i {
  margin-right: 8px;
  font-size: 16px;
}

.tip-warning-box strong {
  color: #f56c6c;
  font-size: 16px;
  margin: 0 2px;
}

.tip-sub {
  margin-top: 12px;
  padding-left: 36px;
}

.tip-sub-label {
  font-size: 13px;
  color: #909399;
  margin-bottom: 8px;
}

.tip-sub-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.tip-tag {
  text-align: center;
  line-height: 20px;
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  background: #f4f4f5;
  border-radius: 4px;
  font-size: 12px;
  color: #606266;
}

.tip-tag i {
  margin-right: 4px;
  color: #909399;
}
</style>
