<template>
  <Dialog
    :title="'AI生成课程'"
    v-model="dialogVisible"
    width="90%"
    :fullscreen="true"
    @update:fullscreen="(value) => (fullscreen = value)"
  >
    <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 class="selection-item">
                  <label>主题类型</label>
                  <el-select
                    v-model="selectedThemeType"
                    size="large"
                    placeholder="请选择主题类型"
                    style="width: 300px"
                  >
                    <el-option label="课程通用" value="13" />
                    <el-option label="诗词课" value="256" />
                  </el-select>
                </div>
              </div>

              <div class="button-group">
                <button
                  class="generate-btn primary"
                  :disabled="
                    !scriptPrompt || !selectedMainTeacher || !selectedThemeType || isGenerating
                  "
                  @click="generateScript"
                >
                  {{ isGenerating ? '生成中...' : '生成课程脚本' }}
                </button>
                <button
                  v-if="hasDraftCache"
                  class="generate-btn secondary"
                  @click="loadDraftAndGotoStep2"
                >
                  查看草稿
                </button>
              </div>
            </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: fullscreen ? '240px' : '130px' }"
                        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, { hidden: dialogue.type === 'user' }]"
                  >
                    <div class="dialogue-header">
                      <div class="dialogue-type-tag" :class="dialogue.type">
                        {{
                          dialogue.type === 'digital'
                            ? '数字人'
                            : dialogue.type === 'user'
                              ? '用户'
                              : dialogue.type === 'quest'
                                ? '提问'
                                : '诗词'
                        }}
                      </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>

                      <!-- 提问 -->
                      <template v-else-if="dialogue.type === 'quest'">
                        <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 === 'poem'">
                        <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>
                    </div>
                  </div>

                  <div class="add-dialogue-buttons">
                    <button class="add-dialogue-btn digital" @click="addDialogue(sectionIndex)"
                      >+ 添加对话</button
                    >
                    <button
                      class="add-dialogue-btn quest-user"
                      @click="addQuestWithUserReply(sectionIndex)"
                      >+ 添加提问与回复</button
                    >
                    <button class="add-dialogue-btn poem" @click="addPoemDialogue(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" @click="nextStep"> 预览完整脚本 </button>
            </div>
          </div>

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

              <div class="scrollable-content">
                <br />

                <div v-if="isValidationPassed" class="validation-result valid">
                  {{ validationMessage }}
                </div>
                <div v-else>
                  <div
                    v-for="(error, index) in errorMessages"
                    :key="index"
                    class="validation-result invalid"
                  >
                    {{ error }}
                  </div>
                </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.filter(
                            (d) => d.type !== 'user'
                          )"
                          :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'
                                    ? '数字人'
                                    : dialogue.type === 'user'
                                      ? '用户'
                                      : dialogue.type === 'quest'
                                        ? '提问'
                                        : '诗词'
                                }}
                              </div>
                              <div class="dialogue-role">
                                {{
                                  dialogue.type !== 'user'
                                    ? getRoleName(dialogue.roleName)
                                    : '用户'
                                }}：
                              </div>
                            </div>
                            <button
                              v-if="dialogue.voiceoverUrl"
                              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>

              <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>

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

<script setup>
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
import { Dialog } from '@/components/Dialog'
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, AiPlatformEnum } from '@/views/ai/utils/constants'
import { marked } from 'marked'
import { useUserStore } from '@/store/modules/user'

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

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

// 步骤1数据
const scriptPrompt = ref('')
const selectedMainTeacher = ref('')
const selectedAssistants = ref([])
const selectedThemeType = ref()
const isGenerating = ref(false)

// 对话框可见性
const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  },
  initialStep: {
    type: Number,
    default: 1
  },
  initialScriptData: {
    type: String,
    default: ''
  }
})

const dialogVisible = computed({
  get: () => props.visible,
  set: (value) => emit('update:visible', value)
})

// 获取用户信息
const userStore = useUserStore()
const userId = computed(() => userStore.getUser.id)

// 检查是否存在草稿缓存
const hasDraftCache = ref(false)

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

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

// 背景音类型
const backgroundMusicTypes = ref([
  {
    id: '轻松欢快',
    name: '轻松欢快',
    url: 'https://learn-aliyun-oss.oss-cn-beijing.aliyuncs.com/20260310/AI_1773106630966.MP3'
  }
])

// 从localStorage加载脚本数据
const loadScriptDataFromCache = () => {
  try {
    const key = `courseScriptData_${userId.value}`
    const cachedData = localStorage.getItem(key)
    if (cachedData) {
      try {
        return JSON.parse(cachedData)
      } catch (error) {
        console.error('解析缓存数据失败:', error)
      }
    }
  } catch (error) {
    console.error('获取用户信息失败:', error)
  }
  return null
}

// 是否为编辑模式
const isEditMode = ref(false)

// 脚本数据结构
const scriptData = reactive(
  loadScriptDataFromCache() || {
    title: '',
    sections: [
      {
        name: '环节一',
        backgroundImage: {
          prompt: '',
          url: '',
          generating: false
        },
        backgroundAudio: {
          type: '',
          url: ''
        },
        dialogues: [
          {
            type: 'digital',
            roleName: '',
            content: '',
            voiceoverUrl: '',
            generatingVoiceover: false
          },
          {
            type: 'user',
            roleName: '',
            content: ''
          }
        ]
      }
    ]
  }
)

// 保存脚本数据到localStorage
const saveScriptDataToCache = () => {
  try {
    const key = `courseScriptData_${userId.value}`
    localStorage.setItem(key, JSON.stringify(scriptData))
    hasDraftCache.value = true
    console.log('保存脚本数据到缓存', key)
  } catch (error) {
    console.error('保存缓存数据失败:', error)
  }
}

// 清空脚本数据缓存
const clearScriptDataCache = () => {
  const key = `courseScriptData_${userId.value}`
  localStorage.removeItem(key)
  hasDraftCache.value = false
  console.log('清除脚本数据缓存', key)
}

// 加载草稿并跳转到步骤2
const loadDraftAndGotoStep2 = () => {
  const cachedData = loadScriptDataFromCache()
  if (cachedData) {
    Object.assign(scriptData, cachedData)
    currentStep.value = 2
  }
}

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

// 监听对话框可见性变化
watch(
  () => props.visible,
  (newVisible, oldVisible) => {
    if (newVisible) {
      // 对话框打开时，设置初始步骤
      currentStep.value = props.initialStep
      // 清空被替换的URL集合
      replacedUrls.value.clear()
      // 处理脚本数据
      if (props.initialScriptData) {
        // 标记为编辑模式
        isEditMode.value = true
        try {
          const parsedData = JSON.parse(props.initialScriptData)
          Object.assign(scriptData, parsedData)
        } catch (error) {
          console.error('解析脚本数据失败:', error)
          // 解析失败，尝试加载草稿
          const cachedData = loadScriptDataFromCache()
          if (cachedData) {
            Object.assign(scriptData, cachedData)
          }
        }
      } else {
        // 标记为新建模式
        isEditMode.value = false
        // 没有脚本数据，尝试加载草稿
        const cachedData = loadScriptDataFromCache()
        if (cachedData) {
          Object.assign(scriptData, cachedData)
        }
      }
    } else if (oldVisible) {
      // 对话框关闭时
      if (props.initialScriptData) {
        // 编辑进来的，清空缓存
        clearScriptDataCache()
      }
      // 重置编辑模式标记
      isEditMode.value = false
      // 新增进来的，保留缓存
    }
  }
)

// 音频播放状态
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 && !!selectedThemeType.value
    case 2:
    case 3:
      return scriptData.sections.every(
        (section) =>
          section.backgroundImage.url &&
          section.dialogues.every(
            (dialogue) =>
              (dialogue.type === 'digital' ||
                dialogue.type === 'quest' ||
                dialogue.type === 'poem') &&
              dialogue.roleName &&
              dialogue.content.trim() &&
              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 errorMessages = ref([])

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

// 全屏状态
const fullscreen = ref(false)

// 存储被替换的URL链接集合
const replacedUrls = ref(new Set())

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(Number(selectedThemeType.value))
    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

          console.log('数据加载中..')
          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) {
            console.log('最终数据:', receiveMessageFullText.value)
            const parsedData = JSON.parse(receiveMessageFullText.value)
            console.log('最终数据json:', parsedData)

            scriptDataTemp.value = parsedData
            Object.assign(scriptData, parsedData)
          }
        } catch (e) {
          console.error('最终数据解析失败:', e)

          // 清洗规则：移除```json、```、** 等非JSON标记，只保留中间的JSON内容
          try {
            let cleanJsonStr = receiveMessageFullText.value
            const parsedData = JSON.parse(
              cleanJsonStr
                .replace(/^```json\s*/, '')
                .replace(/\s*```$/, '')
                .replace(/\*\*/g, '')
                .trim()
            )
            console.log('最终清洗后数据json:', parsedData)
            scriptDataTemp.value = parsedData
            Object.assign(scriptData, parsedData)
          } catch (cleanError) {
            console.error('清洗后数据解析失败:', cleanError)
          }
        }
      }
    )
  } 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 addQuestDialogue = (sectionIndex) => {
  scriptData.sections[sectionIndex].dialogues.push({
    type: 'quest',
    content: '',
    roleName: '',
    voiceoverUrl: '',
    generatingVoiceover: false
  })
}

// 步骤2：添加诗词
const addPoemDialogue = (sectionIndex) => {
  scriptData.sections[sectionIndex].dialogues.push({
    type: 'poem',
    content: '',
    roleName: '',
    voiceoverUrl: '',
    generatingVoiceover: false
  })
}

// 步骤2：添加提问与用户回复
const addQuestWithUserReply = (sectionIndex) => {
  // 添加提问类型对话
  scriptData.sections[sectionIndex].dialogues.push({
    type: 'quest',
    content: '',
    roleName: '',
    voiceoverUrl: '',
    generatingVoiceover: false
  })
  // 添加用户回复类型对话
  scriptData.sections[sectionIndex].dialogues.push({
    type: 'user',
    content: '',
    roleName: '',
    voiceoverUrl: '',
    generatingVoiceover: false
  })
}

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

  // 如果是提问类型，同时删除后面的用户回复
  if (
    dialogue.type === 'quest' &&
    dialogueIndex < dialogues.length - 1 &&
    dialogues[dialogueIndex + 1].type === 'user'
  ) {
    dialogues.splice(dialogueIndex, 2)
  } else {
    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

  // 记录旧的URL
  let oldUrl = null
  if (media.url) {
    oldUrl = media.url
    replacedUrls.value.add(oldUrl)
  }

  media.generating = true
  try {
    const form = {
      platform: AiPlatformEnum.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
    // 生成失败，从replacedUrls中移除旧URL
    if (oldUrl) {
      replacedUrls.value.delete(oldUrl)
    }
  }
}

// 步骤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
          // 生成失败，从replacedUrls中移除旧URL
          if (section.backgroundImage.url) {
            replacedUrls.value.delete(section.backgroundImage.url)
          }
        }
      }
    })
    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)
    audio.autoplay = false
    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' && dialogue.type !== 'quest' && dialogue.type !== 'poem') {
    return
  }

  // 记录旧的URL
  let oldUrl = null
  if (dialogue.voiceoverUrl) {
    oldUrl = dialogue.voiceoverUrl
    replacedUrls.value.add(oldUrl)
  }

  dialogue.generatingVoiceover = true

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

  try {
    // 根据对话类型设置不同的command
    const command =
      dialogue.type === 'poem' ? '要有感情的朗读诗词语句，要符合诗词的节奏和韵律。' : null

    // 调用后端API将文本转成语音
    // 将返回的URL赋值给对话
    dialogue.voiceoverUrl = await TtsApi.convert({
      roleId: Number(role.id),
      content: dialogue.content,
      command: command
    })
  } catch (error) {
    console.error('生成语音失败:', error)
    // 生成失败，从replacedUrls中移除旧URL
    if (oldUrl) {
      replacedUrls.value.delete(oldUrl)
    }
  } 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
  errorMessages.value = []

  // 检查环节名称、背景图
  scriptData.sections.forEach((section, sectionIndex) => {
    if (!section.name.trim() || !section.backgroundImage.url) {
      errorMessages.value.push(`环节${sectionIndex + 1}：名称或背景图未配置！`)
      isValid = false
    }

    // 检查对话
    section.dialogues.forEach((dialogue, dialogueIndex) => {
      // 只检查数字人、提问和诗词类型的对话
      if (dialogue.type === 'digital' || dialogue.type === 'quest' || dialogue.type === 'poem') {
        if (
          !dialogue.roleName ||
          !dialogue.content.trim() ||
          (dialogue.type !== 'poem' && !dialogue.voiceoverUrl)
        ) {
          errorMessages.value.push(
            `环节${sectionIndex + 1}：对话${dialogueIndex + 1}：存在完成内容！`
          )
          isValid = false
        }
      }
    })
  })

  isValidationPassed.value = isValid
  validationMessage.value = errorMessages.value.length > 0 ? '校验失败' : '校验通过'
}

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

  if (!isValidationPassed.value) {
    return
  }

  // 保存脚本后清除缓存
  clearScriptDataCache()
  emit('save', scriptData, [...replacedUrls.value])
  emit('update:visible', false)
}

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

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

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

// 组件挂载时
onMounted(async () => {
  // 设置初始步骤
  currentStep.value = props.initialStep

  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)
    params.category = '全部'
    const { list: listAll } = await ChatRoleApi.getMyPage(params)
    params.category = '全部-Poet'
    const { list: listAllPoet } = await ChatRoleApi.getMyPage(params)
    listAi.push(...list)
    listAi.push(...listAll)
    listAi.push(...listAllPoet)
    digitalHumans.value = listAi
  } catch (error) {
    console.error('获取角色数据失败:', error)
  }

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

// 关闭事件
const emit = defineEmits(['update:visible', 'save'])
const handleClose = () => {
  emit('update:visible', false)
}

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

<style scoped>
.course-script-editor {
  width: 100%;
  height: 90vh;
  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);
}

/* 按钮组样式 */
.button-group {
  display: flex;
  gap: 10px;
  margin-top: 20px;
  justify-content: center;
}

/* 次要按钮样式 */
.generate-btn.secondary {
  background-color: #606266;
  color: white;
}

.generate-btn.secondary:hover {
  background-color: #ffaa72;
  color: white;
}

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

/* 隐藏用户回复卡片 */
.dialogue-item.hidden {
  display: none;
}

/* 错误信息项样式 */
.error-item {
  margin-bottom: 8px;
  line-height: 1.4;
}

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

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

.dialogue-type-tag.quest {
  background-color: #e6a23c;
}

.dialogue-type-tag.poem {
  background-color: #909399;
}

/* 对话项样式 */
.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-item.quest {
  border-left: 4px solid #e6a23c;
}

/* 对话头部 */
.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.quest {
  background-color: #e6a23c;
  color: white;
}

.add-dialogue-btn.poem {
  background-color: #909399;
  color: white;
}

.add-dialogue-btn.quest-user {
  background-color: #e6a23c;
  color: white;
}

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

.add-dialogue-btn.quest:hover {
  background-color: #cf9236;
  border-color: #cf9236;
  color: white;
}

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

.add-dialogue-btn.poem:hover {
  background-color: #73767a;
  border-color: #73767a;
  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.quest {
  border-left: 4px solid #e6a23c;
}

.preview-dialogue.poem {
  border-left: 4px solid #909399;
}

.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-group {
  display: flex;
  gap: 10px;
  margin-top: 30px;
  justify-content: center;
}

.ai-input-container .button-group button {
  flex: 1;
  min-width: 200px;
  text-align: 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;
}

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

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

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

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

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

.preview-content {
  margin-top: 20px;
  margin-bottom: 30px;
}

.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>
