<template>
  <view class="chat-container" :style="{ paddingTop: navBarHeight + 'px' }">
    <!-- 夜空装饰背景 -->
    <view class="night-sky-decoration">
      <view class="star star-1"></view>
      <view class="star star-2"></view>
      <view class="star star-3"></view>
      <view class="star star-4"></view>
      <view class="star star-5"></view>
      <view class="star star-6"></view>
      <view class="star star-7"></view>
      <view class="star star-8"></view>
    </view>

    <!-- 自定义导航栏 -->
    <view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
      <view class="navbar-content">
        <view class="navbar-left">
          <view v-if="showBackButton" @tap="goBack" class="left-btn">
            <text class="back-icon">←</text>
            <text class="back-text">返回</text>
          </view>
          <text class="clear-btn" @tap="clearContext">清空</text>
        </view>
        <view class="navbar-center" :class="{'centered': !showBackButton}">
          <image class="character-avatar" :src="currentCharacter.avatar" mode="aspectFill" />
          <text class="character-name">{{ currentCharacter.name }}</text>
        </view>
        <view class="navbar-right">
        </view>
      </view>
    </view>


    <!-- 聊天消息区域 - 使用 Ant Design X Bubble.List -->
    <scroll-view
      class="chat-messages"
      scroll-y="true"
      :scroll-top="scrollTop"
      scroll-with-animation="true"
    >
      <view class="message-list">
        <!-- 使用 Bubble 组件展示消息 -->
        <view
          v-for="(message, index) in messages"
          :key="index"
          class="message-wrapper"
        >
          <!-- 系统消息 -->
          <view v-if="message.type === 'system'" class="system-message">
            <text class="system-text">{{ message.content }}</text>
          </view>

          <!-- AI/用户消息 -->
          <view v-else class="bubble-container" :class="[message.type]">
            <view class="bubble-avatar" v-if="message.type === 'ai'">
              <image :src="currentCharacter.avatar" mode="aspectFill" />
            </view>

            <view class="bubble-content">
              <view class="bubble" :class="[message.type]">
                <text class="bubble-text">{{ message.content }}</text>

                <!-- AI 消息操作按钮 - 已隐藏播放按钮 -->
                <!-- <view class="bubble-actions" v-if="message.type === 'ai' && isLoggedIn">
                  <view class="action-btn" @click="() => playVoiceResponse(message.content)">
                    <text class="action-icon">🔊</text>
                  </view>
                </view> -->

                <view class="bubble-time">{{ message.time }}</view>
              </view>
            </view>

            <view class="bubble-avatar" v-if="message.type === 'user'">
              <image :src="userAvatar" mode="aspectFill" />
            </view>
          </view>
        </view>

        <!-- 正在输入指示器 -->
        <view class="typing-indicator" v-if="isTyping">
          <view class="bubble-avatar">
            <image :src="currentCharacter.avatar" mode="aspectFill" />
          </view>
          <view class="typing-bubble">
            <view class="typing-dots">
              <view class="dot"></view>
              <view class="dot"></view>
              <view class="dot"></view>
            </view>
          </view>
        </view>
      </view>
    </scroll-view>
  </view>

  <!-- 输入区域 - 使用 Ant Design X Sender 风格 -->
  <view class="input-area">
    <!-- 智能体选择按钮 -->
    <!-- <view class="action-bar" v-if="availableTemplates.length > 0">
      <view class="template-selector-btn" @click="showTemplateSelector">
        <text class="template-icon">🤖</text>
        <text class="template-name">{{ currentTemplateName }}</text>
        <text class="arrow-icon">›</text>
      </view>
    </view> -->

    <view class="sender-container">
      <!-- 文本输入模式 -->
      <view v-if="!isRecordingMode" class="text-input-mode">
        <input
          class="text-input"
          v-model="inputText"
          placeholder="输入消息..."
          :disabled="isTyping || isLoading"
          @confirm="sendMessage"
          confirm-type="send"
          @focus="handleInputFocus"
        />

        <view class="input-actions">
          <!-- 麦克风按钮已隐藏 -->
          <!-- <view class="action-icon-btn" @click="toggleRecordingMode">
            <text class="icon">🎙️</text>
          </view> -->
          <view
            class="send-btn"
            :class="{'active': inputText.trim()}"
            @click="sendMessage"
          >
            <text class="send-icon">发送</text>
          </view>
        </view>
      </view>

      <!-- 语音输入模式 -->
      <view v-else class="voice-input-mode">
        <view
          class="hold-to-speak"
          :class="{'recording': isActuallyRecording}"
          @touchstart="startActualRecording"
          @touchend="stopActualRecording"
          @touchcancel="cancelActualRecording"
          @touchmove="handleRecordingMove"
        >
          <text class="speak-text">{{ isActuallyRecording ? '松手发送...' : '按住说话' }}</text>
        </view>

        <!-- 键盘按钮已隐藏 -->
        <!-- <view class="action-icon-btn" @click="toggleRecordingMode">
          <text class="icon">⌨️</text>
        </view> -->
      </view>
    </view>

    <!-- 录音状态提示 -->
    <view class="recording-overlay" v-if="isActuallyRecording">
      <view class="recording-modal">
        <text class="recording-tip">{{ recordingTipText }}</text>
        <view class="recording-animation" v-if="!isRecordingCancelled">
          <view class="wave" v-for="i in 5" :key="i"></view>
        </view>
      </view>
    </view>
  </view>

  <!-- 智能体选择弹窗 -->
  <!-- <view class="modal-overlay" v-if="showTemplateModal" @click="hideTemplateSelector">
    <view class="modal-content" @click.stop>
      <view class="modal-header">
        <text class="modal-title">选择智能体</text>
        <view class="close-btn" @click="hideTemplateSelector">
          <text class="close-icon">✕</text>
        </view>
      </view>

      <view class="template-list">
        <view
          class="template-item"
          :class="{'active': currentTemplateId === template.templateId}"
          v-for="template in availableTemplates"
          :key="template.templateId"
          @click="() => selectTemplate(template)"
        >
          <view class="template-info">
            <text class="template-name">{{ template.templateName }}</text>
            <text class="template-desc">{{ template.templateDesc }}</text>
          </view>
          <view class="check-mark" v-if="currentTemplateId === template.templateId">
            <text class="check-icon">✓</text>
          </view>
        </view>
      </view>
    </view>
  </view> -->
</template>

<script setup>
import { ref, computed, onMounted, nextTick } from 'vue';
import { useUserStore } from '@/stores/user.js';
import { getCharacterById, getSmartResponse } from '@/utils/aiCharacters.js';
import { chatAPI, voiceAPI, cleanText, configAPI } from '@/utils/api.js';

// 状态管理
const userStore = useUserStore();

// 响应式数据
const messages = ref([]);
const inputText = ref('');
const isTyping = ref(false);
const isOnline = ref(true);
const scrollTop = ref(0);
const currentCharacter = ref({});
const userAvatar = ref('/static/default-avatar.png');
const conversationId = ref(null);
const isLoading = ref(false);
const isLoggedIn = ref(false);
const showBackButton = ref(true);

// 状态栏高度适配
const statusBarHeight = ref(0);
const navBarHeight = ref(0);

// 录音相关
const isRecordingMode = ref(false);
const isActuallyRecording = ref(false);
const isRecordingCancelled = ref(false);
const recordingTipText = ref('松手发送，上移取消');
const touchStartY = ref(0);
const recorderManager = ref(null);
const audioContext = ref(null);

// AI配置
const availableTemplates = ref([]);
const currentModelId = ref(null);
const currentTemplateId = ref(null);
const showTemplateModal = ref(false);

// 当前模板名称
const currentTemplateName = computed(() => {
  const template = availableTemplates.value.find(t => t.templateId === currentTemplateId.value);
  return template?.templateName || '默认智能体';
});

// 获取系统状态栏高度
const getSystemInfo = () => {
  const systemInfo = uni.getSystemInfoSync();
  statusBarHeight.value = systemInfo.statusBarHeight || 0;
  // 导航栏总高度 = 状态栏高度 + 导航栏内容高度（44px）
  navBarHeight.value = statusBarHeight.value + 44;
  console.log('状态栏高度:', statusBarHeight.value, '导航栏总高度:', navBarHeight.value);
};

// 生命周期
onMounted(() => {
  getSystemInfo(); // 获取系统信息
  initPage();
  initRecorder();
});

// 初始化页面
const initPage = async () => {
  checkLoginStatus();

  const pages = getCurrentPages();
  const currentPage = pages[pages.length - 1];
  const options = currentPage.options || {};

  if (!options.characterId && !options.roleId) {
    showBackButton.value = false;
  }

  // 蔚AI
  if (options.characterId === 'wei-ai' || !options.characterId) {
    currentCharacter.value = {
      id: 'wei-ai',
      name: options.characterName || '蔚AI',
      avatar: options.characterAvatar || '/static/avatar/icon_hushi.jpg',
      greeting: decodeURIComponent(options.introMessage || '你好！我是蔚AI，很高兴为您服务！')
    };

    await loadAIConfigs();
    createNewConversation('wei-ai');

    // 尝试加载历史消息
    await loadHistoryMessages();

    // 如果没有历史消息，显示欢迎消息
    if (messages.value.length === 0) {
      addMessage('ai', currentCharacter.value.greeting);

      if (!isLoggedIn.value) {
        addMessage('system', '您当前处于未登录状态，将使用本地模拟回复。登录后可享受完整的AI对话功能。');
      }
    }
  }
  // AI角色
  else if (options.roleId) {
    currentCharacter.value = {
      id: options.characterId,
      roleId: options.roleId,
      name: decodeURIComponent(options.roleName || 'AI角色'),
      avatar: decodeURIComponent(options.avatar || '/static/logo.png'),
      greeting: decodeURIComponent(options.greeting || '你好！很高兴认识你！'),
      roleDesc: decodeURIComponent(options.roleDesc || ''),
      modelId: options.modelId || null,
      templateId: options.templateId || null,
      ttsId: options.ttsId || null,
      sttId: options.sttId || null,
      temperature: options.temperature || null,
      topP: options.topP || null
    };

    await loadAIConfigs();

    if (options.modelId) {
      currentModelId.value = parseInt(options.modelId);
    }
    if (options.templateId) {
      currentTemplateId.value = parseInt(options.templateId);
    }

    createNewConversation(options.roleId);

    // 尝试加载历史消息
    await loadHistoryMessages();

    // 如果没有历史消息，显示欢迎消息
    if (messages.value.length === 0) {
      addMessage('ai', currentCharacter.value.greeting);

      if (!isLoggedIn.value) {
        addMessage('system', '您当前处于未登录状态，将使用本地模拟回复。登录后可享受完整的AI对话功能。');
      }
    }
  }
  // 默认角色
  else {
    const characterId = options.characterId || 5;
    const character = getCharacterById(characterId);
    if (character) {
      currentCharacter.value = character;
      await loadAIConfigs();
      createNewConversation(characterId);

      // 尝试加载历史消息
      await loadHistoryMessages();

      // 如果没有历史消息，显示欢迎消息
      if (messages.value.length === 0) {
        addMessage('ai', character.greeting);

        if (!isLoggedIn.value) {
          addMessage('system', '您当前处于未登录状态，将使用本地模拟回复。登录后可享受完整的AI对话功能。');
        }
      }
    }
  }

  if (userStore.userInfo?.avatar) {
    userAvatar.value = userStore.userInfo.avatar;
  }
};

// 加载AI配置
const loadAIConfigs = async () => {
  try {
    const templatesResult = await configAPI.getTemplates();

    if (templatesResult.success) {
      availableTemplates.value = templatesResult.data.data?.list || templatesResult.data.data || templatesResult.data;

      if (availableTemplates.value.length > 0 && !currentTemplateId.value) {
        currentTemplateId.value = availableTemplates.value[0].templateId;
      }
    } else {
      // 模拟数据
      availableTemplates.value = [
        { templateId: 1, templateName: '默认AI模型', templateDesc: '在用户与AI角色对话时，这个智能体会记住用户的言语习惯。' },
        { templateId: 2, templateName: '1号AI模型', templateDesc: '学习用户的表达方式，并逐渐适应个性化的交流风格。' }
      ];
      currentTemplateId.value = 1;
    }
  } catch (error) {
    console.error('加载AI配置异常:', error);
    availableTemplates.value = [
      { templateId: 1, templateName: '默认AI模型', templateDesc: '默认AI模型' }
    ];
    currentTemplateId.value = 1;
  }
};

// 检查登录状态
const checkLoginStatus = () => {
  const customToken = uni.getStorageSync('custom_token');
  const userToken = uni.getStorageSync('user_token');
  const userInfo = uni.getStorageSync('userInfo');

  isLoggedIn.value = !!(userStore.token || customToken || userToken || userInfo);
};

// 初始化录音器
const initRecorder = () => {
  // #ifdef MP-WEIXIN
  recorderManager.value = uni.getRecorderManager();

  recorderManager.value.onStart(() => {
    console.log('录音开始');
  });

  recorderManager.value.onStop((res) => {
    console.log('录音结束', res);
    if (!isRecordingCancelled.value) {
      handleVoiceMessage(res.tempFilePath);
    }
  });

  recorderManager.value.onError((err) => {
    console.error('录音错误', err);
    uni.showToast({
      title: '录音失败',
      icon: 'none'
    });
    isActuallyRecording.value = false;
  });
  // #endif
};

// 添加消息
const addMessage = (type, content) => {
  const now = new Date();
  const time = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;

  messages.value.push({
    type,
    content,
    time
  });

  nextTick(() => {
    scrollToBottom();
  });
};

// 滚动到底部
const scrollToBottom = () => {
  const query = uni.createSelectorQuery();
  query.select('.message-list').boundingClientRect();
  query.exec((res) => {
    if (res[0]) {
      scrollTop.value = res[0].height;
    }
  });
};

// 延时工具
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

// 根据 & 分段，逐条展示 AI 回复
const addSegmentedAIResponse = async (text) => {
  if (!text || typeof text !== 'string') return;
  // 使用 & 作为分隔符，按段落逐条展示
  const segments = text
    .split('&')
    .map(s => s.trim())
    .filter(Boolean);

  if (segments.length === 0) {
    addMessage('ai', text.trim());
    return;
  }

  for (const seg of segments) {
    addMessage('ai', seg);
    // 简单的节奏控制：与长度相关，介于300-1200ms
    const delay = Math.min(1200, Math.max(300, seg.length * 30));
    await sleep(delay);
  }
};

// 发送消息
const sendMessage = async () => {
  const text = inputText.value.trim();
  if (!text || isTyping.value || isLoading.value) return;

  addMessage('user', text);
  inputText.value = '';
  isTyping.value = true;

  try {
    await getAIResponse(text);
  } catch (error) {
    console.error('发送消息失败:', error);
    uni.showToast({
      title: '发送失败',
      icon: 'none'
    });
  } finally {
    isTyping.value = false;
  }
};

// 创建或获取会话ID（基于角色持久化存储）
const createNewConversation = (characterId) => {
  // 生成存储key：根据角色类型区分
  let storageKey = '';
  if (characterId === 'wei-ai' || !currentCharacter.value.roleId) {
    // 蔚AI或默认角色
    storageKey = `session_weiai`;
  } else {
    // 剧情角色
    storageKey = `session_role_${currentCharacter.value.roleId}`;
  }

  // 尝试从本地存储获取已有的sessionId
  let existingSessionId = uni.getStorageSync(storageKey);

  if (existingSessionId) {
    // 已有sessionId，直接使用（保持上下文）
    conversationId.value = existingSessionId;
    console.log('使用已有sessionId:', existingSessionId, 'storageKey:', storageKey);
  } else {
    // 生成新的sessionId
    const userId = userStore.userInfo?.openid || userStore.userInfo?.userId || 'guest';
    const timestamp = Date.now();
    const newSessionId = `session_${characterId}_${userId}_${timestamp}`;

    // 存储到本地
    uni.setStorageSync(storageKey, newSessionId);
    conversationId.value = newSessionId;
    console.log('创建新sessionId:', newSessionId, 'storageKey:', storageKey);
  }
};

// 加载历史消息
const loadHistoryMessages = async () => {
  if (!conversationId.value || !isLoggedIn.value) {
    console.log('没有sessionId或用户未登录，跳过加载历史消息');
    return;
  }

  try {
    console.log('开始加载历史消息，sessionId:', conversationId.value);
    const result = await chatAPI.getHistoryMessages(conversationId.value);

    if (result.success && result.data && result.data.length > 0) {
      console.log('获取到历史消息:', result.data.length, '条');

      // 将后端消息格式转换为前端格式，保持与API回复一致的“清理后回复”逻辑
      const historyMessages = [];

      result.data.forEach(msg => {
        // 格式化时间
        let timeStr = '';
        if (msg.createTime) {
          const date = new Date(msg.createTime);
          const hours = String(date.getHours()).padStart(2, '0');
          const minutes = String(date.getMinutes()).padStart(2, '0');
          timeStr = `${hours}:${minutes}`;
        }

        const messageType = msg.sender === 'assistant' ? 'ai' : (msg.sender === 'user' ? 'user' : 'system');
        const rawContent = msg.message || '';

        // 与API一致：先清理文本，再根据 & 分段
        const cleanedContent = cleanText(rawContent);

        if (messageType === 'ai' && cleanedContent.includes('&')) {
          const segments = cleanedContent
            .split('&')
            .map(s => s.trim())
            .filter(Boolean);

          segments.forEach(segment => {
            historyMessages.push({
              type: messageType,
              content: segment,
              time: timeStr
            });
          });
        } else {
          // 非 AI 或无分隔符，直接使用清理后的内容
          const content = cleanedContent.trim();
          if (content) {
            historyMessages.push({
              type: messageType,
              content,
              time: timeStr
            });
          }
        }
      });

      // 按时间排序（从旧到新）
      historyMessages.sort((a, b) => {
        if (!a.time || !b.time) return 0;
        return a.time.localeCompare(b.time);
      });

      // 清空当前消息列表，加载历史消息
      messages.value = historyMessages;
      console.log('历史消息加载完成，共', messages.value.length, '条');

      // 滚动到底部
      await nextTick();
      scrollToBottom();
    } else {
      console.log('没有历史消息或获取失败');
    }
  } catch (error) {
    console.error('加载历史消息失败:', error);
  }
};

// 获取AI回复
const getAIResponse = async (userMessage) => {
  try {
    isLoading.value = true;

    const requestParams = {
      message: userMessage,
      characterId: currentCharacter.value.id,
      conversationId: conversationId.value,
      modelId: 10,
      templateId: 6
    };

    if (currentCharacter.value.roleId) {
      if (currentCharacter.value.modelId) {
        requestParams.modelId = currentCharacter.value.modelId;
      }
      if (currentCharacter.value.templateId) {
        requestParams.templateId = currentCharacter.value.templateId;
      } else {
        requestParams.templateId = currentCharacter.value.roleId;
      }
    }

    const result = await chatAPI.syncChat(requestParams);

    if (result.success) {
      const aiResponse = result.data;
      await addSegmentedAIResponse(aiResponse);

      if (result.originalResponse && result.originalResponse.conversationId) {
        conversationId.value = result.originalResponse.conversationId;
      }
    } else {
      const fallbackResponse = getSmartResponse(currentCharacter.value, userMessage);
      const cleanedResponse = cleanText(fallbackResponse);
      await addSegmentedAIResponse(cleanedResponse);

      if (!result.isAnonymous) {
        uni.showToast({
          title: 'AI服务暂时不可用，使用本地回复',
          icon: 'none',
          duration: 2000
        });
      }
    }
  } catch (error) {
    console.error('AI API调用异常:', error);
    const fallbackResponse = getSmartResponse(currentCharacter.value, userMessage);
    const cleanedResponse = cleanText(fallbackResponse);
    await addSegmentedAIResponse(cleanedResponse);

    uni.showToast({
      title: '网络异常，使用本地回复',
      icon: 'none',
      duration: 2000
    });
  } finally {
    isLoading.value = false;
  }
};

// 切换录音模式
const toggleRecordingMode = () => {
  if (isTyping.value) return;
  isRecordingMode.value = !isRecordingMode.value;

  if (!isRecordingMode.value && isActuallyRecording.value) {
    stopActualRecording();
  }
};

// 开始录音
const startActualRecording = (e) => {
  if (isTyping.value || !isRecordingMode.value) return;

  touchStartY.value = e.touches[0].clientY;
  isRecordingCancelled.value = false;
  recordingTipText.value = '松手发送，上移取消';

  // #ifdef MP-WEIXIN
  uni.authorize({
    scope: 'scope.record',
    success: () => {
      isActuallyRecording.value = true;
      recorderManager.value.start({
        duration: 60000,
        sampleRate: 16000,
        numberOfChannels: 1,
        encodeBitRate: 96000,
        format: 'aac'
      });
    },
    fail: () => {
      uni.showModal({
        title: '需要录音权限',
        content: '请在设置中开启录音权限',
        showCancel: false
      });
    }
  });
  // #endif

  // #ifndef MP-WEIXIN
  uni.showToast({
    title: '语音功能仅支持微信小程序',
    icon: 'none'
  });
  // #endif
};

// 停止录音
const stopActualRecording = () => {
  if (!isActuallyRecording.value) return;

  // #ifdef MP-WEIXIN
  isActuallyRecording.value = false;
  isRecordingCancelled.value = false;
  recorderManager.value.stop();
  // #endif
};

// 取消录音
const cancelActualRecording = () => {
  if (!isActuallyRecording.value) return;

  // #ifdef MP-WEIXIN
  isActuallyRecording.value = false;
  isRecordingCancelled.value = true;
  recorderManager.value.stop();

  uni.showToast({
    title: '录音已取消',
    icon: 'none',
    duration: 1000
  });
  // #endif
};

// 处理录音移动
const handleRecordingMove = (e) => {
  if (isActuallyRecording.value) {
    const currentY = e.touches[0].clientY;
    const deltaY = touchStartY.value - currentY;

    if (deltaY > 50) {
      isRecordingCancelled.value = true;
      recordingTipText.value = '松开取消录音';
    } else {
      isRecordingCancelled.value = false;
      recordingTipText.value = '松手发送，上移取消';
    }
  }
};

// 处理语音消息
const handleVoiceMessage = async (filePath) => {
  if (isRecordingCancelled.value) return;

  addMessage('user', '[语音消息]');
  isTyping.value = true;

  try {
    let effectiveModelId = currentModelId.value;
    let effectiveTemplateId = currentTemplateId.value;

    if (currentCharacter.value.roleId) {
      if (currentCharacter.value.modelId) {
        effectiveModelId = currentCharacter.value.modelId;
      }
      if (currentCharacter.value.templateId) {
        effectiveTemplateId = currentCharacter.value.templateId;
      } else {
        effectiveTemplateId = currentCharacter.value.roleId;
      }
    }

    const voiceChatResult = await voiceAPI.voiceChat(filePath, {
      modelId: effectiveModelId,
      templateId: effectiveTemplateId
    });

    if (voiceChatResult.success) {
      const { userText, aiResponse, audioUrl } = voiceChatResult.data;

      if (messages.value.length > 0) {
        const lastMessage = messages.value[messages.value.length - 1];
        if (lastMessage.type === 'user' && lastMessage.content === '[语音消息]') {
          lastMessage.content = userText || '[语音消息]';
        }
      }

      await addSegmentedAIResponse(aiResponse);

      if (audioUrl) {
        await playVoiceResponse(aiResponse, audioUrl);
      }
    } else {
      const uploadResult = await voiceAPI.uploadVoiceChat(filePath, {
        modelId: effectiveModelId,
        templateId: effectiveTemplateId
      });

      if (uploadResult.success) {
        const { userText, aiResponse, audioUrl } = uploadResult.data;

        if (messages.value.length > 0) {
          const lastMessage = messages.value[messages.value.length - 1];
          if (lastMessage.type === 'user' && lastMessage.content === '[语音消息]') {
            lastMessage.content = userText || '[语音消息]';
          }
        }

        await addSegmentedAIResponse(aiResponse);

        if (audioUrl) {
          await playVoiceResponse(aiResponse, audioUrl);
        }
      } else {
        const fallbackResponse = getSmartResponse(currentCharacter.value, '[语音消息]');
        const cleanedResponse = cleanText(fallbackResponse);
        await addSegmentedAIResponse(cleanedResponse);

        uni.showToast({
          title: '语音处理失败，使用本地回复',
          icon: 'none',
          duration: 2000
        });
      }
    }
  } catch (error) {
    console.error('处理语音消息失败:', error);
    const fallbackResponse = getSmartResponse(currentCharacter.value, '[语音消息]');
    const cleanedResponse = cleanText(fallbackResponse);
    await addSegmentedAIResponse(cleanedResponse);

    uni.showToast({
      title: '语音处理异常，使用本地回复',
      icon: 'none',
      duration: 2000
    });
  } finally {
    isTyping.value = false;
  }
};

// 播放语音
const playVoiceResponse = async (text, audioUrl = null) => {
  // #ifdef MP-WEIXIN
  try {
    let finalAudioUrl = audioUrl;

    if (!finalAudioUrl) {
      const ttsResult = await voiceAPI.textToSpeech(text, currentCharacter.value.voiceStyle);

      if (ttsResult.success) {
        finalAudioUrl = ttsResult.data.audioUrl;
      } else {
        uni.showToast({
          title: '语音合成失败',
          icon: 'none'
        });
        return;
      }
    }

    if (audioContext.value) {
      audioContext.value.destroy();
    }

    audioContext.value = uni.createInnerAudioContext();
    audioContext.value.src = finalAudioUrl;

    audioContext.value.onPlay(() => {
      uni.showToast({
        title: '正在播放语音',
        icon: 'none',
        duration: 1000
      });
    });

    audioContext.value.onError((err) => {
      console.error('语音播放错误:', err);
      uni.showToast({
        title: '语音播放失败',
        icon: 'none'
      });
    });

    audioContext.value.play();
  } catch (error) {
    console.error('语音播放异常:', error);
    uni.showToast({
      title: '语音播放异常',
      icon: 'none'
    });
  }
  // #endif

  // #ifndef MP-WEIXIN
  uni.showToast({
    title: '语音功能仅支持微信小程序',
    icon: 'none'
  });
  // #endif
};

// 显示模板选择器
const showTemplateSelector = () => {
  showTemplateModal.value = true;
};

// 隐藏模板选择器
const hideTemplateSelector = () => {
  showTemplateModal.value = false;
};

// 选择模板
const selectTemplate = (template) => {
  currentTemplateId.value = template.templateId;

  uni.showToast({
    title: `已切换到${template.templateName}`,
    icon: 'none',
    duration: 1500
  });

  hideTemplateSelector();
};

// 处理输入框聚焦
const handleInputFocus = () => {
  console.log('输入框获得焦点');
};

// 返回
const goBack = () => {
  uni.navigateBack();
};


// 清空对话上下文
const clearContext = async () => {
  uni.showModal({
    title: '清空对话',
    content: '确定要清空与该角色的所有对话记录吗？此操作不可恢复。',
    confirmText: '确定清空',
    cancelText: '取消',
    success: async (res) => {
      if (res.confirm) {
        try {
          uni.showLoading({ title: '清空中...' });

          // 1. 调用后端清除session（如果用户已登录）
          if (conversationId.value && isLoggedIn.value) {
            try {
              const result = await chatAPI.clearSession(conversationId.value);
              console.log('后端清除会话结果:', result);
            } catch (error) {
              console.log('后端清除失败，继续本地清除:', error);
            }
          }

          // 2. 删除本地存储的sessionId
          let storageKey = '';
          if (currentCharacter.value.id === 'wei-ai' || !currentCharacter.value.roleId) {
            storageKey = `session_weiai`;
          } else {
            storageKey = `session_role_${currentCharacter.value.roleId}`;
          }
          uni.removeStorageSync(storageKey);
          console.log('删除本地sessionId:', storageKey);

          // 3. 生成新的sessionId
          const characterIdForSession = currentCharacter.value.id || currentCharacter.value.roleId || 'default';
          createNewConversation(characterIdForSession);

          // 4. 清空消息列表（保留欢迎消息）
          messages.value = [];
          addMessage('ai', currentCharacter.value.greeting || '你好！很高兴再次见到你！');

          uni.hideLoading();
          uni.showToast({
            title: '对话已清空',
            icon: 'success'
          });
        } catch (error) {
          console.error('清空对话失败:', error);
          uni.hideLoading();
          uni.showToast({
            title: '清空失败',
            icon: 'none'
          });
        }
      }
    }
  });
};
</script>

<style scoped>
/* 页面容器 */
page {
  height: 100vh;
  overflow: hidden;
  background: linear-gradient(180deg, #1a0b2e 0%, #2d1b4e 50%, #1a0b2e 100%);
}

.chat-container {
  width: 100vw;
  height: 100vh;
  background: linear-gradient(180deg, #1a0b2e 0%, #2d1b4e 50%, #1a0b2e 100%);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  overflow: hidden;
  padding-bottom: 200rpx;
}

/* 夜空装饰 */
.night-sky-decoration {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
}

.star {
  position: absolute;
  width: 6rpx;
  height: 6rpx;
  background: #f9e076;
  border-radius: 50%;
  animation: twinkle 2s infinite;
  box-shadow: 0 0 10rpx #f9e076;
}

@keyframes twinkle {
  0%, 100% { opacity: 0.3; }
  50% { opacity: 1; }
}

.star-1 { top: 10%; left: 15%; animation-delay: 0s; }
.star-2 { top: 20%; left: 80%; animation-delay: 0.3s; }
.star-3 { top: 30%; left: 45%; animation-delay: 0.6s; }
.star-4 { top: 50%; left: 25%; animation-delay: 0.9s; }
.star-5 { top: 60%; left: 70%; animation-delay: 1.2s; }
.star-6 { top: 70%; left: 40%; animation-delay: 1.5s; }
.star-7 { top: 15%; left: 60%; animation-delay: 0.4s; }
.star-8 { top: 85%; left: 55%; animation-delay: 1.8s; }

/* 自定义导航栏 */
.custom-navbar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  background: rgba(26, 11, 46, 0.95);
  backdrop-filter: blur(20rpx);
  box-shadow: 0 2rpx 20rpx rgba(0, 0, 0, 0.3);
  border-bottom: 1rpx solid rgba(249, 224, 118, 0.1);
  z-index: 1000;
}

.navbar-content {
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 32rpx;
  position: relative;
}

.navbar-left {
  position: absolute;
  left: 24rpx;
  display: flex;
  align-items: center;
  gap: 16rpx;
  color: #f9e076;
  font-size: 28rpx;
  font-weight: 500;
  text-shadow: 0 0 10rpx rgba(249, 224, 118, 0.3);
}

.left-btn {
  display: flex;
  align-items: center;
  gap: 8rpx;
}

.back-icon {
  font-size: 32rpx;
}

.navbar-center {
  display: flex;
  align-items: center;
  gap: 16rpx;
}

.navbar-center.centered {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

.character-avatar {
  width: 64rpx;
  height: 64rpx;
  border-radius: 50%;
  border: 3rpx solid rgba(249, 224, 118, 0.3);
  box-shadow: 0 4rpx 12rpx rgba(249, 224, 118, 0.2);
}

.character-name {
  font-size: 32rpx;
  font-weight: 600;
  color: #f9e076;
  text-shadow: 0 0 15rpx rgba(249, 224, 118, 0.4);
}

.navbar-right {
  position: absolute;
  right: 32rpx;
  display: flex;
  align-items: center;
}

.clear-btn {
  font-size: 28rpx;
  color: #f9e076;
  font-weight: 500;
  text-shadow: 0 0 8rpx rgba(249, 224, 118, 0.3);
  padding: 8rpx 16rpx;
  transition: all 0.3s;
}

.clear-btn:active {
  opacity: 0.7;
  transform: scale(0.95);
}

.status-dot.online {
  background: #4caf50;
  box-shadow: 0 0 12rpx rgba(76, 175, 80, 0.8);
  animation: pulse 2s infinite;
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.6;
  }
}


/* 聊天消息区域 */
.chat-messages {
  height: calc(100vh - 200rpx);
  padding: 24rpx;
  overflow-y: auto;
}

.message-list {
  display: flex;
  flex-direction: column;
  gap: 24rpx;
}

.message-wrapper {
  width: 100%;
}

/* 系统消息 */
.system-message {
  display: flex;
  justify-content: center;
  margin: 16rpx 0;
}

.system-text {
  background: rgba(249, 224, 118, 0.1);
  backdrop-filter: blur(10px);
  border: 1rpx solid rgba(249, 224, 118, 0.2);
  color: rgba(249, 224, 118, 0.8);
  padding: 12rpx 24rpx;
  border-radius: 20rpx;
  font-size: 24rpx;
  text-align: center;
  max-width: 80%;
  line-height: 1.5;
}

/* Bubble 样式 */
.bubble-container {
  display: flex;
  align-items: flex-end;
  gap: 16rpx;
  width: 100%;
}

.bubble-container.user {
  flex-direction: row-reverse;
}

.bubble-avatar {
  width: 72rpx;
  height: 72rpx;
  border-radius: 50%;
  overflow: hidden;
  flex-shrink: 0;
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}

.bubble-avatar image {
  width: 100%;
  height: 100%;
}

.bubble-content {
  flex: 1;
  max-width: 70%;
}

.bubble {
  padding: 20rpx 24rpx;
  border-radius: 24rpx;
  position: relative;
  word-wrap: break-word;
  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.3);
}

.bubble.ai {
  background: linear-gradient(135deg, rgba(249, 224, 118, 0.15) 0%, rgba(249, 224, 118, 0.08) 100%);
  border: 1rpx solid rgba(249, 224, 118, 0.3);
  color: #f9e076;
  border-bottom-left-radius: 8rpx;
}

.bubble.user {
  background: linear-gradient(135deg, #f9e076 0%, #f5d042 100%);
  color: #1a0b2e;
  border-bottom-right-radius: 8rpx;
  box-shadow: 0 8rpx 24rpx rgba(249, 224, 118, 0.3);
}

.bubble-text {
  font-size: 28rpx;
  line-height: 1.6;
  display: block;
  margin-bottom: 8rpx;
}

.bubble-actions {
  display: flex;
  gap: 12rpx;
  margin: 12rpx 0 8rpx 0;
}

.action-btn {
  width: 48rpx;
  height: 48rpx;
  border-radius: 50%;
  background: rgba(249, 224, 118, 0.2);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
}

.action-btn:active {
  background: rgba(249, 224, 118, 0.4);
  transform: scale(0.95);
}

.action-icon {
  font-size: 24rpx;
}

.bubble-time {
  font-size: 20rpx;
  opacity: 0.6;
  text-align: right;
}

.bubble.ai .bubble-time {
  text-align: left;
}

/* 正在输入 */
.typing-indicator {
  display: flex;
  align-items: flex-end;
  gap: 16rpx;
}

.typing-bubble {
  background: linear-gradient(135deg, rgba(249, 224, 118, 0.15) 0%, rgba(249, 224, 118, 0.08) 100%);
  border: 1rpx solid rgba(249, 224, 118, 0.3);
  padding: 20rpx 24rpx;
  border-radius: 24rpx;
  border-bottom-left-radius: 8rpx;
  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.3);
}

.typing-dots {
  display: flex;
  gap: 8rpx;
  align-items: center;
}

.dot {
  width: 12rpx;
  height: 12rpx;
  border-radius: 50%;
  background: #f9e076;
  box-shadow: 0 0 8rpx rgba(249, 224, 118, 0.5);
  animation: typing 1.4s infinite ease-in-out;
}

.dot:nth-child(1) { animation-delay: -0.32s; }
.dot:nth-child(2) { animation-delay: -0.16s; }

@keyframes typing {
  0%, 80%, 100% {
    transform: scale(0.8);
    opacity: 0.5;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
}

/* 输入区域 */
.input-area {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(26, 11, 46, 0.95);
  backdrop-filter: blur(20rpx);
  border-top: 1rpx solid rgba(249, 224, 118, 0.1);
  padding: 16rpx 24rpx;
  padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.3);
  z-index: 1000;
}

.action-bar {
  margin-bottom: 12rpx;
}

.template-selector-btn {
  background: linear-gradient(135deg, rgba(249, 224, 118, 0.1) 0%, rgba(249, 224, 118, 0.05) 100%);
  border: 2rpx solid rgba(249, 224, 118, 0.3);
  border-radius: 16rpx;
  padding: 12rpx 20rpx;
  display: flex;
  align-items: center;
  gap: 12rpx;
  transition: all 0.3s;
}

.template-selector-btn:active {
  background: linear-gradient(135deg, rgba(249, 224, 118, 0.2) 0%, rgba(249, 224, 118, 0.1) 100%);
  transform: scale(0.98);
}

.template-icon {
  font-size: 28rpx;
}

.template-name {
  flex: 1;
  font-size: 26rpx;
  color: #f9e076;
  font-weight: 500;
}

.arrow-icon {
  font-size: 32rpx;
  color: #f9e076;
}

/* Sender 样式 */
.sender-container {
  background: rgba(249, 224, 118, 0.08);
  border: 1rpx solid rgba(249, 224, 118, 0.2);
  border-radius: 24rpx;
  overflow: hidden;
}

.text-input-mode {
  display: flex;
  align-items: center;
  gap: 12rpx;
  padding: 8rpx 16rpx;
}

.text-input {
  flex: 1;
  font-size: 28rpx;
  color: #f9e076;
  background: transparent;
  border: none;
  outline: none;
  padding: 12rpx 0;
  min-height: 48rpx;
}

.text-input::placeholder {
  color: rgba(249, 224, 118, 0.5);
}

.input-actions {
  display: flex;
  align-items: center;
  gap: 12rpx;
}

.action-icon-btn {
  width: 56rpx;
  height: 56rpx;
  border-radius: 50%;
  background: rgba(249, 224, 118, 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
}

.action-icon-btn:active {
  background: rgba(249, 224, 118, 0.3);
  transform: scale(0.95);
}

.icon {
  font-size: 28rpx;
}

.send-btn {
  padding: 12rpx 24rpx;
  border-radius: 20rpx;
  background: rgba(249, 224, 118, 0.2);
  font-size: 26rpx;
  color: rgba(249, 224, 118, 0.6);
  font-weight: 500;
  transition: all 0.3s;
}

.send-btn.active {
  background: linear-gradient(135deg, #f9e076 0%, #f5d042 100%);
  color: #1a0b2e;
  box-shadow: 0 4rpx 12rpx rgba(249, 224, 118, 0.4);
}

.send-btn.active:active {
  transform: scale(0.95);
}

.send-icon {
  display: block;
}

/* 语音输入模式 */
.voice-input-mode {
  display: flex;
  align-items: center;
  gap: 12rpx;
  padding: 12rpx 16rpx;
}

.hold-to-speak {
  flex: 1;
  background: rgba(249, 224, 118, 0.1);
  border: 2rpx dashed rgba(249, 224, 118, 0.3);
  border-radius: 16rpx;
  padding: 20rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
}

.hold-to-speak.recording {
  background: linear-gradient(135deg, #f9e076 0%, #f5d042 100%);
  border-color: transparent;
  animation: pulse-recording 1s infinite;
}

.speak-text {
  font-size: 28rpx;
  color: #f9e076;
  font-weight: 500;
}

.hold-to-speak.recording .speak-text {
  color: #1a0b2e;
}

@keyframes pulse-recording {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.02);
  }
}

/* 录音提示 */
.recording-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  backdrop-filter: blur(4rpx);
}

.recording-modal {
  background: rgba(26, 11, 46, 0.95);
  backdrop-filter: blur(20rpx);
  border: 2rpx solid rgba(249, 224, 118, 0.3);
  padding: 48rpx;
  border-radius: 32rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24rpx;
  box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.5);
}

.recording-tip {
  font-size: 28rpx;
  color: #f9e076;
  font-weight: 500;
  text-shadow: 0 0 10rpx rgba(249, 224, 118, 0.5);
}

.recording-animation {
  display: flex;
  gap: 8rpx;
  align-items: center;
}

.wave {
  width: 6rpx;
  height: 40rpx;
  background: linear-gradient(135deg, #f9e076 0%, #f5d042 100%);
  border-radius: 3rpx;
  animation: wave 1.2s infinite ease-in-out;
  box-shadow: 0 0 8rpx rgba(249, 224, 118, 0.5);
}

.wave:nth-child(1) { animation-delay: 0s; }
.wave:nth-child(2) { animation-delay: 0.1s; }
.wave:nth-child(3) { animation-delay: 0.2s; }
.wave:nth-child(4) { animation-delay: 0.3s; }
.wave:nth-child(5) { animation-delay: 0.4s; }

@keyframes wave {
  0%, 100% {
    height: 40rpx;
  }
  50% {
    height: 80rpx;
  }
}

/* 模态框 */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  backdrop-filter: blur(8rpx);
}

.modal-content {
  width: 86%;
  max-width: 640rpx;
  max-height: 80vh;
  background: linear-gradient(135deg, rgba(26, 11, 46, 0.98) 0%, rgba(45, 27, 78, 0.98) 100%);
  border: 2rpx solid rgba(249, 224, 118, 0.3);
  border-radius: 32rpx;
  overflow: hidden;
  box-shadow: 0 12rpx 48rpx rgba(0, 0, 0, 0.5);
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 32rpx;
  border-bottom: 1rpx solid rgba(249, 224, 118, 0.1);
  background: linear-gradient(135deg, rgba(249, 224, 118, 0.08) 0%, rgba(249, 224, 118, 0.03) 100%);
}

.modal-title {
  font-size: 32rpx;
  font-weight: 600;
  color: #f9e076;
  text-shadow: 0 0 15rpx rgba(249, 224, 118, 0.5);
}

.close-btn {
  width: 56rpx;
  height: 56rpx;
  border-radius: 50%;
  background: rgba(249, 224, 118, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
}

.close-btn:active {
  background: rgba(249, 224, 118, 0.2);
  transform: scale(0.95);
}

.close-icon {
  font-size: 28rpx;
  color: #f9e076;
}

.template-list {
  max-height: 60vh;
  overflow-y: auto;
}

.template-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 32rpx;
  border-bottom: 1rpx solid rgba(249, 224, 118, 0.1);
  transition: all 0.3s;
}

.template-item:active {
  background: rgba(249, 224, 118, 0.05);
}

.template-item.active {
  background: linear-gradient(135deg, rgba(249, 224, 118, 0.15) 0%, rgba(249, 224, 118, 0.08) 100%);
}

.template-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8rpx;
  padding-right: 16rpx;
}

.template-item .template-name {
  font-size: 28rpx;
  font-weight: 600;
  color: #f9e076;
  margin-bottom: 4rpx;
}

.template-desc {
  font-size: 24rpx;
  color: rgba(249, 224, 118, 0.7);
  line-height: 1.5;
}

.check-mark {
  width: 48rpx;
  height: 48rpx;
  border-radius: 50%;
  background: linear-gradient(135deg, #f9e076 0%, #f5d042 100%);
  box-shadow: 0 4rpx 12rpx rgba(249, 224, 118, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.check-icon {
  font-size: 24rpx;
  color: #1a0b2e;
  font-weight: bold;
}
</style>
