<template>
  <div class="dialog-content-wrapper">
    <!-- 遮罩层 -->
    <div v-if="showMask" class="mask-layer" ref="maskLayer">
      <div class="play-button-container">
        <button class="play-button" @click="startPlayback">
          <el-icon class="play-icon"><VideoPlay /></el-icon>
        </button>
      </div>
    </div>
    <!-- 标题 -->
    <div class="title-box">
      <!-- 返回 -->
      <div class="title-left">
        <div class="box-icon" @click="goBackToMain">
          <el-icon class="left-icon"><ArrowLeftBold /></el-icon>
          {{ backText }}
        </div>
      </div>
      <!-- 标题 -->
      <div class="title-center">
        <div class="title-text" :title="currentSection?.name">
          {{ currentSection?.name }}
        </div>
      </div>
      <!-- 左右按钮 -->
      <div class="title-right">
        <div class="arrow-icon-circle" @click="playPrevious" :class="{ 'disabled': currentSectionIndex === 0 && currentDialogueIndex === 0 }">
          <el-icon class="arrow-icon"><CaretLeft /></el-icon>
        </div>
        <div class="arrow-icon-circle" @click="togglePlay">
          <span class="play-text">{{ isPlaying ? '暂停' : '自动' }}</span>
        </div>
        <div class="arrow-icon-circle" @click="playNext" :class="{ 'disabled': currentSectionIndex === scriptData.sections.length - 1 && currentDialogueIndex === currentSection.dialogues.length - 1 }">
          <el-icon class="arrow-icon"><CaretRight /></el-icon>
        </div>
      </div>
    </div>

    <!-- 内容区域 -->
    <div class="content-box">
      <!-- 人物形象 -->
      <div
        v-if="currentDialogue && (currentDialogue.type === 'digital' || currentDialogue.type === 'quest')"
        :key="`character-${currentDialogueIndex}`"
        class="character"
        :class="{
          'left': getCharacterSide(currentDialogue.roleName) === 'left',
          'right': getCharacterSide(currentDialogue.roleName) === 'right'
        }"
        :style="{ backgroundImage: `url(${getCharacterImage(currentDialogue.roleName)})` }"
      ></div>

      <!-- 对话卡片 -->
      <div
        v-if="currentDialogue && (currentDialogue.type === 'digital' || currentDialogue.type === 'quest')"
        :key="`dialogue-${currentDialogueIndex}`"
        class="dialogue-card"
        :class="{
          'left': getCharacterSide(currentDialogue.roleName) === 'left',
          'right': getCharacterSide(currentDialogue.roleName) === 'right'
        }"
      >
        <div class="dialogue-header">
          <span class="role-name">{{ currentDialogue?.roleName }}</span>
        </div>
        <div class="dialogue-content" v-html="parseMarkdown(currentDialogue.content)"></div>
      </div>

      <!-- 用户输入卡片 -->
      <div
        v-if="currentDialogue.type === 'user'"
        class="dialogue-card user-input-card"
      >
        <div class="dialogue-header">
          <span class="role-name">我</span>
        </div>
        <div class="dialogue-content">
          <textarea
            :value="userInput"
            @input="e => userInput = e.target.value"
            class="user-input-textarea"
            placeholder="请输入内容..."
            @keyup.enter.exact="submitUserInput"
          ></textarea>
          <div class="input-actions">
            <button class="cancel-btn" @click="cancelUserInput">清空</button>
            <button class="submit-btn" @click="submitUserInput">发送</button>
          </div>
        </div>
      </div>

      <!-- 输入按钮区域 -->
      <div class="input-buttons-container" v-if="currentDialogue.type === 'user'">
        <!-- 语音输入按钮 -->
        <div class="voice-input-outer" :class="{ 'recording': isVoiceRecording }">
          <VoiceInput 
            @voiceRecognized="handleVoiceRecognized" 
            @recordingStatusChanged="handleRecordingStatusChanged"
          />
        </div>
      </div>
    </div>

    <img :src="currentBackgroundImage" alt="背景图" class="background-image">
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { useRouter } from 'vue-router'
import { ArrowLeftBold, CaretLeft, CaretRight, Grid, VideoPlay } from '@element-plus/icons-vue'
import VoiceInput from '@/components/ai/voice/VoiceInput.vue'
import { marked } from 'marked'
import {CreateDialogue, sendChatMessageStream} from "@/api/questions.js";
import {useAudioPlayer} from "@/api/tts/useAudioPlayer.js";
import {Message} from "@/utils/message/Message.js";

const { playAudioChunk , stopPlayback, setOnPlaybackComplete  } = useAudioPlayer();

// 路由实例
const router = useRouter()

const props = defineProps({
  scriptData: {
    type: Object,
    default: () => ({
      title: "",
      sections: []
    })
  },
  scriptRoles: {
    type: Array,
    default: () => []
  },
  backText: {
    type: String,
    default: '返回课程'
  }
})

// 对话相关状态
// 当前章节索引
const currentSectionIndex = ref(0)
// 当前对话索引
const currentDialogueIndex = ref(0)
// 是否正在播放
const isPlaying = ref(false)
// 用户输入内容
const userInput = ref('')
// 语音录音状态
const isVoiceRecording = ref(false)
// 实时语音识别结果
const voiceRecognizedText = ref("")
// 录音开始时的光标位置
const recordingStartCursorPos = ref(0)
// 录音开始时的原始文本
const recordingStartText = ref("")

// 音频对象
// 背景音频
const backgroundAudio = ref(null)
// 对话音频
const dialogueAudio = ref(null)
// 遮罩层显示状态
const showMask = ref(true)

// 计算属性
// 当前章节信息
const currentSection = computed(() => {
  return props.scriptData.sections[currentSectionIndex.value]
})
// 当前对话信息
const currentDialogue = computed(() => {
  if (!currentSection.value) return null
  return currentSection.value.dialogues[currentDialogueIndex.value]
})

const currentBackgroundImage = computed(() => {
  if (!currentSection.value || !currentSection.value.backgroundImage || !currentSection.value.backgroundImage.url) {
    return ''
  }
  return currentSection.value.backgroundImage.url
})

// 当前对话缓存
const currentDialogueCache = ref(null)

// 方法
const handleVoiceRecognized = (text) => {
  console.log('语音识别结果:', text)
  if (isVoiceRecording.value) {
    // 在同一次录音过程中，实时更新文本框内容
    voiceRecognizedText.value = text
    const textarea = document.querySelector('.user-input-textarea')
    if (textarea) {
      // 使用录音开始时的原始文本和光标位置
      const startPos = recordingStartCursorPos.value
      const originalText = recordingStartText.value
      // 在光标位置插入实时识别结果
      userInput.value = originalText.substring(0, startPos) + text + originalText.substring(startPos)
    }
  } else {
    // 在录音结束时，将最终的语音内容追加到userInput.value
    const textarea = document.querySelector('.user-input-textarea')
    if (textarea) {
      // 使用录音开始时的光标位置和原始文本
      const startPos = recordingStartCursorPos.value
      const originalText = recordingStartText.value
      // 在光标位置插入文本
      userInput.value = originalText.substring(0, startPos) + text + originalText.substring(startPos)
      // 重新设置光标位置到插入文本的末尾
      setTimeout(() => {
        textarea.selectionStart = textarea.selectionEnd = startPos + text.length
      }, 0)
    } else {
      // 如果没有找到输入框，直接替换整个内容
      userInput.value = text
    }
    // 清空临时变量
    voiceRecognizedText.value = ""
  }
}

// 处理录音状态变化
const handleRecordingStatusChanged = (isRecording) => {
  console.log('录音状态:', isRecording)
  const wasRecording = isVoiceRecording.value
  isVoiceRecording.value = isRecording

  // 如果是从未录音状态切换到录音状态，记录当前光标位置和文本内容
  if (!wasRecording && isRecording) {
    const textarea = document.querySelector('.user-input-textarea')
    if (textarea) {
      recordingStartCursorPos.value = textarea.selectionStart
      recordingStartText.value = userInput.value
    } else {
      recordingStartCursorPos.value = 0
      recordingStartText.value = userInput.value
    }
  }

  // 如果是从录音状态切换到非录音状态，只需要清空临时变量
  if (wasRecording && !isRecording) {
    // 清空临时变量
    voiceRecognizedText.value = ""
  }
}

// 提交用户输入
const submitUserInput = async () => {
  if (userInput.value.trim()) {
    console.log('用户输入:', userInput.value)
    
    await createAiChart();
    await doSendMessage();
  }
}

// 取消用户输入
const cancelUserInput = () => {
  userInput.value = ''
}

// 解析 Markdown 内容
const parseMarkdown = (content) => {
  if (!content) return ''
  return marked(content)
}

const getCharacterSide = () => {
  return currentDialogueIndex.value % 2 === 0 ? 'left' : 'right'
  
}

// 根据角色ID获取角色名称
const getRole = (roleName) => {
  return props.scriptRoles.find(r => r.name === roleName)
}

const getCharacterImage = (roleName) => {
  const role = getRole(roleName)
  return role ? role.avatar : ''
}

const stopAllAudio = () => {
  if (backgroundAudio.value) {
    backgroundAudio.value.pause()
    backgroundAudio.value.currentTime = 0
  }
  if (dialogueAudio.value) {
    dialogueAudio.value.pause()
    dialogueAudio.value.currentTime = 0
  }
}

const playBackgroundAudio = () => {
  // 停止之前的背景音
  if (backgroundAudio.value) {
    backgroundAudio.value.pause()
    backgroundAudio.value.currentTime = 0
  }
  
  // 播放当前环节的背景音
  if (currentSection.value?.backgroundAudio?.url && isPlaying.value) {
    backgroundAudio.value = new Audio(currentSection.value.backgroundAudio.url)
    backgroundAudio.value.loop = true
    backgroundAudio.value.volume = 1
    backgroundAudio.value.play().catch(e => console.error('背景音播放失败:', e))
  }
}

const playDialogueAudio = (isAutoPlay = false) => {
  // 停止之前的对话语音
  if (dialogueAudio.value) {
    dialogueAudio.value.pause()
    dialogueAudio.value.currentTime = 0
  }
  
  // 播放当前对话的语音
  if (currentDialogue.value?.voiceoverUrl) {
    const audio = new Audio(currentDialogue.value.voiceoverUrl)
    dialogueAudio.value = audio
    
    // 音频结束事件
    audio.onended = () => {
      // 如果是自动播放状态，继续播放下一条
      if (isAutoPlay && isPlaying.value) {
        setTimeout(() => {
          if (!playNext(true)) {
            // 播放完毕
            isPlaying.value = false
            stopAllAudio()
          }
        }, 100)
      }
    }
    
    // 播放音频
    audio.play().catch(e => {
      console.error('对话语音播放失败:', e)
      // 播放失败时，2秒后跳转（暂时注销，因为会导致user类型数字人回复播报跳转后语音播报报错，直接2秒跳转）
      // if (isAutoPlay && isPlaying.value) {
      //   setTimeout(() => {
      //     if (!playNext(true)) {
      //       // 播放完毕
      //       isPlaying.value = false
      //       stopAllAudio()
      //     }
      //   }, 2000)
      // }
    })
  } else {
    // 如果没有语音文件，2秒后跳转
    if (isAutoPlay && isPlaying.value && currentDialogue.value?.type !== 'user') {
      setTimeout(() => {
        if (!playNext(true)) {
          // 播放完毕
          isPlaying.value = false
          stopAllAudio()
        }
      }, 2000)
    }
  }
}

const togglePlay = () => {
  isPlaying.value = !isPlaying.value
  if (isPlaying.value) {
    // 播放背景音
    playBackgroundAudio()
    // 开始播放序列
    playSequence()
  } else {
    // 暂停所有音频
    stopAllAudio()
  }
}

// 自动播放序列
const playSequence = () => {
  if (!isPlaying.value) return

  // 如果当前是用户输入卡片，暂停播放等待用户输入
  if (currentDialogue.value?.type === 'user') return

  // 播放当前对话语音，传递isAutoPlay参数
  playDialogueAudio(true)
}

const playPrevious = () => {
  // 停止当前音频
  stopAllAudio()

  // 如果正在进行数字人对话，调用stopStream清理
  recoverQuestDialogue()
  stopPlayback(false) // 不触发回调
  if (conversationInProgress.value) {
    stopStream()
  }

  if (currentDialogueIndex.value > 0) {
    currentDialogueIndex.value--
  } else if (currentSectionIndex.value > 0) {
    currentSectionIndex.value--
    const section = props.scriptData.sections[currentSectionIndex.value]
    currentDialogueIndex.value = section.dialogues.length - 1
  }

  // 播放背景音
  playBackgroundAudio()
  // 播放当前对话语音
  if (isPlaying.value) {
    playDialogueAudio(true)
  } else {
    playDialogueAudio()
  }
}

const playNext = (isAutoPlay = false) => {
  // 停止当前对话语音
  if (dialogueAudio.value) {
    dialogueAudio.value.pause()
    dialogueAudio.value.currentTime = 0
  }
  
  // 如果正在进行数字人对话，调用stopStream清理
  recoverQuestDialogue()
  stopPlayback(false)
  if (conversationInProgress.value) {
    stopStream()
  }

  if (currentSection.value && currentDialogueIndex.value < currentSection.value.dialogues.length - 1) {
    currentDialogueIndex.value++
    // 根据是否为自动播放状态决定如何播放语音
    if (isPlaying.value) {
      playDialogueAudio(true)
    } else {
      playDialogueAudio()
    }
    return true
  } else if (currentSectionIndex.value < props.scriptData.sections.length - 1) {
    currentSectionIndex.value++
    currentDialogueIndex.value = 0
    // 播放背景音
    playBackgroundAudio()
    // 根据是否为自动播放状态决定如何播放语音
    if (isPlaying.value) {
      playDialogueAudio(true)
    } else {
      playDialogueAudio()
    }
    return true
  }
  return false
}

// 返回主页按钮点击事件
const goBackToMain = () => {
  // 停止所有音频
  stopAllAudio()
  // 跳转到 ai-general-course 页面，保持侧边栏选中状态
  router.push('/ai-general-course')
}

// 开始播放
const maskLayer = ref(null)
const startPlayback = () => {
  // 消失动画
  if (maskLayer.value) {
    maskLayer.value.classList.add('fade-out')
    // 等待动画完成后隐藏遮罩层
    setTimeout(() => {
      showMask.value = false
    }, 500)
  }
  // 播放当前对话语音
  playDialogueAudio()
}

// 键盘事件处理，键盘左右箭头控制对话
const handleKeydown = (event) => {
  // 如果遮罩层显示，不处理键盘事件
  if (showMask.value) {
    return
  }
  
  // 如果当前是用户输入对话，不处理键盘事件，让默认行为生效（在输入框中左右移动光标）
  if (currentDialogue.value?.type === 'user') {
    return
  }
  
  // 处理左右箭头键
  switch (event.key) {
    case 'ArrowLeft':
      playPrevious()
      event.preventDefault() // 防止默认行为
      break
    case 'ArrowRight':
      playNext()
      event.preventDefault() // 防止默认行为
      break
    default:
      // 其他按键不做处理
      break
  }
}

// 监听环节变化
watch(currentSectionIndex, () => {
  playBackgroundAudio()
})

// 监听 scriptData 变化（侧边栏切换话题时）
watch(() => props.scriptData, (newVal, oldVal) => {
  if (newVal && oldVal && newVal !== oldVal) {
    // 停止所有音频
    stopAllAudio()
    // 如果正在进行数字人对话，调用stopStream清理
    recoverQuestDialogue()
    stopPlayback(false)
    if (conversationInProgress.value) {
      stopStream()
    }
    // 清空索引
    currentSectionIndex.value = 0
    currentDialogueIndex.value = 0
    // 重置播放状态
    isPlaying.value = false
    // 显示遮罩层
    showMask.value = true
    // 清空用户输入
    userInput.value = ''
    // 清空对话缓存
    currentDialogueCache.value = null
  }
}, { deep: true })

// 会话ID
const activeConversationId = ref(null)
const conversationInProgress = ref(false)
const conversationInAbortController = ref()
const receiveMessageFullText = ref('')

//创建对话
const createAiChart = async () => {
  let role = props.scriptRoles.find(r => r.name === currentDialogue.value.roleName)
  // 智能问答
  await CreateDialogue({ roleId: role.id })
      .then(res => {
        console.log("创建会话：", res.data);
        activeConversationId.value = res.data
      })
      .catch(error => {
        console.error('请求出错:', error)
      })
}

/** 真正执行【发送】消息操作 */
const doSendMessage = async () => {
  // 校验
  if (userInput.value.length < 1) {
    console.error('发送失败，原因：内容为空！')
    return
  }

  if (activeConversationId.value == null) {
    console.error('还没创建对话，不能发送!')
    return
  }

  let userInputTemp = userInput.value;
  let currentDialogueTemp = currentSection.value.dialogues[currentDialogueIndex.value-1]
  userInputTemp += "(此内容是帮我解答的问题，问题是：" + currentDialogueTemp.content + "，回复要求：根据问题处理我回答的内容是否正确并给予鼓励或夸赞；注意请使用精简回答，尽量控制字体数量在50个字内)"
  // 执行发送
  await doSendMessageStream({
    conversationId: activeConversationId.value,
    content: userInputTemp,
    contentAnswer: null,
  })
  // 清空输入框
  userInput.value = ''
}

/** 显示问题回答对话 */
const showQuestAnswerDialogue = () => {
  // 缓存当前对话
  currentDialogueCache.value = JSON.parse(JSON.stringify(currentDialogue.value))

  // 将当前对话类型设置为数字人对话
  currentDialogue.value.type = "digital"
  // 设置默认内容为"让我思考一下..."
  currentDialogue.value.content = "让我思考一下..."

}

//延时恢复对话，避免立即回复导致对话内容被覆盖
const delayRecoverQuestDialogue = () => {
  // Message().error('当前网络无反应，请稍后重试！', true);
  // 设置默认内容为"让我思考一下..."
  currentDialogue.value.content = "当前网络无反应，请稍后重试！"

  setTimeout(() => {
    recoverQuestDialogue()
  }, 1500)
}

/** 回复对话 */
const recoverQuestDialogue = () => {
  // 如果有缓存的对话
  if (currentDialogueCache.value){
    // 恢复当前对话
    const currentSection = props.scriptData.sections[currentSectionIndex.value]
    if (currentSection) {
      currentSection.dialogues[currentDialogueIndex.value] = JSON.parse(JSON.stringify(currentDialogueCache.value))
    }
    // 清空缓存
    currentDialogueCache.value = null
  }
}

/** 真正执行【发送】消息操作 */
const doSendMessageStream = async userMessage => {
  // 创建 AbortController 实例，以便中止请求
  conversationInAbortController.value = new AbortController()
  // 标记对话进行中
  conversationInProgress.value = true
  // 设置为空
  receiveMessageFullText.value = ''

  showQuestAnswerDialogue()

  try {

    // 发送 event stream
    let isFirstChunk = true // 是否是第一个 chunk 消息段
    await sendChatMessageStream(
        userMessage.conversationId,
        userMessage.content,
        userMessage.contentAnswer,
        conversationInAbortController.value,
        true, // enableContext 参数
        async res => {
          const { code, data, msg } = JSON.parse(res.data)
          if (code !== 0) {
            console.log(`对话异常! ${msg}`)
            stopStream();
            return
          }

          if (data.eventType === 'TEXT') {

            // 如果内容为空，就不处理。
            if (data.receive?.content === '') {
              return
            }
            receiveMessageFullText.value += data.receive.content
            // 更新数字人对话框内容
            currentDialogue.value.content = receiveMessageFullText.value
            // 首次返回需要添加一个 message 到页面，后面的都是更新
            if (isFirstChunk) {
              isFirstChunk = false
              //第一次返回
            } else {
              //更新最后一条消息
            }
          }
          if (data.eventType === 'AUDIO') {
            // 处理音频消息
            await playAudioChunk(data.audioData);
          }
        },
        error => {
          console.log(`对话异常! ${error}`)
          stopStream()

          delayRecoverQuestDialogue()
          // 需要抛出异常，禁止重试
          throw error
        },
        () => {
          console.log(`结束对话！ `)
          stopStream()
        }
    )
  } catch (error) {
    console.error('发送消息失败:', error)
    stopStream()
    delayRecoverQuestDialogue()
  }
}

/** 停止 stream 流式调用 */
const stopStream = async () => {
  // 如果 stream 进行中的 message，就需要调用 controller 结束
  if (conversationInAbortController.value) {
    conversationInAbortController.value.abort()
  }
  // 销毁语音读取
  // stopPlayback();
  // 设置为 false
  conversationInProgress.value = false

  console.log(`结束对话！更改状态： `,conversationInProgress.value)
}

// 处理音频播放完成
const handleAudioPlaybackComplete = () => {
  console.log('智能问答音频播放完成');
  // AI回答完成后，如果之前是播放状态，继续播放

  stopAllAudio();
  // 如果处于自动播放状态，继续播放下一条对话
  if (isPlaying.value) {
    if (playNext()) {
      // 继续自动播放序列
      playSequence();
    } else {
      // 播放完毕
      isPlaying.value = false;
      stopAllAudio();
    }
  }
};

// 组件挂载时添加键盘事件监听
onMounted(() => {
  window.addEventListener('keydown', handleKeydown)
  // 播放背景音
  playBackgroundAudio()
  // // 播放当前对话语音
  // playDialogueAudio()
  // 设置音频播放完成回调
  setOnPlaybackComplete(handleAudioPlaybackComplete)
})

// 组件卸载时移除键盘事件监听和停止音频
onUnmounted(() => {
  window.removeEventListener('keydown', handleKeydown)
  stopAllAudio()
  stopPlayback(false)
})
</script>

<style scoped lang="scss">
@use "sass:math";

@function rpx($px) {
  @return math.div($px, 750) * 100vw;
}

.dialog-content-wrapper {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 100;
}

.title-box {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: rpx(60);
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: white;
  padding: 0 rpx(20);
  z-index: 10;
}

.title-left {
  width: 33.33%;
  height: 100%;
  display: flex;
  align-items: center;
  gap: rpx(5);
  .box-icon {
    display: flex;
    align-items: center;
    color: #0064BE;
    gap: rpx(5);
    padding: rpx(5) rpx(10);
    background: linear-gradient(135deg, #A0DCF0, #50BEF0);
    border: rpx(1) solid rgba(0, 100, 192);
    border-radius: rpx(30);
    backdrop-filter: blur(10px);
    cursor: pointer;
    transition: all 0.3s ease;
    font-size: rpx(9);
    font-weight: 500;
    width: fit-content;
  }
  
  .box-icon:hover {
    background-color: rgba(255, 255, 255, 90%);
    transform: translateX(-3px);
  }
  
  .left-icon {
    font-size: rpx(12);
  }
}

.title-center {
  width: 33.33%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-image: url('@/assets/dialogue/number-title.png');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  height: 100%;
}

.title-text {
  height: 100%;
  font-size: rpx(12);
  font-weight: bold;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 50%;
  display: flex;
  align-items: center;
  justify-content: left;
}

.title-right {
  width: 33.33%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: rpx(10);
  .arrow-icon-circle {
    width: rpx(20);
    height: rpx(20);
    border-radius: 50%;
    border: rpx(1) solid rgba(0, 100, 192);
    background: linear-gradient(135deg, #A0DCF0, #50BEF0);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s ease;
  }
  .arrow-icon-circle:hover:not(.disabled) {
    transform: scale(1.1);
    box-shadow: 0 rpx(1) rpx(6) rgba(0, 0, 0, 0.3);
  }
  .arrow-icon-circle:active:not(.disabled) {
    transform: scale(0.95);
  }
  .arrow-icon-circle.disabled {
    opacity: 0.5;
    cursor: not-allowed;
    border-color: rgba(0, 100, 192, 0.3);
    background: linear-gradient(135deg, rgba(160, 220, 240, 0.5), rgba(80, 190, 240, 0.5));
  }
  .arrow-icon {
    font-size: rpx(15);
    color: #0064BE;
  }
  
  .play-text {
    font-size: rpx(7);
    color: #0064BE;
    font-weight: 500;
  }
}

.background-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 1;
  position: relative;
}

/* 遮罩层样式 */
.mask-layer {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.7);
  z-index: 20;
  display: flex;
  justify-content: center;
  align-items: center;
  opacity: 1;
  transition: all 0.5s ease-out;
}

.mask-layer.fade-out {
  opacity: 0;
  transform: scale(1.1);
  z-index: -1;
}

.play-button-container {
  display: flex;
  justify-content: center;
  align-items: center;
}

.play-button {
  width: rpx(80);
  height: rpx(80);
  border-radius: 50%;
  border: none;
  background: transparent;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  outline: none;
  -webkit-tap-highlight-color: transparent;
}

.play-icon {
  font-size: rpx(40);
  color: #A0DCF0;
  transition: all 0.3s ease;
  cursor: pointer;
}

.play-icon:hover {
  transform: scale(1.2);
  color: #50BEF0;
  text-shadow: 0 0 rpx(10) rgba(64, 158, 255, 0.5);
}

.content-box {
  position: absolute;
  top: rpx(60);
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: rpx(10);
  z-index: 10;
}

.character {
  position: absolute;
  bottom: 0;
  width: rpx(135);
  height: rpx(240);
  background-size: contain;
  background-position: bottom;
  background-repeat: no-repeat;
  opacity: 0;
  z-index: 1;
  // background-color: #fff;
}

.character.left {
  left: rpx(17);
  transform: translateX(-100%);
  animation: characterEnterLeft 0.8s ease forwards;
}

.character.right {
  right: rpx(17);
  transform: translateX(100%) scaleX(-1);
  animation: characterEnterRight 0.8s ease forwards;
}

@keyframes characterEnterLeft {
  0% {
    opacity: 0;
    transform: translateX(-100%) scale(0.8);
  }
  70% {
    opacity: 0.9;
    transform: translateX(10%) scale(1.05);
  }
  100% {
    opacity: 1;
    transform: translateX(0) scale(1);
  }
}

@keyframes characterEnterRight {
  0% {
    opacity: 0;
    transform: translateX(100%) scale(0.8) scaleX(-1);
  }
  70% {
    opacity: 0.9;
    transform: translateX(-10%) scale(1.05) scaleX(-1);
  }
  100% {
    opacity: 1;
    transform: translateX(0) scale(1) scaleX(-1);
  }
}

.dialogue-card {
  background: rgba(255, 255, 255, 0.9);
  border-radius: rpx(6);
  padding: rpx(8);
  max-width: 20%;
  min-width: rpx(150);
  box-shadow: 0 rpx(3.5) rpx(10) rgba(0, 0, 0, 0.15);
  position: absolute;
  bottom: rpx(50);
  width: auto;
  display: inline-block;
  z-index: 2;
}

.dialogue-card.left {
  left: rpx(145);
  animation: dialogueEnterLeft 0.6s ease forwards;
}

.dialogue-card.right {
  right: rpx(145);
  animation: dialogueEnterRight 0.6s ease forwards;
}

.dialogue-card.left::before {
  content: '';
  position: absolute;
  left: rpx(-11.5);
  bottom: rpx(12);
  width: 0;
  height: 0;
  border-top: rpx(7) solid transparent;
  border-bottom: rpx(7) solid transparent;
  border-right: rpx(12) solid rgba(255, 255, 255, 0.9);
  transform: translateY(0);
}

.dialogue-card.right::before {
  content: '';
  position: absolute;
  right: rpx(-11.5);
  bottom: rpx(12);
  width: 0;
  height: 0;
  border-top: rpx(7) solid transparent;
  border-bottom: rpx(7) solid transparent;
  border-left: rpx(12) solid rgba(255, 255, 255, 0.9);
  transform: translateY(0);
}

@keyframes dialogueEnterLeft {
  from {
    opacity: 0;
    transform: translateX(-rpx(30)) translateY(rpx(20));
  }
  to {
    opacity: 1;
    transform: translateX(0) translateY(0);
  }
}

@keyframes dialogueEnterRight {
  from {
    opacity: 0;
    transform: translateX(rpx(30)) translateY(rpx(20));
  }
  to {
    opacity: 1;
    transform: translateX(0) translateY(0);
  }
}

.dialogue-header {
  position: absolute;
  top: rpx(-11);
  left: rpx(12);
  background: #409EFF;
  color: white;
  padding: rpx(1.2) rpx(6);
  border-radius: rpx(5);
  font-size: rpx(8);
  box-shadow: 0 rpx(2.5) rpx(10) rgba(0, 0, 0, 0.2);
}

.dialogue-card.right .dialogue-header {
  left: rpx(10);
}

.role-name {
  font-weight: 600;
  color: white;
  font-size: rpx(10);
}

.dialogue-content {
  font-size: rpx(12);
  line-height: 1.2;
  color: #333;
  text-align: left;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
}

.user-input-card {
  max-width: 50%;
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: rpx(70);
  right: auto;
  animation: dialogueEnterCenter 0.6s ease forwards;
}

.user-input-card::before {
  display: none;
}

@keyframes dialogueEnterCenter {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(rpx(20));
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}

.user-input-textarea {
  width: 95%;
  min-height: rpx(50);
  max-height: rpx(150);
  border: none;
  outline: none;
  background: transparent;
  font-size: rpx(10);
  line-height: 1.2;
  color: #333;
  resize: none;
  font-family: inherit;
  overflow-y: auto;
  text-align: left;
  padding: rpx(5) 0;
}

.voice-input-content {
  width: 95%;
  min-height: rpx(50);
  max-height: rpx(150);
  font-size: rpx(10);
  line-height: 1.2;
  color: #333;
  text-align: left;
  padding: rpx(5) 0;
  overflow-y: auto;
}

.voice-input-placeholder {
  width: 95%;
  min-height: rpx(50);
  font-size: rpx(10);
  line-height: 1.2;
  color: #999;
  text-align: left;
  padding: rpx(5) 0;
  font-style: italic;
}

/* 滚动条样式 */
.user-input-textarea::-webkit-scrollbar {
  width: rpx(0);
}

.user-input-textarea::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.05);
  border-radius: rpx(3);
}

.user-input-textarea::-webkit-scrollbar-thumb {
  background: rgba(64, 158, 255, 0.5);
  border-radius: rpx(3);
}

.user-input-textarea::-webkit-scrollbar-thumb:hover {
  background: rgba(64, 158, 255, 0.8);
}

.input-actions {
  display: flex;
  justify-content: flex-end;
  gap: rpx(6);
  margin-top: rpx(6);
  width: 100%;
}

.cancel-btn, .submit-btn {
  padding: rpx(2.5) rpx(10);
  border: none;
  border-radius: rpx(4);
  font-size: rpx(8);
  cursor: pointer;
  transition: all 0.3s ease;
}

.cancel-btn {
  background: #E0E0E0;
  color: #666;
}

.submit-btn {
  background: #409EFF;
  color: white;
}

.cancel-btn:hover, .submit-btn:hover {
  transform: scale(1.05);
}

.cancel-btn:active, .submit-btn:active {
  transform: scale(0.95);
}

.dialogue-content :deep(p) {
  margin: 0 0 rpx(4) 0;
}

.dialogue-content :deep(strong),
.dialogue-content :deep(b) {
  font-weight: bold;
}

.dialogue-content :deep(em),
.dialogue-content :deep(i) {
  font-style: italic;
}

.dialogue-content :deep(ul),
.dialogue-content :deep(ol) {
  margin: rpx(4) 0;
  padding-left: rpx(10);
}

.dialogue-content :deep(li) {
  margin: rpx(2) 0;
}

.dialogue-content :deep(code) {
  background-color: #f0f0f0;
  padding: rpx(1) rpx(3);
  border-radius: rpx(2);
  font-family: monospace;
  font-size: rpx(9);
}

.dialogue-content :deep(a) {
  color: #409EFF;
  text-decoration: underline;
}

.input-buttons-container {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  z-index: 10;
  transition: all 0.3s ease;
  transform: scale(0.9);
}

.voice-input-outer,
.keyboard-input-outer {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
}

.voice-input-outer {
  position: relative;
  width: rpx(50);
  height: rpx(50);
  border-radius: 50%;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;

  // 正常状态只显示一圈
  &::before {
    content: '';
    position: absolute;
    width: 85%;
    height: 85%;
    border-radius: 50%;
    border: rpx(2) solid rgba(80, 190, 240, 0.6);
  }

  // 录音时显示波纹效果
  &.recording {
    &::before {
      animation: pulse 2s infinite;
    }

    &::after {
      content: '';
      position: absolute;
      width: 85%;
      height: 85%;
      border-radius: 50%;
      border: rpx(2) solid rgba(80, 190, 240, 0.4);
      animation: pulse 2s infinite 0.5s;
    }
  }

  :deep(.voice-input-container) {
    position: relative;
    z-index: 10;
    .speech-btn {
      width: rpx(40);
      height: rpx(40);
      border-radius: 50%;
      border: rpx(2) solid rgba(0, 100, 192);
      background: linear-gradient(135deg, #A0DCF0, #50BEF0);
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0;
      gap: 0;
      transition: all 0.3s ease;
      cursor: pointer;
      position: relative;
      overflow: hidden;

      &:hover {
        transform: scale(1.05);
        box-shadow: 0 rpx(4) rpx(12) rgba(0, 0, 0, 0.3);
      }

      &:active {
        transform: scale(0.95);
      }

      &::before {
        content: '';
        position: absolute;
        top: 50%;
        left: 50%;
        width: 0;
        height: 0;
        border-radius: 50%;
        background: rgba(255, 255, 255, 0.5);
        transform: translate(-50%, -50%);
        transition: width 0.6s, height 0.6s;
      }

      &:active::before {
        width: rpx(80);
        height: rpx(80);
      }

      .el-icon {
        font-size: rpx(20);
        color: #0064BE;
        z-index: 1;
      }

      .countdown-text {
        display: none;
      }

      .waveform-container {
        display: none;
      }
    }
  }
}

@keyframes pulse {
  0% {
    transform: scale(1);
    opacity: 1;
  }
  100% {
    transform: scale(1.15);
    opacity: 0;
  }
}

.keyboard-input-outer {
  width: rpx(30);
  height: rpx(30);
  border-radius: 50%;
  background: transparent;

  &.active {
    width: rpx(40);
    height: rpx(40);
    left: 50%;
    transform: translateX(-50%);
    z-index: 11;

    .keyboard-btn {
      width: rpx(36);
      height: rpx(36);
      border: rpx(2) solid rgba(0, 100, 192);
      box-shadow: 0 rpx(3) rpx(8) rgba(0, 0, 0, 0.3);

      .keyboard-icon {
        font-size: rpx(18);
      }
    }
  }

  &.inactive {
    width: rpx(24);
    height: rpx(24);
    left: calc(50% + rpx(40));
    transform: translateX(-50%);
    z-index: 10;

    .keyboard-btn {
      width: rpx(22);
      height: rpx(22);
      border: rpx(1) solid rgba(128, 128, 128, 0.5);
      box-shadow: none;
      background: linear-gradient(135deg, #E0E0E0, #C0C0C0);

      .keyboard-icon {
        font-size: rpx(12);
        color: #808080;
      }
    }
  }
}

.keyboard-btn {
  width: rpx(28);
  height: rpx(28);
  border-radius: 50%;
  border: rpx(1) solid rgba(0, 100, 192);
  background: linear-gradient(135deg, #A0DCF0, #50BEF0);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  gap: 0;
  transition: all 0.3s ease;
  cursor: pointer;

  &:hover {
    transform: scale(1.1);
    box-shadow: 0 rpx(2) rpx(8) rgba(0, 0, 0, 0.3);
  }

  &:active {
    transform: scale(0.95);
  }

  .keyboard-icon {
    font-size: rpx(14);
    color: #0064BE;
  }
}
</style>