<template>
  <div class="course-script-editor">
    <!-- 全屏遮挡层 -->
    <div v-if="isGenerating" class="loading-overlay">
      <div class="loading-content">
        <div class="loading-spinner"></div>
        <div class="loading-text">生成中...</div>
      </div>
    </div>
    <div class="main-container">
      <!-- 左侧步骤指示器 -->
      <div class="steps-sidebar">
        <div class="steps-container">
          <template v-for="(step, index) in steps" :key="step.id">
            <div
              :class="['step-item', { process: currentStep === step.id, finish: step.id < currentStep, wait: step.id > currentStep }]"
            >
              <div class="step-circle">{{ step.id }}</div>
              <div class="step-title">{{ step.label }}</div>
            </div>
            <div v-if="index < steps.length - 1" class="step-line" :class="{ active: currentStep > step.id }"></div>
          </template>
        </div>
      </div>

      <!-- 右侧内容区域 -->
      <div class="content-area">
        <!-- 步骤1：AI一句话生成 -->
        <div v-if="currentStep === 1" class="step-content">
          <div class="ai-input-container">
            <div class="ai-input-wrapper">
              <div class="ai-icon">🤖</div>
              <textarea
                v-model="scriptPrompt"
                placeholder="AI一句话生成课程脚本，例如：生成一节关于牛顿万有引力的小学科学课脚本..."
                class="ai-textarea"
              ></textarea>
            </div>

            <div class="selection-group">
              <div class="selection-item">
                <label>主讲老师</label>
                <el-select v-model="selectedMainTeacher" filterable size="large" placeholder="请选择主讲老师" style="width: 300px" clearable>
                  <el-option
                    v-for="teacher in digitalHumans"
                    :key="teacher.name"
                    :label="teacher.name"
                    :value="teacher.name"
                  />
                </el-select>
              </div>

              <div class="selection-item">
                <label>助讲老师</label>
                <el-select v-model="selectedAssistants" filterable size="large" placeholder="请选择助讲老师" style="width: 300px" clearable multiple>
                  <el-option
                    v-for="teacher in digitalHumans"
                    :key="teacher.name"
                    :label="teacher.name"
                    :value="teacher.name"
                  />
                </el-select>
              </div>
            </div>

            <button
              class="generate-btn primary"
              :disabled="!scriptPrompt || !selectedMainTeacher || isGenerating"
              @click="generateScript"
            >
              {{ isGenerating ? '生成中...' : '生成课程脚本' }}
            </button>
          </div>
        </div>

        <!-- 步骤2：脚本编辑（含背景图/音生成） -->
        <div v-else-if="currentStep === 2" class="step-content">
          <!-- 固定顶部的一键操作栏 -->
          <div class="editor-toolbar sticky-top">
            <button 
              class="toolbar-btn" 
              @click="generateAllImages"
              :disabled="isGeneratingImages || isAnyImageGenerating"
            >
              {{ isGeneratingImages ? '生成中...' : '一键生成所有背景图' }}
            </button>
            <button 
              class="toolbar-btn" 
              @click="generateAllVoiceovers"
              :disabled="isGeneratingVoiceovers || isAnyVoiceoverGenerating"
            >
              {{ isGeneratingVoiceovers ? '生成中...' : '一键配音' }}
            </button>
          </div>

          <!-- 可滚动的内容区域 -->
          <div class="script-editor">
            <div
              v-for="(section, sectionIndex) in scriptData.sections"
              :key="sectionIndex"
              class="script-section"
            >
              <div class="section-header">
                <div class="section-name-container">
                  <label class="section-name-label">环节 {{sectionIndex+1}}</label>
                  <input
                    v-model="section.name"
                    class="section-title"
                    placeholder="如：环节一（引入）"
                  />
                </div>
                <button class="remove-section-btn" @click="removeSection(sectionIndex)">×</button>
              </div>
              <div class="media-controls" >
                <div class="media-item">
                  <div class="media-input-group">
                    <span class="media-label">背景图</span>
                    <el-input
                      v-model="section.backgroundImage.prompt"
                      type="textarea"
                      :autosize="{ minRows: 2, maxRows: 4 }"
                      placeholder="描述词"
                      class="media-prompt"
                    />
                    <el-button
                      type="primary"
                      size="small"
                      :loading="section.backgroundImage.generating"
                      :disabled="!section.backgroundImage.prompt || section.backgroundImage.generating"
                      @click="generateMedia(sectionIndex)"
                      class="generate-btn"
                    >
                      {{ section.backgroundImage.generating ? '生成中...' : (section.backgroundImage.url ? '重新生成' : '生成') }}
                    </el-button>
                  </div>
                  <div v-if="section.backgroundImage.url" class="media-preview">
                    <img :src="section.backgroundImage.url" alt="背景图预览" />
                  </div>
                </div>

                <div class="media-item">
                  <div class="media-input-group">
                    <span class="media-label">背景音</span>
                    <el-select v-model="section.backgroundAudio.type" placeholder="选择背景音" style="width: 240px" clearable size="large" @change="(value) => handleBackgroundAudioChange(value, section)">
                      <el-option
                        v-for="musicType in backgroundMusicTypes"
                        :key="musicType.id"
                        :label="musicType.name"
                        :value="musicType.id"
                      />
                    </el-select>
                    <button
                        v-if="section.backgroundAudio.type"
                        class="play-btn small"
                        @click="playBackgroundAudio(section.backgroundAudio.type)"
                      >
                        <span class="play-icon">{{ audioState.isPlaying && audioState.currentType === 'background' && audioState.currentUrl === section.backgroundAudio.url ? '⏸' : '▶' }}</span>
                      </button>
                  </div>
                </div>
              </div>

              <div class="dialogues-container">
                <div
                  v-for="(dialogue, dialogueIndex) in section.dialogues"
                  :key="dialogueIndex"
                  class="dialogue-item"
                  :class="dialogue.type"
                >
                  <div class="dialogue-header">
                    <div class="dialogue-type-tag" :class="dialogue.type">
                      {{ dialogue.type === 'digital' ? '数字人' : '用户' }}
                    </div>
                  </div>
                  <div class="dialogue-row">
                    <!-- 数字人对话 -->
                    <template v-if="dialogue.type === 'digital'">
                      <div class="dialogue-role-select">
                        <el-select v-model="dialogue.roleName" placeholder="选择角色" style="width: 140px" clearable>
                          <el-option
                            v-for="role in digitalHumans"
                            :key="role.id"
                            :label="role.name"
                            :value="role.name"
                          />
                        </el-select>
                      </div>
                      <div class="dialogue-content-container">
                        <el-input
                          v-model="dialogue.content"
                          type="textarea"
                          class="dialogue-content"
                          placeholder="对话内容..."
                          :autosize="{ minRows: 2, maxRows: 4 }"
                        />
                      </div>
                      <div class="action-buttons">
                        <div class="action-buttons-row">
                          <button
                            v-if="dialogue.voiceoverUrl"
                            class="play-btn"
                            @click="playVoiceover(dialogue.voiceoverUrl)"
                          >
                            <span class="play-icon">{{ audioState.isPlaying && audioState.currentType === 'voice' && audioState.currentUrl === dialogue.voiceoverUrl ? '⏸' : '▶' }}</span>
                          </button>
                          <button class="remove-btn" @click="removeDialogue(sectionIndex, dialogueIndex)">×</button>
                        </div>
                        <div class="action-buttons-row">
                          <button
                            v-if="!dialogue.voiceoverUrl"
                            class="generate-btn small"
                            :disabled="!dialogue.content || !dialogue.roleName || dialogue.generatingVoiceover"
                            @click="generateVoiceover(sectionIndex, dialogueIndex)"
                          >
                            <span class="voice-icon">{{ dialogue.generatingVoiceover ? '生成中...' : '生成语音' }}</span>
                          </button>
                          <button
                            v-if="dialogue.voiceoverUrl"
                            class="generate-btn small"
                            :disabled="!dialogue.content || !dialogue.roleName || dialogue.generatingVoiceover"
                            @click="generateVoiceover(sectionIndex, dialogueIndex)"
                          >
                            <span class="voice-icon">{{ dialogue.generatingVoiceover ? '生成中...' : '重新生成' }}</span>
                          </button>
                        </div>
                      </div>
                    </template>

                    <!-- 用户 -->
                    <template v-else-if="dialogue.type === 'user'">
                      <div class="dialogue-content-container full-width">
                        <el-input
                          v-model="dialogue.content"
                          type="textarea"
                          class="dialogue-content"
                          placeholder="用户回复内容..."
                          :autosize="{ minRows: 2, maxRows: 4 }"
                        />
                      </div>
                      <div class="dialogue-reply-select">
                        <el-select v-model="dialogue.roleName" placeholder="选择数字人回复" style="width: 140px" clearable>
                          <el-option
                            v-for="role in digitalHumans"
                            :key="role.id"
                            :label="role.name"
                            :value="role.name"
                          />
                        </el-select>
                      </div>
                      <div class="action-buttons">
                        <div class="action-buttons-row">
                          <button class="remove-btn" @click="removeDialogue(sectionIndex, dialogueIndex)">×</button>
                        </div>
                      </div>
                    </template>
                  </div>
                </div>

                <div class="add-dialogue-buttons">
                  <button class="add-dialogue-btn digital" @click="addDialogue(sectionIndex)">+ 添加对话</button>
                  <button class="add-dialogue-btn user" @click="addUserReply(sectionIndex)">+ 添加用户回复</button>
                </div>
              </div>
            </div>

            <button class="add-section-btn" @click="addSection">+ 添加环节</button>
          </div>


          <div class="preview-actions">

            <button
              v-if="currentStep > 1"
              class="secondary-btn"
              @click="currentStep--"
            >
              重新生成
            </button>

            <button
              class="primary-btn"
              :disabled="!canProceed"
              @click="nextStep"
            >
              预览完整脚本
            </button>
          </div>
        </div>

        <!-- 步骤3：预览与保存 -->
        <div v-else-if="currentStep === 3" class="step-content">
          <div class="preview-container">
            <h3>课程脚本预览</h3>
            <br/>

            <div class="validation-result" :class="{ valid: isValidationPassed, invalid: !isValidationPassed }">
              {{ validationMessage }}
            </div>

            <div class="preview-content">
              <div
                v-for="(section, sectionIndex) in scriptData.sections"
                :key="sectionIndex"
                class="preview-section"
                :style="{ backgroundImage: section.backgroundImage.url ? `url(${section.backgroundImage.url})` : 'none', backgroundSize: 'cover', backgroundPosition: 'center', backgroundRepeat: 'no-repeat' }"
              >
                <div class="preview-section-content">
                  <div class="preview-media">
                    <div class="preview-media-left">
                      <label class="section-name-label">环节 {{sectionIndex+1}}</label>
                      <strong>{{ section.name }}</strong>
                    </div>
                    <div class="preview-media-right">
                      <span v-if="section.backgroundAudio.type" class="preview-audio">
                        背景音：{{ section.backgroundAudio.type }}
                        <button
                        class="play-btn small"
                        @click="playBackgroundAudio(section.backgroundAudio.type)"
                      >
                        <span class="play-icon">{{ audioState.isPlaying && audioState.currentType === 'background' && audioState.currentUrl === section.backgroundAudio.url ? '⏸' : '▶' }}</span>
                      </button>
                      </span>
                    </div>
                  </div>

                <div class="preview-dialogues">
                  <div
                    v-for="(dialogue, dialogueIndex) in section.dialogues"
                    :key="dialogueIndex"
                    class="preview-dialogue"
                    :class="dialogue.type"
                  >
                    <div class="dialogue-header">
                      <div class="dialogue-header-left">
                        <div class="dialogue-type-tag" :class="dialogue.type">
                          {{ dialogue.type === 'digital' ? '数字人' : '用户' }}
                        </div>
                        <div class="dialogue-role">
                          {{ dialogue.type === 'digital' ? getRoleName(dialogue.roleName) : '用户' }}：
                        </div>
                      </div>
                      <button
                        v-if="dialogue.voiceoverUrl && dialogue.type === 'digital'"
                        class="play-btn small"
                        @click="playVoiceover(dialogue.voiceoverUrl)"
                      >
                        <span class="play-icon">{{ audioState.isPlaying && audioState.currentType === 'voice' && audioState.currentUrl === dialogue.voiceoverUrl ? '⏸' : '▶' }}</span>
                      </button>
                    </div>
                    <div class="dialogue-text" v-html="parseMarkdown(dialogue.content)"></div>
                    <div v-if="dialogue.type === 'user' && dialogue.roleName" class="reply-info">
                      回复角色：{{ getRoleName(dialogue.roleName) }}
                    </div>
                  </div>
                </div>
                </div>
              </div>
            </div>

            <div class="preview-actions">
              <button class="secondary-btn" @click="currentStep = 2">返回修改</button>
              <button
                class="primary-btn"
                :disabled="!isValidationPassed"
                @click="showVideoPreview"
              >
                预览视频
              </button>
              <button
                class="primary-btn"
                :disabled="!isValidationPassed"
                @click="saveScript"
              >
                保存课程脚本
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- 视频预览模态框 -->
  <VideoPreview
    :visible="showVideoPreviewModal"
    :script-data="scriptData"
    :script-roles="digitalHumans"
    @close="closeVideoPreview"
  />
</template>

<script setup>
import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue'
import { ChatMessageApi } from '@/api/ai/chat/message'
import { ChatConversationApi } from '@/api/ai/chat/conversation'
import { ChatRoleApi } from '@/api/ai/model/chatRole'
import { ImageApi } from '@/api/ai/image'
import { TtsApi } from '@/api/ai/tts'
import VideoPreview from '@/views/bjdx/course/aiGenerate/VideoPreview.vue'
import { AiImageStatusEnum } from '@/views/ai/utils/constants'
import { marked } from 'marked'

// 步骤配置
const steps = [
  { id: 1, label: 'AI生成脚本' },
  { id: 2, label: '编辑脚本与媒体' },
  { id: 3, label: '预览与保存' }
]

// 当前步骤
const currentStep = ref(2)

// 步骤1数据
const scriptPrompt = ref('请给我一个讲解万有引力的课程')
const selectedMainTeacher = ref('牛顿')
const selectedAssistants = ref([])
const isGenerating = ref(false)

// 步骤2生成状态
const isGeneratingImages = ref(false)
const isGeneratingVoiceovers = ref(false)

// 数字人列表
const digitalHumans = ref([])

// 背景音类型
const backgroundMusicTypes = ref([
  { id: '轻松欢快', name: '轻松欢快', url: 'http://192.168.110.9:8080/admin-api/infra/file/29/get/20260228/bgm_1772265321253.MP3' },
])

// 从localStorage加载脚本数据
const loadScriptDataFromCache = () => {
  const cachedData = localStorage.getItem('courseScriptData')
  if (cachedData) {
    try {
      return JSON.parse(cachedData)
    } catch (error) {
      console.error('解析缓存数据失败:', error)
    }
  }
  return {
    title: '',
    sections: [
      {
        name: '环节一',
        backgroundImage: {
          prompt: '',
          url: '',
          generating: false
        },
        backgroundAudio: {
          type: '',
          url: ''
        },
        dialogues: [
          {
            type: 'digital',
            roleName: '',
            content: '',
            voiceoverUrl: '',
            generatingVoiceover: false
          },
          {
            type: 'user',
            roleName: '',
            content: '',
          }
        ]
      }
    ]
  }
}

// 脚本数据结构
const scriptData = reactive(loadScriptDataFromCache())

// 保存脚本数据到localStorage
const saveScriptDataToCache = () => {
  try {
    localStorage.setItem('courseScriptData', JSON.stringify(scriptData))
  } catch (error) {
    console.error('保存缓存数据失败:', error)
  }
}

// 清空脚本数据缓存
const clearScriptDataCache = () => {
  localStorage.removeItem('courseScriptData')
}

// 监听脚本数据变化，自动保存到缓存
watch(() => scriptData, () => {
  saveScriptDataToCache()
}, { deep: true })

// 音频播放状态
const audioState = reactive({
  currentAudio: null,
  isPlaying: false,
  currentType: '',
  currentUrl: ''
})

// 存储所有音频实例
const audioInstances = new Map()

// 计算属性：判断是否可以进入下一步
const canProceed = computed(() => {
  switch (currentStep.value) {
    case 1:
      return !!scriptPrompt.value && !!selectedMainTeacher.value
    case 2:
    case 3:
      return scriptData.sections.every(section =>
        section.backgroundImage.url && section.dialogues.every(dialogue => dialogue.type !== "digital" || dialogue.voiceoverUrl)
      )
    default:
      return false
  }
})

// 计算属性：检查是否有任何背景图正在生成
const isAnyImageGenerating = computed(() => {
  return scriptData.sections.some(section => section.backgroundImage.generating)
})

// 计算属性：检查是否有任何配音正在生成
const isAnyVoiceoverGenerating = computed(() => {
  return scriptData.sections.some(section =>
    section.dialogues.some(dialogue => dialogue.generatingVoiceover)
  )
})

// 校验结果
const isValidationPassed = ref(false)
const validationMessage = ref('')

// 视频预览状态
const showVideoPreviewModal = ref(false)

const activeConversationId = ref(null) // 选中的对话编号
const conversationInAbortController = ref() // 对话进行中 abort 控制器(控制 stream 对话)
const conversationInProgress = ref(false) // 对话是否正在进行中。目前只有【发送】消息时，会更新为 true，避免切换对话、删除对话等操作
const enableContext = ref(false) // 是否开启上下文

// 接收 Stream 消息
const receiveMessageFullText = ref('')
const scriptDataTemp = ref(null)




// 步骤1：生成脚本
const generateScript = async () => {
  isGenerating.value = true
  try {
    clearScriptDataCache()
    scriptData.title = ''
    scriptData.sections = []
    receiveMessageFullText.value = ''
    scriptDataTemp.value = null

    const role = digitalHumans.value.find(r => r.name === selectedMainTeacher.value)
    let content = scriptPrompt.value + "（主讲人：" + role.name + "[" + role.description + "]，助讲："
    let zhujiang = []

    selectedAssistants.value.forEach((rName) => {
      const role = digitalHumans.value.find(r => r.name === rName)
      zhujiang.push( role.name + "[" + role.description + "]")
    })
    content+= zhujiang.join('，') + "）";

    await createAiRoleIdConversation(13)
    currentStep.value = 2
    await doSendMessageStream(activeConversationId.value, content)

  } catch (error) {
    console.error('生成脚本失败:', error)
  } finally {
    isGenerating.value = false
  }
}

/** 选择 card 角色：新建聊天对话 */
const createAiRoleIdConversation = async (roleId) => {
  activeConversationId.value =  await ChatConversationApi.createChatConversationMy({
    roleId: roleId
  })
}

/** 真正执行【发送】消息操作 */
const doSendMessageStream = async (conversationId, content) => {
  conversationInAbortController.value = new AbortController()
  conversationInProgress.value = true
  scriptPrompt.value = ''

  try {
    let isFirstChunk = true
    await ChatMessageApi.sendChatMessageStream(
      conversationId,
      content,
      conversationInAbortController.value,
      enableContext.value,
      async (res) => {
        const { code, data, msg } = JSON.parse(res.data)
        if (code !== 0) {
          console.error(`对话异常! ${msg}`)
          return
        }

        if (data.eventType === 'TEXT') {
          if (data.receive?.content === '') {
            return
          }

          if (isFirstChunk) {
            isFirstChunk = false
          }

          receiveMessageFullText.value += data.receive.content

          try {
            const parsedData = JSON.parse(receiveMessageFullText.value)
            scriptDataTemp.value = parsedData
            Object.assign(scriptData, parsedData)
          } catch (e) {
            // 解析失败，说明数据还不完整，继续等待
          }
        }
      },
      (error) => {
        console.error(`对话异常! ${error}`)
        throw error
      },
      () => {
        try {
          if (receiveMessageFullText.value) {
            const parsedData = JSON.parse(receiveMessageFullText.value)
            scriptDataTemp.value = parsedData
            Object.assign(scriptData, parsedData)
          }
        } catch (e) {
          console.error("最终数据解析失败:", e)
        }
      }
    )
  } catch (error) {
    console.error("发送消息流失败:", error)
  } finally {
    conversationInProgress.value = false
  }
}

// 步骤2：添加环节
const addSection = () => {
  scriptData.sections.push({
    name: `环节${scriptData.sections.length + 1}`,
    backgroundImage: { prompt: '', url: '', generating: false },
    backgroundAudio: { type: '', url: '' },
    dialogues: []
  })
}

// 步骤2：添加对话（数字人）
const addDialogue = (sectionIndex) => {
  scriptData.sections[sectionIndex].dialogues.push({
    type: 'digital',
    roleName: '',
    content: '',
    voiceoverUrl: '',
    generatingVoiceover: false
  })
}

// 步骤2：添加用户回复
const addUserReply = (sectionIndex) => {
  scriptData.sections[sectionIndex].dialogues.push({
    type: 'user',
    content: '',
    roleName: '',
    voiceoverUrl: '',
    generatingVoiceover: false
  })
}

// 步骤2：删除对话
const removeDialogue = (sectionIndex, dialogueIndex) => {
  scriptData.sections[sectionIndex].dialogues.splice(dialogueIndex, 1)
}

// 步骤2：删除环节
const removeSection = (sectionIndex) => {
  if (scriptData.sections.length > 1) {
    scriptData.sections.splice(sectionIndex, 1)
  } else {
    alert('至少需要保留一个环节')
  }
}

// 图片生成相关状态
const inProgressImageMap = ref({}) // 监听的图片映射，key 为 image 编号，value 为 { sectionIndex, type: 'image'|'audio' }
const inProgressTimer = ref(null) // 生成中的图片定时器，轮询生成进展

// 步骤2：生成单个媒体（仅背景图）
const generateMedia = async (sectionIndex) => {
  const section = scriptData.sections[sectionIndex]
  const media = section.backgroundImage

  media.generating = true
  try {
    const form = {
      platform: 'DOU_BAO',
      modelId: 56,
      prompt: media.prompt,
      width: 1024,
      height: 768
    }
    const response = await ImageApi.drawImage(form)
    inProgressImageMap.value[response] = {
      sectionIndex
    }
  } catch (error) {
    console.error(`生成图片失败:`, error)
    media.generating = false
  }
}

// 步骤2：一键生成所有背景图
const generateAllImages = async () => {
  isGeneratingImages.value = true
  try {
    for (let i = 0; i < scriptData.sections.length; i++) {
      const section = scriptData.sections[i]
      // 只处理没有背景图URL的环节
      if (!section.backgroundImage.url) {
        await generateMedia(i)
      }
    }

    // 检查是否有图片正在生成
    const checkImagesComplete = setInterval(() => {
      if (Object.keys(inProgressImageMap.value).length === 0) {
        isGeneratingImages.value = false
        clearInterval(checkImagesComplete)
      }
    }, 1000)
  } catch (error) {
    console.error('生成所有背景图失败:', error)
    isGeneratingImages.value = false
  }
}



// 轮询生成中的图片列表
const refreshWatchImages = async () => {
  const imageIds = Object.keys(inProgressImageMap.value).map(Number)
  if (imageIds.length === 0) {
    return
  }

  try {
    const list = await ImageApi.getImageListMyByIds(imageIds)
    const newWatchImages = {}
    list.forEach((image) => {
      const info = inProgressImageMap.value[image.id]
      if (info) {
        if (image.status === AiImageStatusEnum.IN_PROGRESS) {
          newWatchImages[image.id] = info
        } else if (image.status === AiImageStatusEnum.SUCCESS && image.picUrl) {
          const section = scriptData.sections[info.sectionIndex]
          section.backgroundImage.url = image.picUrl
          section.backgroundImage.generating = false
        } else if (image.status === AiImageStatusEnum.FAIL) {
          const section = scriptData.sections[info.sectionIndex]
          section.backgroundImage.generating = false
        }
      }
    })
    inProgressImageMap.value = newWatchImages
  } catch (error) {
    console.error('轮询图片状态失败:', error)
  }
}

// 播放音频通用函数
const playAudio = (url, type) => {
  if (audioState.currentAudio) {
    audioState.currentAudio.pause()
    audioState.currentAudio.currentTime = 0
  }

  if (audioState.isPlaying && audioState.currentUrl === url && audioState.currentType === type) {
    if (audioState.currentAudio) {
      audioState.currentAudio.pause()
    }
    audioState.isPlaying = false
    return
  }

  let audio = audioInstances.get(`${type}_${url}`)
  if (!audio) {
    audio = new Audio(url)
    audioInstances.set(`${type}_${url}`, audio)

    audio.onended = () => {
      audioState.isPlaying = false
      audioState.currentAudio = null
      audioState.currentUrl = ''
      audioState.currentType = ''
    }
  }

  audio.play().catch(error => {
    console.error('播放失败:', error)
    audioState.isPlaying = false
  })

  audioState.currentAudio = audio
  audioState.isPlaying = true
  audioState.currentUrl = url
  audioState.currentType = type
}

// 播放语音
const playVoiceover = (voiceoverUrl) => {
  playAudio(voiceoverUrl, 'voice')
}

// 处理背景音选择变化
const handleBackgroundAudioChange = (value, section) => {
  if (value) {
    const selectedMusic = backgroundMusicTypes.value.find(music => music.id === value)
    if (selectedMusic) {
      section.backgroundAudio.url = selectedMusic.url
    }
  } else {
    section.backgroundAudio.url = ''
  }
}

// 播放背景音
const playBackgroundAudio = (musicType) => {
  const selectedMusic = backgroundMusicTypes.value.find(music => music.id === musicType)
  const audioUrl = selectedMusic ? selectedMusic.url : `https://example.com/${musicType}.mp3`
  playAudio(audioUrl, 'background')
}

// 生成单个语音
const generateVoiceover = async (sectionIndex, dialogueIndex) => {
  const dialogue = scriptData.sections[sectionIndex].dialogues[dialogueIndex]

  // 只处理数字人类型的对话
  if (dialogue.type !== 'digital') {
    return
  }

  dialogue.generatingVoiceover = true

  let role = digitalHumans.value.find(r => r.name === dialogue.roleName)

  try {
    // 调用后端API将文本转成语音
    const speechUrl = await TtsApi.convert({
      roleId: Number(role.id),
      content: dialogue.content
    })

    // 将返回的URL赋值给对话
    dialogue.voiceoverUrl = speechUrl
  } catch (error) {
    console.error('生成语音失败:', error)
  } finally {
    dialogue.generatingVoiceover = false
  }
}

// 步骤3：一键生成所有语音
const generateAllVoiceovers = async () => {
  isGeneratingVoiceovers.value = true
  try {
    for (let i = 0; i < scriptData.sections.length; i++) {
      for (let j = 0; j < scriptData.sections[i].dialogues.length; j++) {
        const dialogue = scriptData.sections[i].dialogues[j]
        // 只处理没有语音URL的对话
        if (!dialogue.voiceoverUrl) {
          await generateVoiceover(i, j)
        }
      }
    }
  } catch (error) {
    console.error('生成所有语音失败:', error)
  } finally {
    isGeneratingVoiceovers.value = false
  }
}

// 获取角色名称
const getRoleName = (roleName) => {
  const role = digitalHumans.value.find(r => r.name === roleName)
  return role ? role.name : '未知角色'
}

// 解析 Markdown 文本
const parseMarkdown = (text) => {
  if (!text) return ''
  return marked(text)
}

// 步骤4：校验脚本
const validateScript = () => {
  let isValid = true
  let message = '校验通过'

  if (!scriptData.sections.every(s => s.name.trim())) {
    isValid = false
    message = '存在空的环节名称'
  } else if (!scriptData.sections.every(s => s.backgroundImage.url)) {
    isValid = false
    message = '存在未生成的背景图'
  } else if (!scriptData.sections.every(s =>
    s.dialogues.every(d => (d.type === 'digital' && d.roleName && d.content.trim() && d.voiceoverUrl) || (d.type === 'user' && d.roleName && d.content.trim()))
  )) {
    isValid = false
    message = '存在未完成的对话或语音'
  }

  isValidationPassed.value = isValid
  validationMessage.value = message
}

// 步骤4：保存脚本
const saveScript = async () => {
  validateScript()

  if (!isValidationPassed.value) {
    return
  }
  console.log('scriptData===', JSON.stringify(scriptData))
}

// 下一步操作
const nextStep = () => {
  if (canProceed.value) {
    if (currentStep.value === 2) {
      validateScript()
    }
    currentStep.value++
  }
}

// 显示视频预览
const showVideoPreview = () => {
  showVideoPreviewModal.value = true
}

// 关闭视频预览
const closeVideoPreview = () => {
  showVideoPreviewModal.value = false
}

// 组件挂载时
onMounted(async () => {
  try {
    const params = {
      pageOn: 1,
      pageSize: 100,
      category: "小学低年级",
      publicStatus: true
    }
    const { list } = await ChatRoleApi.getMyPage(params)
    params.category += "AI"
    const { list:listAi } = await ChatRoleApi.getMyPage(params)
    list.push(...listAi)
    digitalHumans.value = list
  } catch (error) {
    console.error('获取角色数据失败:', error)
  }

  inProgressTimer.value = setInterval(async () => {
    await refreshWatchImages()
  }, 3000)
})

// 组件卸载时
onUnmounted(() => {
  if (inProgressTimer.value) {
    clearInterval(inProgressTimer.value)
  }
})
</script>

<style scoped>
.course-script-editor {
  width: 100%;
  height: 100vh;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background-color: #f8f9fa;
}

/* 主容器样式 */
.main-container {
  flex: 1;
  display: flex;
  overflow: hidden;
}

/* 左侧步骤指示器样式 */
.steps-sidebar {
  width: 200px;
  background-color: #f5f7fa;
  border-right: 1px solid #ebeef5;
  padding: 30px 0;
  display: flex;
  align-items: center;
}

/* 右侧内容区域样式 */
.content-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* 步骤内容样式 */
.step-content {
  flex: 1;
  padding: 20px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background-color: white;
  border-radius: 0;
  box-shadow: none;
}

/* 步骤1垂直居中 */
.step-content:has(.ai-input-container) {
  justify-content: center;
  align-items: center;
}

/* 编辑器工具栏样式 - 固定顶部 */
.editor-toolbar.sticky-top {
  position: sticky;
  top: 0;
  z-index: 100;
  margin-top: -20px;
  margin-left: -20px;
  margin-right: -20px;
  border-radius: 0;
  border-bottom: 1px solid #ebeef5;
  background: rgba(250, 250, 250, 0.95);
  backdrop-filter: blur(10px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

/* 脚本编辑器样式 - 可滚动 */
.script-editor {
  flex: 1;
  overflow-y: auto;
  margin-top: 20px;
  padding-right: 10px;
  background-color: white;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.script-editor::-webkit-scrollbar {
  width: 6px;
}

.script-editor::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.script-editor::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
}

.script-editor::-webkit-scrollbar-thumb:hover {
  background: #a1a1a1;
}
/* 步骤导航 */
.steps-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: 100%;
  .step-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    .step-circle {
      width: 32px;
      height: 32px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-weight: bold;
      margin-bottom: 8px;
    }
    .step-title {
      font-size: 14px;
      text-align: center;
      padding: 0 20px;
    }
    &.process {
      .step-circle {
        background-color: #409EFF;
        color: white;
      }
      .step-title {
        color: #409EFF;
      }
    }
    &.wait {
      .step-circle {
        background-color: #E4E7ED;
        color: #C0C4CC;
      }
      .step-title {
        color: #C0C4CC;
      }
    }
    &.finish {
      .step-circle {
        background-color: #67C23A;
        color: white;
      }
      .step-title {
        color: #67C23A;
      }
    }
  }
  .step-line {
    width: 2px;
    height: 40px;
    background-color: #E4E7ED;
    &.active {
      background-color: #409EFF;
    }
  }
}

/* 步骤内容 */
.step-content {
  background-color: white;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

/* 对话类型标签 */
.dialogue-type-tag {
  position: absolute;
  top: -10px;
  left: 10px;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 12px;
  font-weight: 500;
  color: white;
}

.dialogue-type-tag.digital {
  background-color: #409EFF;
}

.dialogue-type-tag.user {
  background-color: #67C23A;
}

/* 对话项样式 */
.dialogue-item {
  position: relative;
  background-color: #f9f9f9;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 15px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.dialogue-item:hover {
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.dialogue-item.digital {
  border-left: 4px solid #409EFF;
}

.dialogue-item.user {
  border-left: 4px solid #67C23A;
}

/* 对话头部 */
.dialogue-header {
  margin-bottom: 10px;
}

/* 对话行 */
.dialogue-row {
  display: flex;
  gap: 15px;
  align-items: flex-start;
}

/* 角色选择 */
.dialogue-role-select {
  flex-shrink: 0;
}

/* 回复角色选择 */
.dialogue-reply-select {
  flex-shrink: 0;
}

/* 内容容器 */
.dialogue-content-container {
  flex: 1;
  min-width: 0;
}



/* 添加对话按钮容器 */
.add-dialogue-buttons {
  display: flex;
  gap: 10px;
  margin-top: 15px;
}

/* 添加对话按钮 */
.add-dialogue-btn {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  min-width: 120px;
}

.add-dialogue-btn.digital {
  background-color: #83c2ff;
  color: white;
}

.add-dialogue-btn.digital:hover {
  background-color: #409EFF;
  border-color: #4aa2fd;
  color: white;
}

.add-dialogue-btn.user {
  background-color: #85ce61;
  color: white;
}

.add-dialogue-btn.user:hover {
  background-color: #67C23A;
  border-color: #67C23A;
  color: white;
}

/* 预览对话样式 */
.preview-dialogue {
  position: relative;
  margin-bottom: 20px;
  padding: 15px;
  border-radius: 8px;
  background-color: #f9f9f9;
}

.preview-dialogue.digital {
  border-left: 4px solid #409EFF;
}

.preview-dialogue.user {
  border-left: 4px solid #67C23A;
}

.preview-dialogue .dialogue-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0;
  margin-bottom: 10px;
}

.preview-dialogue .dialogue-header-left {
  display: flex;
  align-items: center;
  gap: 2px;
}

.preview-dialogue .dialogue-type-tag {
  position: static;
  margin-right: 2px;
}

/* 回复信息 */
.reply-info {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid #e8e8e8;
  font-size: 14px;
  color: #666;
  font-style: italic;
}

/* AI输入容器 */
.ai-input-container {
  max-width: 800px;
  margin: 0 auto;
  padding: 30px;
  background: white;
  border-radius: 16px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
  display: flex;
  flex-direction: column;
  min-height: 500px;
}

.selection-group {
  margin-bottom: 30px;
}

.ai-input-wrapper {
  margin-bottom: 30px;
}

.ai-input-container button.generate-btn.primary {
  margin-top: 30px;
  align-self: center;
}

.ai-input-wrapper {
  position: relative;
  margin-bottom: 30px;
}

.ai-icon {
  position: absolute;
  top: 20px;
  left: 20px;
  font-size: 28px;
  color: #409EFF;
  background: rgba(64, 158, 255, 0.1);
  width: 48px;
  height: 48px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: pulse 2s infinite;
}

@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(64, 158, 255, 0.4);
  }
  70% {
    box-shadow: 0 0 0 10px rgba(64, 158, 255, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(64, 158, 255, 0);
  }
}

.ai-textarea {
  width: 100%;
  min-height: 140px;
  padding: 24px 24px 24px 84px;
  border: 2px solid #e8e8e8;
  border-radius: 16px;
  font-size: 16px;
  resize: vertical;
  transition: all 0.3s ease;
  background: #fafafa;
  line-height: 1.6;
}

.ai-textarea:focus {
  outline: none;
  border-color: #409EFF;
  background: white;
  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1);
}

.selection-group {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-bottom: 30px;
}

.selection-item {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.selection-item label {
  font-weight: 600;
  color: #333;
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: #666;
}

.selection-item select {
  padding: 14px 16px;
  border: 2px solid #e8e8e8;
  border-radius: 10px;
  font-size: 14px;
  transition: all 0.3s ease;
  background: white;
}

.selection-item select:focus {
  outline: none;
  border-color: #409EFF;
  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1);
}

.multi-select {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 12px;
  border: 2px solid #e8e8e8;
  border-radius: 10px;
  background: white;
  transition: all 0.3s ease;
}

.multi-select:focus-within {
  border-color: #409EFF;
  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1);
}

.select-option {
  padding: 8px 16px;
  background: #f5f5f5;
  border-radius: 20px;
  cursor: pointer;
  transition: all 0.2s ease;
  font-size: 14px;
  font-weight: 500;
  border: 1px solid transparent;
}

.select-option:hover {
  background: #e6f7ff;
  border-color: #91d5ff;
}

.select-option.selected {
  background: #409EFF;
  color: white;
  border-color: #409EFF;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
}

/* 加载遮挡层样式 */
.loading-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  pointer-events: auto;
}

.loading-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  background: white;
  padding: 32px;
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
  pointer-events: auto;
}

.loading-spinner {
  width: 48px;
  height: 48px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #409EFF;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.loading-text {
  font-size: 16px;
  font-weight: 500;
  color: #333;
}

/* 按钮样式 */
.generate-btn {
  padding: 14px 8px;
  border: none;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 400;
  cursor: pointer;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

.generate-btn.primary {
  background: linear-gradient(135deg, #409EFF, #1890ff);
  color: white;
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
}

.generate-btn.primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(64, 158, 255, 0.4);
}

.generate-btn.primary:disabled {
  background: #91c5f7;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.generate-btn.small {
  padding: 8px 16px;
  font-size: 14px;
  border-radius: 8px;
}

.generate-btn.small:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 8px rgba(64, 158, 255, 0.3);
}

.generate-btn.small:disabled {
  background: #91c5f7;
  color: white;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.toolbar-btn:disabled {
  background: #f0f0f0;
  color: #c0c0c0;
  border-color: #e0e0e0;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.toolbar-btn:disabled:hover {
  background: #f0f0f0;
  color: #c0c0c0;
  border-color: #e0e0e0;
  transform: none;
  box-shadow: none;
}

/* 编辑器工具栏 */
.editor-toolbar {
  position: sticky;
  top: 20px;
  z-index: 100;
  margin-bottom: 30px;
  padding: 16px 20px;
  background: rgba(250, 250, 250, 0.95);
  backdrop-filter: blur(10px);
  border-radius: 12px;
  border: 1px solid #e8e8e8;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  overflow-x: auto;
  overflow-y: hidden;
  white-space: nowrap;
}

.editor-toolbar::-webkit-scrollbar {
  height: 4px;
}

.editor-toolbar::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 2px;
}

.editor-toolbar::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 2px;
}

.editor-toolbar::-webkit-scrollbar-thumb:hover {
  background: #a1a1a1;
}

.toolbar-btn {
  padding: 12px 24px;
  margin: 0 12px;
  background: white;
  border: 2px solid #e8e8e8;
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-weight: 500;
  color: #333;
}

.toolbar-btn:hover {
  background: #409EFF;
  color: white;
  border-color: #409EFF;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
}

/* 脚本编辑器 */
.script-section {
  margin-top: 40px;
  margin-bottom: 40px;
  padding: 5px 24px 24px;
  background: white;
  border-radius: 16px;
  position: relative;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
  border: 1px solid #f0f0f0;
}

.section-header {
  margin-bottom: 24px;
  display: flex;
  align-items: center;
  gap: 16px;
}

.section-name-container {
  display: flex;
  align-items: center;
  flex: 1;
  gap: 12px;
  margin-top: 16px;
}

.remove-section-btn {
  background: #ff4d4f;
  border: none;
  color: white;
  font-size: 16px;
  cursor: pointer;
  padding: 0;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  transition: all 0.3s ease;
  flex-shrink: 0;
}

.remove-section-btn:hover {
  background: #ff7875;
  transform: scale(1.1);
  box-shadow: 0 2px 8px rgba(255, 77, 79, 0.3);
}

.section-name-label {
  padding: 2px 15px;
  border-radius: 10px;
  font-size: 18px;
  font-weight: 500;
  color: white;
  background-color: #c18484;
  white-space: nowrap;
  display: flex;
  align-items: center;
  height: 44px;
  box-sizing: border-box;
}

.section-title {
  flex: 1;
  padding: 14px 16px;
  border: 2px solid #e8e8e8;
  border-radius: 10px;
  font-size: 16px;
  font-weight: 500;
  transition: all 0.3s ease;
}

.section-title:focus {
  outline: none;
  border-color: #409EFF;
  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1);
}

.media-controls {
  display: flex;
  background: linear-gradient(135deg, #f8f9fa, #ffffff);
  padding: 16px 20px;
  border-radius: 10px;
  border: 1px solid #e8e8e8;
  align-items: center;
  justify-content: space-between;
}

.media-item {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-right: 50px;
}

.media-input-group {
  display: flex;
  align-items: center;
  gap: 10px;
}

.media-label {
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  color: #666;
}

.media-prompt {
  font-size: 14px;
  transition: all 0.3s ease;
  width: 300px;
}

.media-prompt .el-textarea {
  width: 100%;
  min-height: 60px;
}

.media-prompt .el-textarea__inner {
  padding: 8px 12px;
  border: 2px solid #e8e8e8;
  border-radius: 8px;
  font-size: 14px;
  transition: all 0.3s ease;
  min-height: 60px;
  resize: none;
}

.media-prompt .el-textarea__inner:focus {
  outline: none;
  border-color: #409EFF;
  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1);
}

.media-preview {
  margin-top: 12px;
  margin-left: 20px;
}

.media-preview img {
  max-width: 180px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s ease;
}

.media-preview img:hover {
  transform: scale(1.05);
}

.dialogues-container {
  margin-top: 48px;
}

.dialogue-item {
  margin-bottom: 20px;
  padding: 20px;
  background: #fafafa;
  border-radius: 12px;
  border: 1px solid #e8e8e8;
  transition: all 0.3s ease;
}

.dialogue-item:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  transform: translateY(-2px);
}

.dialogue-row {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}

.dialogue-role-select {
  min-width: 140px;
}

.dialogue-role-select select {
  width: 100%;
  padding: 10px 12px;
  border: 2px solid #e8e8e8;
  border-radius: 8px;
  font-size: 14px;
  transition: all 0.3s ease;
}

.dialogue-role-select select:focus {
  outline: none;
  border-color: #409EFF;
  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1);
}

.dialogue-content-container {
  flex: 1;
}

.dialogue-content:focus {
  outline: none;
  border-color: #409EFF;
  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1);
}

.remove-btn {
  background: #ff4d4f;
  border: none;
  color: white;
  font-size: 16px;
  cursor: pointer;
  padding: 0;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  transition: all 0.3s ease;
  flex-shrink: 0;
}

.remove-btn:hover {
  background: #ff7875;
  transform: scale(1.1);
  box-shadow: 0 2px 8px rgba(255, 77, 79, 0.3);
}

.dialogue-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.dialogue-text {
  flex: 1;
  width: 100%;
  font-size: 16px;
  line-height: 1.6;
}

.generate-btn.small {
  padding: 8px;
  background: linear-gradient(135deg, #409EFF, #1890ff);
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 28px;
  font-size: 14px;
}

.generate-btn.small:hover {
  transform: scale(1.1);
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
}

.play-btn {
  padding: 8px;
  background: #52c41a;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  font-size: 14px;
}

.play-btn:hover {
  background: #73d13d;
  transform: scale(1.1);
  box-shadow: 0 2px 8px rgba(82, 196, 26, 0.3);
}

.play-btn.small {
  padding: 8px;
  width: 28px;
  height: 28px;
  font-size: 14px;
}

.voice-icon {
  font-size: 14px;
  line-height: 1;
}

.play-icon {
  font-size: 14px;
  line-height: 1;
}

.action-buttons {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-left: 8px;
}

.action-buttons-row {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: flex-end;
}



.add-dialogue-btn,
.add-section-btn {
  padding: 12px 24px;
  background: white;
  border: 2px dashed #d9d9d9;
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-weight: 500;
  color: #666;
  margin-top: 16px;
  width: 100%;
  text-align: center;
}

.add-dialogue-btn:hover,
.add-section-btn:hover {
  border-color: #c18484;
  color: white;
  background: rgba(193, 132, 132, 0.6);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
}



/* 预览页面 */
.preview-container {
  width: 100%;
  height: 100%;
  background: white;
  border-radius: 16px;
  padding: 30px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
  display: flex;
  flex-direction: column;
}

.preview-content {
  flex: 1;
  overflow-y: auto;
  margin-top: 20px;
  margin-bottom: 30px;
  padding-right: 10px;
}

.preview-content::-webkit-scrollbar {
  width: 6px;
}

.preview-content::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.preview-content::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
}

.preview-content::-webkit-scrollbar-thumb:hover {
  background: #a1a1a1;
}

.preview-actions {
  margin-top: auto;
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

.validation-result {
  padding: 16px 20px;
  border-radius: 10px;
  font-weight: 500;
  font-size: 14px;
}

.validation-result.valid {
  background: #f6ffed;
  border: 2px solid #b7eb8f;
  color: #52c41a;
  box-shadow: 0 2px 8px rgba(82, 196, 26, 0.1);
}

.validation-result.invalid {
  background: #fff2f0;
  border: 2px solid #ffccc7;
  color: #ff4d4f;
  box-shadow: 0 2px 8px rgba(255, 77, 79, 0.1);
}

.preview-section {
  margin-bottom: 40px;
  padding: 40px;
  border-radius: 12px;
  border: 1px solid #e8e8e8;
  min-height: 300px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.preview-section h4 {
  margin-top: 0;
  color: #333;
  font-size: 18px;
  font-weight: 600;
  margin-bottom: 20px;
}

.preview-section-content {
  background: rgba(255, 255, 255, 0.2);
  padding: 20px;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(5px);
  width: 80%  ;
}

.preview-media {
  margin: 20px 0;
  padding: 16px;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 10px;
  border: 1px solid #e8e8e8;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}

.preview-media-left {
  display: flex;
  align-items: center;
  gap: 12px;
}

.preview-media-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.preview-image img {
  max-width: 250px;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s ease;
}

.preview-image img:hover {
  transform: scale(1.05);
}

.preview-audio{
  float: right;
  margin-right: 20px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.preview-dialogue {
  margin-bottom: 20px;
  padding: 16px;
  background: white;
  border-radius: 10px;
  border: 1px solid #e8e8e8;
  transition: all 0.3s ease;
}

.dialogue-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.preview-dialogue:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.dialogue-role {
  font-weight: 600;
  color: #409EFF;
  font-size: 14px;
}

.dialogue-text {
  line-height: 1.6;
  font-size: 14px;
  color: #333;
}

/* Markdown 样式 */
.dialogue-text h1,
.dialogue-text h2,
.dialogue-text h3,
.dialogue-text h4,
.dialogue-text h5,
.dialogue-text h6 {
  margin: 16px 0 8px 0;
  font-weight: 600;
  line-height: 1.2;
}

.dialogue-text h1 { font-size: 24px; }
.dialogue-text h2 { font-size: 20px; }
.dialogue-text h3 { font-size: 18px; }
.dialogue-text h4 { font-size: 16px; }
.dialogue-text h5 { font-size: 14px; }
.dialogue-text h6 { font-size: 12px; }

.dialogue-text p {
  margin: 8px 0;
}

.dialogue-text ul,
.dialogue-text ol {
  margin: 8px 0;
  padding-left: 24px;
}

.dialogue-text li {
  margin: 4px 0;
}

.dialogue-text strong {
  font-weight: 600;
}

.dialogue-text em {
  font-style: italic;
}

.dialogue-text a {
  color: #409EFF;
  text-decoration: none;
}

.dialogue-text a:hover {
  text-decoration: underline;
}

.dialogue-text code {
  background: #f5f5f5;
  padding: 2px 4px;
  border-radius: 4px;
  font-family: 'Courier New', Courier, monospace;
  font-size: 14px;
}

.dialogue-text pre {
  background: #f5f5f5;
  padding: 12px;
  border-radius: 8px;
  overflow-x: auto;
  margin: 12px 0;
}

.dialogue-text pre code {
  background: none;
  padding: 0;
}

.voiceover-preview {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid #f0f0f0;
}

.preview-actions {
  display: flex;
  justify-content: center;
  gap: 20px;
  padding-top: 24px;
  border-top: 1px solid #e8e8e8;
}

.primary-btn,
.secondary-btn {
  padding: 14px 32px;
  border: none;
  border-radius: 12px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

.primary-btn {
  background: linear-gradient(135deg, #409EFF, #1890ff);
  color: white;
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
}

.primary-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(64, 158, 255, 0.4);
}

.primary-btn:disabled {
  background: #91c5f7;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.secondary-btn {
  background: white;
  color: #333;
  border: 2px solid #e8e8e8;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.secondary-btn:hover {
  background: #fafafa;
  border-color: #409EFF;
  color: #409EFF;
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
}
</style>
