<template>
  <div class="ai-sidebar-wrapper">
    <!-- 侧边栏切换按钮 - 放在侧边栏外部 -->
    <div class="sidebar-toggle" 
         @click="toggleSidebar" 
         :title="isCollapsed ? '展开AI助手' : '折叠AI助手'"
         :style="{ left: isCollapsed ? '10px' : '420px' }">
      <svg v-if="isCollapsed" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
        <path d="M9 18l6-6-6-6"/>
      </svg>
      <svg v-else width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
        <path d="M15 18l-6-6 6-6"/>
      </svg>
    </div>
    
    <div class="ai-sidebar" :class="{ 'sidebar-collapsed': isCollapsed }">

    <!-- 侧边栏内容 -->
    <div class="sidebar-content" v-show="!isCollapsed">
      <div class="sidebar-header">
        <h3>🤖 AI 助手</h3>
        <p>文档转思维导图工具</p>
        <div class="collapse-hint">
          <small>💡 点击右侧按钮可折叠侧边栏</small>
        </div>
      </div>

      <!-- AI生成Markdown部分 -->
      <!-- 文件上传AI生成Markdown -->
      <div class="section">
        <h4>📁 生成思维导图</h4>
        <div class="input-group">
          <label>上传文件：</label>
          <div class="file-upload-area"
               @drop="handleFileDrop"
               @dragover="handleDragOver"
               @dragleave="handleDragLeave">
            <input 
              type="file" 
              ref="fileInput"
              @change="handleFileUpload"
              accept=".txt,.md,.doc,.docx,.pdf"
              class="file-input"
            />
            <div class="file-upload-placeholder" :class="{ 'drag-over': isDragOver }">
              <span class="upload-icon">📎</span>
              <span class="upload-text">点击选择文件或拖拽文件到此处</span>
              <span class="upload-hint">支持 .txt, .md, .doc, .docx, .pdf 格式</span>
            </div>
          </div>
        </div>
        
        <!-- 文件信息显示 -->
        <div v-if="uploadedFile" class="file-info">
          <div class="file-details">
            <div class="file-info-left">
              <span class="file-name">📄 {{ uploadedFile.name }}</span>
              <span class="file-size">({{ formatFileSize(uploadedFile.size) }})</span>
            </div>
            <button @click="removeFile" class="btn-remove" title="删除文件">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M10 11v6M14 11v6"/>
              </svg>
            </button>
          </div>
        </div>
        
        <div class="button-group file-action-buttons">
          <button 
            @click="generateMarkdownFromFile" 
            :disabled="!uploadedFile || isGenerating" 
            class="btn-primary"
          >
            <span v-if="isGenerating">AI生成中...</span>
            <span v-else>AI生成思维导图</span>
          </button>
        </div>
      </div>

      <!-- 历史记录 -->
      <div class="section" v-if="history.length > 0">
        <h4>📚 历史记录</h4>
        <div class="history-list">
          <div 
            v-for="(item, index) in history" 
            :key="index" 
            class="history-item"
            @click="loadHistoryItem(item)"
          >
            <div class="history-title">{{ item.title }}</div>
            <div class="history-time">{{ formatTime(item.timestamp) }}</div>
          </div>
        </div>
      </div>

      <!-- AI生成的Markdown结果 - 固定显示区域 -->
      <div class="section">
        <h4>📝 AI生成的Markdown结果</h4>
        <div class="input-group">
          <label>Markdown内容：</label>
          <textarea 
            v-model="markdownContent" 
            placeholder="AI生成的Markdown内容将显示在这里"
            rows="6"
            readonly
            class="markdown-result"
          ></textarea>
        </div>
        <div class="button-group">
          <button @click="convertToJSON" :disabled="isConverting" class="btn-secondary">
            <span v-if="isConverting">转换中...</span>
            <span v-else>🔄 转换为JSON</span>
          </button>
          <button @click="clearContent" class="btn-clear">清空</button>
          <button @click="copyMarkdown" class="btn-copy">📋 复制Markdown</button>
        </div>
      </div>

      <!-- Markdown转JSON结果 - 固定显示区域 -->
      <div class="section">
        <h4>📊 Markdown转JSON结果</h4>
        
        <!-- 处理状态显示 -->
        <div v-if="isProcessing" class="processing-status">
          <div class="spinner"></div>
          <span>{{ processingMessage }}</span>
        </div>
        
        <div class="result-container">
          <pre class="json-result">{{ convertedJSON || 'JSON转换结果将显示在这里' }}</pre>
          <div class="button-group">
            <button @click="copyJSON" class="btn-copy">📋 复制JSON</button>
            <button @click="previewMindmap" :disabled="isProcessing" class="btn-copy">
              {{ isProcessing ? '处理中...' : '👁️ 预览' }}
            </button>
          </div>
        </div>
      </div>

      <!-- 快速测试
      <div class="section">
        <h4>🧪 快速测试</h4>
        <div class="button-group">
          <button @click="loadTestData" class="btn-test">📊 加载测试数据</button>
          <button @click="clearAll" class="btn-clear">🗑️ 清空所有</button>
        </div>
      </div> -->

      <!-- 历史记录
      <div class="section" v-if="history.length > 0">
        <h4>📚 历史记录</h4>
        <div class="history-list">
          <div 
            v-for="(item, index) in history" 
            :key="index" 
            class="history-item"
            @click="loadHistoryItem(item)"
          >
            <div class="history-title">{{ item.title }}</div>
            <div class="history-time">{{ formatTime(item.timestamp) }}</div>
          </div>
        </div>
      </div> -->
    </div>
  </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue';
import axios from 'axios';
import { marked } from 'marked';
import { hasMarkdownSyntax, renderMarkdownToHTML } from '../utils/markdownRenderer.js';

// 定义emit事件
const emit = defineEmits(['start-realtime-generation']);

// 响应式数据
const isCollapsed = ref(false); // 默认展开状态
const aiPrompt = ref('');
const markdownContent = ref('');
const convertedJSON = ref('');
const isGenerating = ref(false);
const isConverting = ref(false);
const history = ref([]);
const isDragOver = ref(false);


// 保存用户输入状态
const savedAiPrompt = ref('');
const savedMarkdownContent = ref('');

// 添加状态管理
const isProcessing = ref(false);
const processingMessage = ref('');

// 文件上传相关
const fileInput = ref(null);
const uploadedFile = ref(null);

// 切换侧边栏
const toggleSidebar = () => {
  isCollapsed.value = !isCollapsed.value;
  
  // 发送折叠状态改变事件
  window.dispatchEvent(new CustomEvent('ai-sidebar-toggle', {
    detail: {
      isCollapsed: isCollapsed.value
    }
  }));
};

// 文件上传处理
const handleFileUpload = (event) => {
  const file = event.target.files[0];
  if (file) {
    uploadedFile.value = file;
    showNotification('文件上传成功！', 'success');
  }
};

// 拖拽文件处理
const handleFileDrop = (event) => {
  event.preventDefault();
  isDragOver.value = false;
  
  const files = event.dataTransfer.files;
  if (files.length > 0) {
    const file = files[0];
    // 检查文件类型
    const allowedTypes = ['.txt', '.md', '.doc', '.docx', '.pdf'];
    const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
    
    if (allowedTypes.includes(fileExtension)) {
      uploadedFile.value = file;
      showNotification('文件拖拽上传成功！', 'success');
    } else {
      showNotification('不支持的文件格式！请上传 .txt, .md, .doc, .docx, .pdf 格式的文件', 'error');
    }
  }
};

// 拖拽悬停处理
const handleDragOver = (event) => {
  event.preventDefault();
  isDragOver.value = true;
};

// 拖拽离开处理
const handleDragLeave = (event) => {
  event.preventDefault();
  isDragOver.value = false;
};

// 移除文件
const removeFile = () => {
  uploadedFile.value = null;
  
  if (fileInput.value) {
    fileInput.value.value = '';
  }
};

// 格式化文件大小
const formatFileSize = (bytes) => {
  if (bytes === 0) return '0 Bytes';
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};



// 从文件生成Markdown
const generateMarkdownFromFile = async () => {
  if (!uploadedFile.value) {
    showNotification('请先上传文件', 'error');
    return;
  }

  isGenerating.value = true;
  
  // 立即切换到思维导图界面，开始实时渲染
  emit('start-realtime-generation');
  
  try {
      // 读取文件内容
      const fileContent = await readFileContent(uploadedFile.value);
    
    // 清空之前的内容，准备流式生成
    markdownContent.value = '';
    
    // 调用流式AI API生成Markdown
    const systemPrompt = `你是一个专业的文档分析专家。请分析上传的文档内容，生成结构化的Markdown格式思维导图。要求：
1. 提取主要主题和关键概念
2. 组织成层次分明的结构
3. 使用清晰的标题和子标题
4. 保持内容的逻辑性和完整性
5. 对于长文档，请确保完整处理所有内容，不要截断
6. **重要：如果原文档中包含图片，请按以下方式处理：
   - 识别图片在文档中的位置和上下文
   - 根据图片内容生成准确的描述文字
   - 在相应位置插入图片占位符：![图片描述](图片路径)
   - 图片描述要准确反映图片内容，图片路径可以是相对路径或占位符
   - 确保图片占位符放在逻辑上合适的位置**
7. **重要：如果原文档中包含表格，请完整保留表格结构：
   - 保持表格的Markdown格式
   - 确保所有表格行都被包含
   - 不要省略任何表格内容
   - 对于合并单元格的表格，请使用HTML格式并正确使用rowspan和colspan属性
   - 如果表格结构复杂，优先使用HTML table标签而不是Markdown表格语法**
8. **重要：确保内容完整性：
   - 不要截断任何内容
   - 保持原文的完整性
   - 所有重要信息都要包含在思维导图中**
9. 输出格式：直接输出Markdown内容，不要添加任何说明文字或代码块标记`;
      const userPrompt = `请分析以下文档内容并生成结构化Markdown：\n\n${fileContent}`;
    
    // 关键修改：使用流式API而不是非流式API
    await callAIStreamAPI(systemPrompt, userPrompt);
    
    
    // 自动转换为JSON
    await convertToJSON();
    
    // 添加到历史记录
    addToHistory(uploadedFile.value.name, markdownContent.value);
    
    // showNotification('AI生成Markdown成功！正在自动保存...', 'success');
    
    // 延迟一下让用户看到成功消息，然后自动保存
    setTimeout(async () => {
      try {
        await previewMindmap();
        } catch (error) {
          console.error('自动保存失败:', error);
        }
    }, 1500);
    
  } catch (error) {
    console.error('从文件生成Markdown失败:', error);
    showNotification('生成失败: ' + error.message, 'error');
  } finally {
    isGenerating.value = false;
  }
};

// 读取文件内容
const readFileContent = (file) => {
  return new Promise(async (resolve, reject) => {
    try {
      // 检查文件类型和扩展名
      const isTextFile = file.type.includes('text') || 
                         file.name.endsWith('.txt') || 
                         file.name.endsWith('.md');
      
      const isOfficeFile = file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || // .docx
                           file.type === 'application/msword' || // .doc
                           file.name.endsWith('.docx') || 
                           file.name.endsWith('.doc');
      
      const isPDFFile = file.type === 'application/pdf' || 
                        file.name.endsWith('.pdf');
      
      if (isTextFile) {
        // 文本文件直接读取
        const reader = new FileReader();
        reader.onload = (e) => resolve(e.target.result);
        reader.onerror = () => reject(new Error('文本文件读取失败'));
        reader.readAsText(file);
      } else if (isOfficeFile) {
        // Office文档处理
        const content = await extractOfficeContent(file);
        resolve(content);
      } else if (isPDFFile) {
        // PDF文件处理
        const content = await extractPDFContent(file);
        resolve(content);
      } else {
        // 对于其他格式，先尝试作为文本读取
        const reader = new FileReader();
        reader.onload = (e) => resolve(e.target.result);
        reader.onerror = () => reject(new Error('文件读取失败'));
        reader.readAsText(file);
      }
    } catch (error) {
      reject(error);
    }
  });
};

// 提取Office文档内容
const extractOfficeContent = async (file) => {
  try {
    if (file.name.endsWith('.docx')) {
      // 使用mammoth.js解析.docx文件
      const mammoth = await import('mammoth');
      const arrayBuffer = await file.arrayBuffer();
      const result = await mammoth.extractRawText({ arrayBuffer });
      return result.value;
    } else if (file.name.endsWith('.doc')) {
      // 对于.doc文件，提示用户转换为.docx格式
      throw new Error('请将.doc文件转换为.docx格式，或安装相应的解析库');
    }
  } catch (error) {
    throw new Error(`Office文档解析失败: ${error.message}`);
  }
};

// 提取PDF文件内容
const extractPDFContent = async (file) => {
  try {
    // 使用pdf.js解析PDF文件
    const pdfjsLib = await import('pdfjs-dist');
    
    // 设置worker路径为本地文件
    pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.mjs';
    
    const arrayBuffer = await file.arrayBuffer();
    const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
    
    let fullText = '';
    for (let i = 1; i <= pdf.numPages; i++) {
      const page = await pdf.getPage(i);
      const textContent = await page.getTextContent();
      const pageText = textContent.items.map(item => item.str).join(' ');
      fullText += pageText + '\n';
    }
    
    return fullText;
  } catch (error) {
    throw new Error(`PDF文件解析失败: ${error.message}`);
  }
};

// AI生成Markdown（流式版本）
const generateMarkdown = async () => {
  if (!aiPrompt.value.trim()) {
    showNotification('请输入主题描述', 'error');
    return;
  }

  // 保存用户输入
  savedAiPrompt.value = aiPrompt.value;
  
  isGenerating.value = true;
  markdownContent.value = ''; // 清空之前的内容
  
  // 立即切换到思维导图界面，开始实时渲染
  emit('start-realtime-generation');
  
  try {
    // 调用流式AI API
    await callAIStreamAPI(null, aiPrompt.value);
    
    
    // 自动转换为JSON
    await convertToJSON();
    
    // 添加到历史记录
    addToHistory(aiPrompt.value.substring(0, 30) + '...', markdownContent.value);
    
    // 确保AI提示词不被清空
    if (aiPrompt.value !== savedAiPrompt.value) {
      aiPrompt.value = savedAiPrompt.value;
    }
    
    // showNotification('AI生成Markdown成功！正在自动保存...', 'success');
    
    // 延迟一下让用户看到成功消息，然后自动保存
    setTimeout(async () => {
      try {
        await previewMindmap();
      } catch (error) {
        console.error('自动保存失败:', error);
        showNotification('自动保存失败，请手动点击预览按钮', 'error');
      }
    }, 1500);
    
  } catch (error) {
    console.error('生成Markdown失败:', error);
    showNotification('生成失败: ' + error.message, 'error');
  } finally {
    isGenerating.value = false;
  }
};

// 清理AI返回的内容，移除多余的说明文字
const cleanAIResponse = (content) => {
  if (!content) return content;
  
  let cleaned = content
    // 移除常见的AI开头说明文字 - 更全面的匹配
    .replace(/^好的[，,]?作为.*?专家[，,]?我已.*?分析.*?内容.*?生成了以下.*?思维导图[：:]\s*/i, '')
    .replace(/^好的[，,]?作为.*?专业的.*?专家[，,]?我已.*?分析.*?内容.*?生成了以下.*?思维导图[：:]\s*/i, '')
    .replace(/^以下是.*?结构化的.*?思维导图[：:]\s*/i, '')
    .replace(/^以下是.*?Markdown.*?思维导图[：:]\s*/i, '')
    .replace(/^以下是.*?Markdown.*?格式.*?思维导图[：:]\s*/i, '')
    // 移除代码块标记
    .replace(/^```(?:markdown)?\s*/gm, '')
    .replace(/```\s*$/gm, '')
    // 移除多余的引号和标记 - 更精确的匹配
    .replace(/^「」`markdown\s*/gm, '')
    .replace(/^「」`\s*/gm, '')
    .replace(/^\s*「」`markdown\s*/gm, '')
    .replace(/^\s*「」`\s*/gm, '')
    // 移除其他可能的AI开头模式
    .replace(/^作为.*?专家[，,]?我已.*?分析.*?内容.*?生成了以下.*?思维导图[：:]\s*/i, '')
    .replace(/^我已.*?分析.*?内容.*?生成了以下.*?思维导图[：:]\s*/i, '')
    .replace(/^根据.*?文档内容.*?生成了以下.*?思维导图[：:]\s*/i, '')
    .replace(/^基于.*?文档.*?生成了以下.*?思维导图[：:]\s*/i, '')
    // 移除更多可能的开头模式
    .replace(/^以下是.*?分析.*?结果[：:]\s*/i, '')
    .replace(/^以下是.*?整理.*?结果[：:]\s*/i, '')
    .replace(/^以下是.*?结构化.*?内容[：:]\s*/i, '')
    // 移除多余的换行
    .replace(/\n{3,}/g, '\n\n')
    // 清理开头和结尾的空白
    .trim();
  
  return cleaned;
};

// 防抖函数
const debounce = (func, wait) => {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
};

// 调用AI API生成Markdown
// 流式AI API调用
const callAIStreamAPI = async (systemPrompt, userPrompt) => {
  const defaultSystemPrompt = `你是一位Markdown格式转换专家。你的任务是将用户提供的文章内容精确转换为结构化的Markdown格式。请遵循以下步骤：

提取主标题： 识别文章最顶层的主标题（通常为文章题目或书名），并使用Markdown的 # 级别表示。

识别层级标题： 从文章内容中提取所有层级的内容标题（从主标题后的第一个标题开始，Level 1 至 Level 4）。判断层级依据：

视觉与结构特征： 如独立成行/段、位置（行首）、格式（加粗、编号如 1., 1.1, (1), - 等）。

语义逻辑： 标题之间的包含和并列关系。

在Markdown中，使用相应标题级别：

Level 1 标题用 ##

Level 2 标题用 ###

Level 3 标题用 ####

Level 4 标题用 #####

精确保留原文标题文字，不得修改、概括或润色。

处理正文内容： 对于每个标题下的正文内容区块（从该标题后开始，直到下一个同级或更高级别标题前）：

直接保留原文文本，但根据内容结构适当格式化为Markdown。

如果内容是列表（如项目符号或编号列表），使用Markdown列表语法（例如 - 用于无序列表，1. 用于有序列表）。

保持段落和换行不变。

**重要：如果原文档中包含图片，请按以下方式处理：
1. 识别图片在文档中的位置和上下文
2. 根据图片内容生成准确的描述文字
3. 在相应位置插入图片占位符：![图片描述](图片路径)
4. 图片描述要准确反映图片内容，图片路径可以是相对路径或占位符
5. 确保图片占位符放在逻辑上合适的位置**

输出格式： 输出必须是纯Markdown格式的文本，不得包含任何额外说明、JSON或非Markdown元素。确保输出与示例风格一致。直接输出Markdown内容，不要添加任何说明文字。`;

  const finalSystemPrompt = systemPrompt || defaultSystemPrompt;
  const finalUserPrompt = userPrompt || `请将以下内容转换为结构化的Markdown格式：`;

    try {
    
    const response = await fetch('http://127.0.0.1:8000/api/ai/generate-stream', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        system_prompt: finalSystemPrompt,
        user_prompt: finalUserPrompt,
        model: 'glm-4.5',
        base_url: 'https://open.bigmodel.cn/api/paas/v4/',
        api_key: 'ce39bdd4fcf34ec0aec75072bc9ff988.hAp7HZTVUwy7vImn'
      })
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';
    let chunkCount = 0;

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      buffer += decoder.decode(value, { stream: true });
      const lines = buffer.split('\n');
      buffer = lines.pop() || '';

      for (const line of lines) {
        if (line.startsWith('data: ')) {
          try {
            const data = JSON.parse(line.slice(6));
            
            if (data.type === 'start') {
              showNotification('AI开始生成内容...', 'info');
            } else if (data.type === 'chunk') {
              chunkCount++;
              
              // 实时更新Markdown内容
              markdownContent.value += data.content;
              
              // 优化：减少实时更新频率，每5个chunk更新一次
              if (chunkCount % 5 === 0) {
                try {
                  // 清理AI返回的多余内容
                  const cleanedContent = cleanAIResponse(markdownContent.value);
                  const tempJSON = markdownToJSON(cleanedContent);
                  convertedJSON.value = JSON.stringify(tempJSON, null, 2);
                  
                  // 🎯 关键：实时更新思维导图显示
                  window.dispatchEvent(new CustomEvent('realtime-mindmap-update', {
                    detail: { 
                      data: tempJSON,
                      title: tempJSON.topic || 'AI生成中...',
                      source: 'ai-streaming',
                      chunkCount: chunkCount
                    }
                  }));
                  
                } catch (e) {
                  // 忽略转换错误，继续接收数据
                  console.warn('⚠️ 实时转换JSON失败:', e);
                }
              }
            } else if (data.type === 'end') {
              showNotification('AI内容生成完成！', 'success');
              
              // 最终处理：确保所有内容都被正确处理
              try {
                const finalCleanedContent = cleanAIResponse(markdownContent.value);
                console.log('🎯 最终内容长度:', finalCleanedContent.length);
                console.log('🎯 最终内容预览:', finalCleanedContent.substring(0, 500) + '...');
                
                // 统计图片数量
                const allImages = extractImageFromContent(finalCleanedContent);
                console.log(`🖼️ 最终统计：共发现 ${allImages.length} 张图片`);
                
                const finalJSON = markdownToJSON(finalCleanedContent);
                convertedJSON.value = JSON.stringify(finalJSON, null, 2);
                
                // 最终更新思维导图
                window.dispatchEvent(new CustomEvent('realtime-mindmap-update', {
                  detail: { 
                    data: finalJSON,
                    title: finalJSON.topic || 'AI生成完成',
                    source: 'ai-final',
                    chunkCount: chunkCount
                  }
                }));
              } catch (e) {
                console.error('⚠️ 最终处理失败:', e);
              }
            } else if (data.type === 'error') {
              throw new Error(data.content);
            }
          } catch (e) {
            console.warn('解析流式数据失败:', e);
          }
        }
      }
    }
  } catch (error) {
    console.error('流式AI API调用失败:', error);
    throw error;
  }
};

const callAIMarkdownAPI = async (systemPrompt, userPrompt, retryCount = 0) => {
  const defaultSystemPrompt = `你是一位Markdown格式转换专家。你的任务是将用户提供的文章内容精确转换为结构化的Markdown格式。请遵循以下步骤：

提取主标题： 识别文章最顶层的主标题（通常为文章题目或书名），并使用Markdown的 # 级别表示。

识别层级标题： 从文章内容中提取所有层级的内容标题（从主标题后的第一个标题开始，Level 1 至 Level 4）。判断层级依据：

视觉与结构特征： 如独立成行/段、位置（行首）、格式（加粗、编号如 1., 1.1, (1), - 等）。

语义逻辑： 标题之间的包含和并列关系。

在Markdown中，使用相应标题级别：

Level 1 标题用 ##

Level 2 标题用 ###

Level 3 标题用 ####

Level 4 标题用 #####

精确保留原文标题文字，不得修改、概括或润色。

处理正文内容： 对于每个标题下的正文内容区块（从该标题后开始，直到下一个同级或更高级别标题前）：

直接保留原文文本，但根据内容结构适当格式化为Markdown。

如果内容是列表（如项目符号或编号列表），使用Markdown列表语法（例如 - 用于无序列表，1. 用于有序列表）。

保持段落和换行不变。

**重要：如果原文档中包含图片，请按以下方式处理：
1. 识别图片在文档中的位置和上下文
2. 根据图片内容生成准确的描述文字
3. 在相应位置插入图片占位符：![图片描述](图片路径)
4. 图片描述要准确反映图片内容，图片路径可以是相对路径或占位符
5. 确保图片占位符放在逻辑上合适的位置**

输出格式： 输出必须是纯Markdown格式的文本，不得包含任何额外说明、JSON或非Markdown元素。确保输出与示例风格一致。直接输出Markdown内容，不要添加任何说明文字。`;

  // 如果没有提供系统提示词，使用默认的
  const finalSystemPrompt = systemPrompt || defaultSystemPrompt;
  
  // 如果没有提供用户提示词，使用传入的prompt作为用户提示词
  const finalUserPrompt = userPrompt || `请将以下内容转换为结构化的Markdown格式：`;

  try {
    
    // 显示进度提示
    // showNotification('AI正在分析文档，请耐心等待（最多2分钟）...', 'info');
    
    // 添加超时处理 - 增加超时时间，处理复杂文档
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), 300000); // 增加到5分钟超时
    
    const response = await fetch('http://127.0.0.1:8000/api/ai/generate-markdown', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        system_prompt: finalSystemPrompt,
        user_prompt: finalUserPrompt,
        model: "glm-4.5",
        base_url: "https://open.bigmodel.cn/api/paas/v4/",
        api_key: "ce39bdd4fcf34ec0aec75072bc9ff988.hAp7HZTVUwy7vImn"
      }),
      signal: controller.signal
    });
    
    clearTimeout(timeoutId);

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    
    let markdownContent = '';
    if (data.success && data.markdown) {
      markdownContent = data.markdown;
    } else if (data.markdown) {
      markdownContent = data.markdown;
    } else if (data.content) {
      markdownContent = data.content;
    } else {
      console.error('❌ AI API响应格式错误:', data);
      return '生成失败，请重试';
    }
    
    // 检查内容是否完整
    
    // 检查是否以不完整的句子结尾
    const isTruncated = markdownContent.trim().endsWith('-') || 
        markdownContent.trim().endsWith('•') ||
        markdownContent.trim().endsWith('*') ||
        markdownContent.trim().endsWith('**') ||
        markdownContent.trim().endsWith('###') ||
        markdownContent.trim().endsWith('##') ||
        markdownContent.trim().endsWith('#') ||
        markdownContent.trim().endsWith('时') ||
        markdownContent.trim().endsWith('的') ||
        markdownContent.trim().endsWith('和') ||
        markdownContent.trim().endsWith('或');
    
    if (isTruncated && retryCount < 2) {
      console.warn(`⚠️ 检测到内容可能被截断，进行第${retryCount + 1}次重试`);
      // showNotification(`检测到内容可能被截断，正在重试...（${retryCount + 1}/2）`, 'warning');
      
      // 等待1秒后重试
      await new Promise(resolve => setTimeout(resolve, 1000));
      return await callAIMarkdownAPI(systemPrompt, userPrompt, retryCount + 1);
    } else if (isTruncated) {
      console.warn('⚠️ 内容可能被截断，但已达到最大重试次数');
      showNotification('内容可能被截断，请尝试上传较小的文档或稍后重试', 'warning');
    }
    
    return markdownContent;
  } catch (error) {
    if (error.name === 'AbortError') {
      throw new Error('AI API请求超时（2分钟），文档可能较复杂，请重试或尝试上传较小的文档');
    }
    console.error('AI API调用失败:', error);
    // 如果API调用失败，抛出异常
    throw new Error(`AI API调用失败: ${error.message}`);
  }
};

// 移除模拟数据生成函数，只使用真实的AI API

// 格式化Markdown为结构化文本
const formatMarkdownToText = (markdown) => {
  // 首先检查是否是表格内容，如果是表格则不进行转换
  if (markdown.includes('|') && markdown.includes('-')) {
    const lines = markdown.split('\n');
    let hasTableRow = false;
    let hasSeparator = false;
    
    for (const line of lines) {
      const trimmedLine = line.trim();
      if (trimmedLine.includes('|') && trimmedLine.split('|').length >= 3) {
        hasTableRow = true;
      }
      if (trimmedLine.includes('|') && trimmedLine.includes('-') && /^[\s\|\-\:]+$/.test(trimmedLine)) {
        hasSeparator = true;
      }
    }
    
    if (hasTableRow && hasSeparator) {
      console.log('🚫 formatMarkdownToText: 检测到表格内容，跳过转换');
      return markdown; // 返回原始表格内容
    }
  }
  
  // 图片现在通过MindElixir原生image属性处理，不需要特殊处理
  
  return markdown
    // 处理标题
    .replace(/^### (.*$)/gim, '📋 $1')  // 三级标题
    .replace(/^## (.*$)/gim, '📌 $1')   // 二级标题
    .replace(/^# (.*$)/gim, '🎯 $1')    // 一级标题
    // 处理粗体 - 改进处理逻辑，确保冒号等标点符号正确处理
    .replace(/\*\*(.*?)\*\*/g, (match, content) => {
      // 如果内容包含冒号，保持冒号，只处理粗体部分
      if (content.includes(':')) {
        const parts = content.split(':');
        if (parts.length > 1) {
          return `【${parts[0]}】: ${parts.slice(1).join(':')}`;
        }
      }
      return `【${content}】`;
    })
    // 处理斜体
    .replace(/\*(.*?)\*/g, '《$1》')
    // 处理列表项
    .replace(/^- (.*$)/gim, '  • $1')
    .replace(/^\d+\. (.*$)/gim, '  $&')
    // 处理代码块
    .replace(/```(.*?)```/gims, '💻 $1')
    // 处理行内代码
    .replace(/`(.*?)`/g, '「$1」')
    // 处理链接
    .replace(/\[([^\]]+)\]\([^)]+\)/g, '🔗 $1')
    // 图片通过MindElixir原生image属性处理，保留图片占位符用于后续处理
    .replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '[图片: $1]')
    // 处理换行 - 优化换行处理，避免错位
    .replace(/\n\n/g, '\n')
    .replace(/\n/g, '\n  ')
    // 限制单行长度，避免节点过宽导致错位
    .split('\n')
    .map(line => {
      // 如果行太长，进行智能截断
      if (line.length > 80) {
        return line.substring(0, 77) + '...';
      }
      return line;
    })
    .join('\n')
    .trim();
};

// Markdown转JSON
const convertToJSON = async () => {
  if (!markdownContent.value.trim()) {
    showNotification('请输入Markdown内容', 'error');
    return;
  }

  isConverting.value = true;
  try {
    // 清理AI返回的多余内容
    const cleanedContent = cleanAIResponse(markdownContent.value);
    const json = markdownToJSON(cleanedContent);
    convertedJSON.value = JSON.stringify(json, null, 2);
  } catch (error) {
    console.error('转换失败:', error);
    showNotification('转换失败，请检查Markdown格式', 'error');
  } finally {
    isConverting.value = false;
  }
};

// 统计节点数量的辅助函数
const countNodes = (node) => {
  if (!node) return 0;
  let count = 1; // 当前节点
  if (node.children && node.children.length > 0) {
    for (const child of node.children) {
      count += countNodes(child);
    }
  }
  return count;
};

// 提取图片信息的辅助函数
const extractImageFromContent = (content) => {
  const imageRegex = /!\[([^\]]*)\]\(([^)]+)\)/g;
  const images = [];
  let match;
  
  while ((match = imageRegex.exec(content)) !== null) {
    const url = match[2];
    const alt = match[1] || '';
    
    // 验证图片URL
    if (url && url.trim() && (url.startsWith('http') || url.startsWith('data:') || url.startsWith('/'))) {
      images.push({
        alt: alt,
        url: url.trim(),
        fullMatch: match[0]
      });
      console.log(`✅ 有效图片URL: ${url}`);
    } else {
      console.warn(`⚠️ 跳过无效的图片URL: ${url}`);
    }
  }
  
  console.log(`🔍 从内容中提取到 ${images.length} 张图片:`, images);
  return images;
};

// 从内容中移除图片Markdown语法
const removeImageMarkdown = (content) => {
  return content.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '').trim();
};

// Markdown转JSON的核心逻辑 - 智能层次化版本
const markdownToJSON = (markdown) => {
  const lines = markdown.split('\n');
  let root = null;
  const stack = [];
  let nodeCounter = 0;
  let currentContent = [];
  
  lines.forEach((line, index) => {
    const trimmed = line.trim();
    
    // 检测标题级别
    const match = trimmed.match(/^(#{1,6})\s+(.+)$/);
    if (match) {
      // 如果有累积的内容，先保存到当前节点
      if (currentContent.length > 0 && stack.length > 0) {
        const content = currentContent.join('\n').trim();
        if (content) {
          // 智能处理内容：检测是否需要创建子节点
          const processedContent = processContentIntelligently(content, stack[stack.length - 1], nodeCounter);
          nodeCounter = processedContent.nodeCounter;
        }
        currentContent = [];
      }
      
      const level = match[1].length;
      const title = match[2].trim();
      
      // 检查标题中是否包含图片
      const titleImages = extractImageFromContent(title);
      const cleanTitle = removeImageMarkdown(formatMarkdownToText(title));
      
      if (titleImages.length > 0) {
        console.log(`🖼️ 在标题中发现 ${titleImages.length} 张图片: ${title}`);
      }
      
      // 创建节点
      const node = {
        id: `node_${nodeCounter++}`,
        topic: cleanTitle,
        children: [],
        level: level,
        data: {},
      };
      
      // 如果标题中有图片，使用第一个图片作为节点图片
      if (titleImages.length > 0) {
        const firstImage = titleImages[0];
        if (firstImage.url && firstImage.url.trim() !== '') {
          node.image = {
            url: firstImage.url,
            width: 200,
            height: 150,
            fit: 'contain'
          };
          console.log(`✅ 成功为标题节点设置图片: ${firstImage.url}`);
        } else {
          console.error(`❌ 标题图片URL无效:`, firstImage);
        }
      }
      
      // 如果是第一个节点（最高级别），设为根节点
      if (level === 1 && !root) {
        root = node;
        stack.length = 0; // 清空栈
        stack.push(root);
      } else {
        // 找到合适的父节点
        while (stack.length > 1 && stack[stack.length - 1].level >= level) {
          stack.pop();
        }
        
        // 添加到父节点
        if (stack.length > 0) {
          stack[stack.length - 1].children.push(node);
        }
        
        // 更新栈
        stack.push(node);
      }
    } else if (trimmed) {
      // 累积内容行
      currentContent.push(trimmed);
    }
  });
  
  // 处理最后的内容
  if (currentContent.length > 0 && stack.length > 0) {
    const content = currentContent.join('\n').trim();
    if (content) {
      // 检查是否包含表格内容
      if (content.includes('|')) {
        console.log('🔍 处理最后的内容（包含表格）:', content.substring(0, 200) + '...');
      }
      const processedContent = processContentIntelligently(content, stack[stack.length - 1], nodeCounter);
      nodeCounter = processedContent.nodeCounter;
    }
  }
  
  // 如果没有找到任何内容，返回默认根节点
  if (!root) {
    root = {
      id: 'root',
      topic: '根节点',
      children: [],
      data: {}
    };
  }
  
  return root;
};

// 智能处理内容，检测是否需要创建子节点
const processContentIntelligently = (content, parentNode, nodeCounter) => {
  // 首先检查是否包含图片内容
  const images = extractImageFromContent(content);
  if (images.length > 0) {
    console.log(`🖼️ 在内容中发现 ${images.length} 张图片`);
    
    // 为每个图片创建单独的节点
    images.forEach((image, index) => {
      console.log(`🖼️ 处理图片 ${index + 1}:`, {
        alt: image.alt,
        url: image.url,
        urlLength: image.url.length
      });
      
      const imageNode = {
        id: `node_${nodeCounter++}`,
        topic: image.alt || `图片 ${index + 1}`,
        children: [],
        level: (parentNode.level || 0) + 1,
        image: {
          url: image.url,
          width: 200,
          height: 150,
          fit: 'contain'
        },
        data: {}
      };
      
      // 验证图片节点数据
      if (!imageNode.image.url || imageNode.image.url.trim() === '') {
        console.error(`❌ 图片节点 ${index + 1} URL为空:`, imageNode);
        return;
      }
      
      parentNode.children.push(imageNode);
      console.log(`✅ 成功创建图片节点: ${imageNode.topic} - ${image.url}`);
    });
    
    // 移除图片后的内容
    const contentWithoutImages = removeImageMarkdown(content);
    if (contentWithoutImages.trim()) {
      // 递归处理剩余内容
      const processedContent = processContentIntelligently(contentWithoutImages, parentNode, nodeCounter);
      nodeCounter = processedContent.nodeCounter;
    }
    
    return { nodeCounter };
  }
  
  // 然后检查整个内容是否是表格
  if (hasTableContent(content)) {
    console.log('🎯 检测到表格内容，创建表格节点');
    // 将markdown表格转换为HTML格式
    const htmlContent = renderMarkdownToHTML(content);
    console.log('🎯 表格HTML内容:', htmlContent);
    
    const tableNode = {
      id: `node_${nodeCounter++}`,
      topic: '', // 清空topic，使用dangerouslySetInnerHTML
      dangerouslySetInnerHTML: htmlContent, // 使用dangerouslySetInnerHTML来正确处理HTML内容
      children: [],
      level: (parentNode.level || 0) + 1,
      data: {},
    };
    
    parentNode.children.push(tableNode);
    return { nodeCounter };
  }
  
  const lines = content.split('\n');
  let currentNodeCounter = nodeCounter;
  let remainingContent = [];
  
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    const trimmed = line.trim();
    
    // 检测是否是【】标记的叶节点
    const leafMatch = trimmed.match(/^[-*+]\s*【(.+)】/);
    if (leafMatch) {
      // 创建叶节点
      const leafTitle = leafMatch[1].trim();
      const leafNode = {
        id: `node_${currentNodeCounter++}`,
        topic: leafTitle,
        children: [],
        level: (parentNode.level || 0) + 1,
        data: {},
      };
      
      // 收集这个叶节点的所有子项内容
      let leafContent = [];
      let j = i + 1;
      while (j < lines.length) {
        const nextLine = lines[j].trim();
        const nextLeafMatch = nextLine.match(/^[-*+]\s*【(.+)】/);
        
        if (nextLeafMatch) {
          // 遇到下一个【】标记，停止收集
          break;
        }
        
        // 收集子项内容
        const listMatch = nextLine.match(/^[-*+]\s+(.+)$/);
        if (listMatch) {
          const listItem = listMatch[1].trim();
          const cleanListItem = formatMarkdownToText(listItem);
          leafContent.push('• ' + cleanListItem);
        }
        
        j++;
      }
      
      // 如果有子项内容，添加到叶节点
      if (leafContent.length > 0) {
        const formattedContent = formatMarkdownToText(leafContent.join('\n'));
        leafNode.topic = leafNode.topic + '\n\n' + formattedContent;
      }
      
      parentNode.children.push(leafNode);
      
      // 跳过已处理的行
      i = j - 1;
    } else if (trimmed) {
      // 普通内容，累积到剩余内容中
      remainingContent.push(trimmed);
    }
  }
  
  // 如果有剩余内容，智能处理（保持表格完整性）
  if (remainingContent.length > 0) {
    const finalContent = remainingContent.join('\n').trim();
    if (finalContent) {
      // 检查是否包含表格内容
      if (hasTableContent(finalContent)) {
        console.log('🎯 检测到表格内容，创建表格节点');
        // 将markdown表格转换为HTML格式
        const htmlContent = renderMarkdownToHTML(finalContent);
        console.log('🎯 表格HTML内容:', htmlContent);
        
        const tableNode = {
          id: `node_${currentNodeCounter++}`,
          topic: '', // 清空topic，使用dangerouslySetInnerHTML
          dangerouslySetInnerHTML: htmlContent, // 使用dangerouslySetInnerHTML来正确处理HTML内容
          children: [],
          level: (parentNode.level || 0) + 1,
          data: {},
        };
        
        parentNode.children.push(tableNode);
      } else {
        // 如果不是表格，按换行符切分内容
        const paragraphs = finalContent.split('\n\n').filter(p => p.trim());
        
        paragraphs.forEach(paragraph => {
          const cleanParagraph = formatMarkdownToText(paragraph.trim());
          if (cleanParagraph) {
            const paragraphNode = {
              id: `node_${currentNodeCounter++}`,
              topic: cleanParagraph,
              children: [],
              level: (parentNode.level || 0) + 1,
              data: {},
            };
            
            parentNode.children.push(paragraphNode);
          }
        });
      }
    }
  }
  
  return { nodeCounter: currentNodeCounter };
};


// 检测内容是否包含表格
const hasTableContent = (content) => {
  if (!content || typeof content !== 'string') {
    return false;
  }
  
  // 首先检查是否包含HTML表格标签
  const hasHtmlTable = content.includes('<table') || content.includes('<tr') || content.includes('<td');
  if (hasHtmlTable) {
    console.log('🔍 检测到HTML表格内容');
    return true;
  }
  
  // 然后检查Markdown表格格式
  // 只对包含|字符的内容进行详细检查
  if (content.includes('|')) {
    console.log('🔍 检查Markdown表格内容:', content.substring(0, 200) + '...');
  }
  
  const lines = content.split('\n');
  let hasTableRow = false;
  let hasSeparator = false;
  
  for (const line of lines) {
    const trimmedLine = line.trim();
    
    // 检查表格行（包含|字符且至少有3个部分）
    if (trimmedLine.includes('|') && trimmedLine.split('|').length >= 3) {
      hasTableRow = true;
      console.log('✅ 找到表格行:', trimmedLine);
    }
    // 检查分隔符行（包含-和|，且主要由这些字符组成）
    if (trimmedLine.includes('|') && trimmedLine.includes('-') && /^[\s\|\-\:]+$/.test(trimmedLine)) {
      hasSeparator = true;
      console.log('✅ 找到分隔符行:', trimmedLine);
    }
  }
  
  // 如果只有表格行但没有分隔符，也可能是表格
  const pipeCount = (content.match(/\|/g) || []).length;
  const hasMultiplePipes = pipeCount >= 4; // 至少2行，每行2个|
  
  const result = (hasTableRow && hasSeparator) || (hasTableRow && hasMultiplePipes);
  console.log('🔍 表格检测结果:', { hasTableRow, hasSeparator, pipeCount, hasMultiplePipes, result });
  
  return result;
};

// 复制Markdown
const copyMarkdown = async () => {
  if (!markdownContent.value) {
    showNotification('没有Markdown内容可复制', 'error');
    return;
  }
  
  try {
    await navigator.clipboard.writeText(markdownContent.value);
    showNotification('Markdown已复制到剪贴板', 'success');
  } catch (error) {
    // 降级方案
    const textArea = document.createElement('textarea');
    textArea.value = markdownContent.value;
    document.body.appendChild(textArea);
    textArea.select();
    document.execCommand('copy');
    textArea.remove();
    showNotification('Markdown已复制到剪贴板', 'success');
  }
};

// 复制JSON
const copyJSON = async () => {
  try {
    await navigator.clipboard.writeText(convertedJSON.value);
    showNotification('JSON已复制到剪贴板', 'success');
  } catch (error) {
    console.error('复制失败:', error);
    showNotification('复制失败', 'error');
  }
};

// 导入到思维导图
const importToMindmap = () => {
  if (!convertedJSON.value) {
    showNotification('请先生成或转换JSON数据', 'error');
    return;
  }
  
  try {
    const mindmapData = JSON.parse(convertedJSON.value);
    
    // 触发事件，通知父组件导入数据
    const event = new CustomEvent('import-mindmap', {
      detail: { 
        json: convertedJSON.value,
        data: mindmapData,
        title: mindmapData.topic || '导入的思维导图'
      }
    });
    window.dispatchEvent(event);
    
    // 显示成功通知而不是alert
    // showNotification('已触发导入事件，正在处理...', 'success');
  } catch (error) {
    console.error('JSON解析失败:', error);
    showNotification('JSON格式错误，请检查数据', 'error');
  }
};

// 定义组件事件
// 删除导入功能，只保留预览和保存功能

// 预览功能（自动保存到数据库）
const previewMindmap = async () => {
  if (!convertedJSON.value) {
    showNotification('请先生成或转换JSON数据', 'error');
    return;
  }
  
  // isProcessing.value = true;
  // processingMessage.value = '正在保存思维导图...';
  
  try {
    const mindmapData = JSON.parse(convertedJSON.value);
    
    // 使用更智能的标题生成
    const title = mindmapData.topic || 
                  mindmapData.title || 
                  `AI生成的思维导图_${new Date().toLocaleString()}`;
    
    // 触发保存到数据库事件
    const event = new CustomEvent('save-preview-to-database', {
      detail: { 
        data: mindmapData, 
        title: title,
        source: 'ai-generated', // 标记来源
        timestamp: Date.now()
      }
    });
    window.dispatchEvent(event);
    
    
    // 延迟显示成功消息
    setTimeout(() => {
      // isProcessing.value = false;
      // processingMessage.value = '';
      showNotification('思维导图已保存成功！', 'success');
      
      // 注释掉自动清空功能，保留数据用于调试
      // 用户可以通过"清空"按钮手动清空数据
      // aiPrompt.value = '';
      // markdownContent.value = '';
      // convertedJSON.value = '';
      
      // 只清空文件上传，保留生成的内容
      uploadedFile.value = null;
      if (fileInput.value) {
        fileInput.value.value = '';
      }
    }, 2000);
    
  } catch (error) {
    // isProcessing.value = false;
    // processingMessage.value = '';
    console.error('JSON解析失败:', error);
    showNotification('JSON格式错误，请检查数据', 'error');
  }
};

// 显示通知的函数
const showNotification = (message, type = 'info') => {
  const notification = document.createElement('div');
  notification.className = `notification notification-${type}`;
  notification.textContent = message;
  notification.style.cssText = `
    position: fixed;
    top: 20px;
    right: 20px;
    padding: 12px 20px;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 500;
    z-index: 10000;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    animation: slideIn 0.3s ease;
    max-width: 300px;
    word-wrap: break-word;
  `;
  
  // 根据类型设置颜色
  switch (type) {
    case 'success':
      notification.style.background = '#4CAF50';
      notification.style.color = 'white';
      break;
    case 'error':
      notification.style.background = '#f44336';
      notification.style.color = 'white';
      break;
    case 'info':
    default:
      notification.style.background = '#2196F3';
      notification.style.color = 'white';
      break;
  }
  
  // 添加动画样式
  if (!document.querySelector('#notification-styles')) {
    const style = document.createElement('style');
    style.id = 'notification-styles';
    style.textContent = `
      @keyframes slideIn {
        from { transform: translateX(100%); opacity: 0; }
        to { transform: translateX(0); opacity: 1; }
      }
      @keyframes slideOut {
        from { transform: translateX(0); opacity: 1; }
        to { transform: translateX(100%); opacity: 0; }
      }
    `;
    document.head.appendChild(style);
  }
  
  document.body.appendChild(notification);
  
  // 3秒后自动移除
  setTimeout(() => {
    notification.style.animation = 'slideOut 0.3s ease';
    setTimeout(() => {
      if (notification.parentNode) {
        notification.parentNode.removeChild(notification);
      }
    }, 300);
  }, 3000);
};

// 删除不再需要的保存函数，预览功能已包含保存

// 清空内容
const clearContent = () => {
  markdownContent.value = '';
  convertedJSON.value = '';
  
  // 显示成功通知
  showNotification('内容已清空', 'info');
};

// 清空所有内容
const clearAll = () => {
  aiPrompt.value = '';
  markdownContent.value = '';
  convertedJSON.value = '';
  
  // 显示成功通知
  showNotification('所有内容已清空', 'info');
};

// 加载测试数据
const loadTestData = () => {
  const testJSON = {
    "id": "node_0",
    "topic": "数字教育平台设计要点",
    "children": [
      {
        "id": "node_1",
        "topic": "用户体验设计",
        "children": [
          {
            "id": "node_2",
            "topic": "界面交互设计",
            "children": [
              {
                "id": "node_3",
                "topic": "核心功能入口应控制在3次点击内可达",
                "children": []
              },
              {
                "id": "node_4",
                "topic": "采用响应式设计适配多端设备",
                "children": []
              }
            ]
          },
          {
            "id": "node_5",
            "topic": "内容架构规划",
            "children": [
              {
                "id": "node_6",
                "topic": "合理的内容组织帮助用户构建知识体系",
                "children": []
              },
              {
                "id": "node_7",
                "topic": "课程结构设计",
                "children": []
              }
            ]
          }
        ]
      },
      {
        "id": "node_8",
        "topic": "互动功能开发",
        "children": [
          {
            "id": "node_9",
            "topic": "学习互动设计",
            "children": [
              {
                "id": "node_10",
                "topic": "平台应提供即时反馈机制",
                "children": []
              },
              {
                "id": "node_11",
                "topic": "开发协作学习工具",
                "children": []
              }
            ]
          }
        ]
      },
      {
        "id": "node_12",
        "topic": "数据安全保障",
        "children": [
          {
            "id": "node_13",
            "topic": "隐私保护措施",
            "children": [
              {
                "id": "node_14",
                "topic": "个人信息和学习数据采用AES-256加密存储",
                "children": []
              },
              {
                "id": "node_15",
                "topic": "实施基于角色的权限管理",
                "children": []
              }
            ]
          }
        ]
      }
    ]
  };
  
  convertedJSON.value = JSON.stringify(testJSON, null, 2);
  markdownContent.value = `# 数字教育平台设计要点

## 用户体验设计

### 界面交互设计
- 核心功能入口应控制在3次点击内可达
- 采用响应式设计适配多端设备

### 内容架构规划
- 合理的内容组织帮助用户构建知识体系
- 课程结构设计

## 互动功能开发

### 学习互动设计
- 平台应提供即时反馈机制
- 开发协作学习工具

## 数据安全保障

### 隐私保护措施
- 个人信息和学习数据采用AES-256加密存储
- 实施基于角色的权限管理

## 测试Markdown语法处理

### 粗体语法测试
- **街拍**: 抓拍方式捕捉自然瞬间
- **人像**: 专业人像摄影技巧
- **风景**: 自然风光拍摄要点

### 混合语法测试
- **重要提示**: 这是*斜体*和**粗体**的混合内容
- **代码示例**: 使用\`console.log\`进行调试
- **链接测试**: [点击这里](https://example.com)查看更多信息`;
  
  // 添加到历史记录（不包含思维导图ID，使用传统方式）
  addToHistory('测试数据: 数字教育平台设计要点', markdownContent.value);
  
  // 显示成功通知
  showNotification('测试数据加载成功！', 'success');
};

// 添加到历史记录
const addToHistory = (title, content, mindmapId = null) => {
  const item = {
    title,
    content,
    mindmapId,
    timestamp: new Date()
  };
  history.value.unshift(item);
  
  // 限制历史记录数量
  if (history.value.length > 10) {
    history.value = history.value.slice(0, 10);
  }
  
  // 保存到本地存储
  localStorage.setItem('ai-sidebar-history', JSON.stringify(history.value));
};

// 加载历史记录项
const loadHistoryItem = async (item) => {
  // 如果有思维导图ID，直接调用后端接口加载
  if (item.mindmapId) {
    
    // 发送事件通知MindMap组件加载数据
    window.dispatchEvent(new CustomEvent('loadMindmapFromHistory', {
      detail: {
        mindmapId: item.mindmapId,
        title: item.title
      }
    }));
    
    // 显示加载通知
    // showNotification(`正在加载: ${item.title}`, 'info');
  } else {
    // 如果没有ID，使用传统方式加载内容
    markdownContent.value = item.content;
    
    // 自动转换为JSON
    await convertToJSON();
    
    // 发送事件通知MindMap组件加载数据
    window.dispatchEvent(new CustomEvent('loadMindmapFromHistory', {
      detail: {
        markdown: item.content,
        json: convertedJSON.value,
        title: item.title
      }
    }));
    
    // 显示加载通知
    // showNotification(`正在加载: ${item.title}`, 'info');
  }
};

// 格式化时间
const formatTime = (timestamp) => {
  const date = new Date(timestamp);
  return date.toLocaleString('zh-CN');
};

// 组件挂载时加载历史记录
import { onMounted, watch } from 'vue';

onMounted(() => {
  const savedHistory = localStorage.getItem('ai-sidebar-history');
  if (savedHistory) {
    try {
      history.value = JSON.parse(savedHistory);
    } catch (error) {
      console.error('加载历史记录失败:', error);
    }
  }
  
  // 监听添加历史记录事件
  window.addEventListener('add-to-history', (event) => {
    const { title, content, timestamp } = event.detail;
    
    // 添加历史记录
    addToHistory(title, content, null);
  });

  // 监听思维导图保存成功事件，更新历史记录
  window.addEventListener('mindmap-saved', (event) => {
    const { mindmapId, title, timestamp } = event.detail;
    
    // 查找对应的历史记录并更新思维导图ID
    const historyItem = history.value.find(item => 
      item.title === title || 
      (item.timestamp && Math.abs(item.timestamp - timestamp) < 5000) // 5秒内的记录
    );
    
    if (historyItem) {
      historyItem.mindmapId = mindmapId;
      
      // 保存到本地存储
      localStorage.setItem('ai-sidebar-history', JSON.stringify(history.value));
    } else {
      // 如果没有找到对应的记录，创建一个新的
      addToHistory(title, '', mindmapId);
    }
  });
  
  // 监听AI提示词的变化
  watch(aiPrompt, (newVal, oldVal) => {
    // AI提示词变化监听
  });
  
  // 监听Markdown内容的变化
  watch(markdownContent, (newVal, oldVal) => {
    // Markdown内容变化监听
  });
});

// 测试流式API
const testStreamAPI = async () => {
  try {
    
    const response = await fetch('http://127.0.0.1:8000/api/ai/test-stream', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        test: 'data'
      })
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      buffer += decoder.decode(value, { stream: true });
      const lines = buffer.split('\n');
      buffer = lines.pop() || '';

      for (const line of lines) {
        if (line.startsWith('data: ')) {
          try {
            const data = JSON.parse(line.slice(6));
          } catch (e) {
            console.warn('解析测试数据失败:', e);
          }
        }
      }
    }
    
  } catch (error) {
    console.error('❌ 测试流式API失败:', error);
  }
};

// 将测试函数暴露到全局，方便在控制台调用
window.testStreamAPI = testStreamAPI;
</script>

<style scoped>
.ai-sidebar-wrapper {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1000;
}

.ai-sidebar {
  position: relative;
  width: 420px;
  height: 100vh;
  background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  color: #37352f;
  transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: none;
  overflow: visible;
}

.ai-sidebar::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: 
      radial-gradient(circle at 20% 80%, rgba(102, 8, 116, 0.1) 0%, transparent 50%),
      radial-gradient(circle at 80% 20%, rgba(102, 8, 116, 0.1) 0%, transparent 50%),
      radial-gradient(circle at 40% 40%, rgba(102, 8, 116, 0.05) 0%, transparent 50%);
  pointer-events: none;
}

.sidebar-collapsed {
  transform: translateX(-420px);
}

.sidebar-toggle {
  position: fixed;
  top: 20px;
  width: 45px;
  height: 45px;
  background: #660874;
  border-radius: 0 8px 8px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 2px 0 10px rgba(0, 0, 0, 0.2), 0 0 20px rgba(102, 8, 116, 0.3);
  color: white;
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  font-weight: bold;
  z-index: 100000;
  border: 2px solid #660874;
}

.sidebar-toggle:hover {
  background: #5a0666;
  transform: scale(1.1);
  color: white;
  box-shadow: 3px 0 15px rgba(0, 0, 0, 0.15);
  border-color: #5a0666;
}

.sidebar-content {
  height: 100%;
  overflow-y: auto;
  padding: 20px;
  position: relative;
  z-index: 10;
}

.sidebar-header {
  text-align: center;
  margin-bottom: 35px;
  padding-bottom: 25px;
  border-bottom: 1px solid rgba(102, 8, 116, 0.1);
  position: relative;
  z-index: 10;
}

.sidebar-header h3 {
  margin: 0 0 15px 0;
  font-size: 28px;
  font-weight: 600;
  color: #000000;
}

.sidebar-header p {
  margin: 0;
  color: #333333;
  font-size: 16px;
}

.collapse-hint {
  margin-top: 10px;
  text-align: center;
}

.collapse-hint small {
  color: #666;
  font-size: 12px;
  opacity: 0.8;
}

.section {
  margin-bottom: 35px;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 12px;
  padding: 25px;
  backdrop-filter: blur(10px);
  border: 2px solid rgba(102, 8, 116, 0.2);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  position: relative;
  z-index: 10;
  overflow: hidden;
}

.section h4 {
  margin: 0 0 20px 0;
  font-size: 20px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 8px;
  color: #000000;
}

.input-group {
  margin-bottom: 20px;
}

.input-group label {
  display: block;
  margin-bottom: 10px;
  font-weight: 500;
  font-size: 16px;
  color: #000000;
}

.input-group textarea {
  width: 100%;
  padding: 12px;
  border: none;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.9);
  color: #333;
  font-size: 14px;
  resize: vertical;
  min-height: 80px;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
}

.input-group textarea:focus {
  outline: none;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5);
}

.button-group {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}

/* 为保存按钮组添加顶部间距 */
.save-button-group {
  margin-top: 15px;
}

.btn-primary, .btn-secondary, .btn-clear, .btn-copy, .btn-import, .btn-preview, .btn-test, .btn-save {
  padding: 12px 18px;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  gap: 6px;
}

.btn-primary {
  background: #660874;
  color: white;
}

.btn-primary:hover:not(:disabled) {
  background: #5a0666;
  transform: translateY(-2px);
}

.btn-secondary {
  background: #2196F3;
  color: white;
}

.btn-secondary:hover:not(:disabled) {
  background: #1976D2;
  transform: translateY(-2px);
}

.btn-clear {
  background: #f44336;
  color: white;
}

.btn-clear:hover {
  background: #d32f2f;
  transform: translateY(-2px);
}

.btn-copy {
  background: #FF9800;
  color: white;
}

.btn-copy:hover {
  background: #F57C00;
  transform: translateY(-2px);
}

.btn-import {
  background: #9C27B0;
  color: white;
}

.btn-import:hover {
  background: #7B1FA2;
  transform: translateY(-2px);
}

.btn-preview {
  background: #00BCD4;
  color: white;
}

.btn-preview:hover {
  background: #0097A7;
  transform: translateY(-2px);
}

.btn-test {
  background: #FF5722;
  color: white;
}

/* 文件上传样式 */
.file-upload-area {
  position: relative;
  border: 2px dashed rgba(102, 8, 116, 0.5);
  border-radius: 8px;
  padding: 20px;
  text-align: center;
  transition: all 0.3s ease;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.9);
}

.file-upload-area:hover {
  border-color: rgba(102, 8, 116, 0.5);
  background: rgba(255, 255, 255, 0.8);
}

.file-upload-area.drag-over {
  border-color: rgba(102, 8, 116, 0.8);
  background: rgba(102, 8, 116, 0.1);
  transform: scale(1.02);
}

.file-input {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.file-upload-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.upload-icon {
  font-size: 24px;
}

.upload-text {
  font-size: 16px;
  font-weight: 500;
  color: #000000;
}

.upload-hint {
  font-size: 14px;
  color: #333333;
}

.file-info {
  margin-top: 20px;
  padding: 16px;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 12px;
  border: 1px solid rgba(102, 8, 116, 0.15);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}

.file-details {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.file-info-left {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
}

.file-name {
  font-weight: 600;
  color: #37352f;
  font-size: 16px;
  line-height: 1.4;
}

.file-size {
  color: #6b7280;
  font-size: 13px;
  font-weight: 500;
}

.btn-remove {
  background: linear-gradient(135deg, #ff6b6b 0%, #ee5a52 100%);
  color: white;
  border: none;
  border-radius: 8px;
  padding: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  box-shadow: 0 2px 4px rgba(255, 107, 107, 0.3);
}

.btn-remove:hover {
  background: linear-gradient(135deg, #ff5252 0%, #d32f2f 100%);
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(255, 107, 107, 0.4);
}

.btn-remove:active {
  transform: translateY(0);
  box-shadow: 0 2px 4px rgba(255, 107, 107, 0.3);
}

/* 文件操作按钮组特殊样式 */
.file-action-buttons {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid rgba(102, 8, 116, 0.1);
}

.btn-test:hover {
  background: #E64A19;
  transform: translateY(-2px);
}

.btn-save {
  background: #660874;
  color: white;
}

.btn-save:hover {
  background: #5a0666;
  transform: translateY(-2px);
}

button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none !important;
}

.result-container {
  background: rgba(255, 255, 255, 0.8);
  border-radius: 8px;
  padding: 18px;
  margin-top: 15px;
  border: 1px solid rgba(102, 8, 116, 0.1);
}

.markdown-result {
  background: rgba(255, 255, 255, 0.95);
  border: 1px solid rgba(102, 8, 116, 0.15);
  border-radius: 8px;
  padding: 15px;
  margin: 0 0 20px 0;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 14px;
  line-height: 1.5;
  color: #333;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 300px;
  overflow-y: auto;
  resize: vertical;
}

.json-result {
  background: rgba(102, 8, 116, 0.1);
  border-radius: 6px;
  padding: 15px;
  margin: 0 0 20px 0;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 14px;
  color: #37352f;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-all;
  max-height: 200px;
  overflow-y: auto;
}

.history-list {
  max-height: 200px;
  overflow-y: auto;
  overflow-x: hidden;
}

.history-item {
  background: rgba(255, 255, 255, 0.8);
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  border: 1px solid rgba(102, 8, 116, 0.1);
  overflow: hidden;
  word-wrap: break-word;
  word-break: break-word;
}

.history-item:hover {
  background: rgba(255, 255, 255, 0.95);
  transform: translateX(5px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}

.history-title {
  font-weight: 500;
  margin-bottom: 6px;
  font-size: 16px;
  color: #37352f;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.history-time {
  font-size: 14px;
  color: #6b7280;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 处理状态样式 */
.processing-status {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 15px;
  background: rgba(102, 8, 116, 0.1);
  border: 1px solid rgba(102, 8, 116, 0.3);
  border-radius: 8px;
  margin: 20px 0;
  color: #660874;
  font-size: 16px;
}

.spinner {
  width: 20px;
  height: 20px;
  border: 2px solid #f3f3f3;
  border-top: 2px solid #660874;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

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

/* 禁用状态的按钮样式 */
.btn-preview:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  background: rgba(255, 255, 255, 0.2);
}

/* 滚动条样式 */
.sidebar-content::-webkit-scrollbar,
.json-result::-webkit-scrollbar,
.history-list::-webkit-scrollbar {
  width: 6px;
}

.sidebar-content::-webkit-scrollbar-track,
.json-result::-webkit-scrollbar-track,
.history-list::-webkit-scrollbar-track {
  background: rgba(102, 8, 116, 0.1);
  border-radius: 3px;
}

.sidebar-content::-webkit-scrollbar-thumb,
.json-result::-webkit-scrollbar-thumb,
.history-list::-webkit-scrollbar-thumb {
  background: rgba(102, 8, 116, 0.3);
  border-radius: 3px;
}

.sidebar-content::-webkit-scrollbar-thumb:hover,
.json-result::-webkit-scrollbar-thumb:hover,
.history-list::-webkit-scrollbar-thumb:hover {
  background: rgba(102, 8, 116, 0.5);
}

/* 响应式设计 */
@media (max-width: 768px) {
  .ai-sidebar {
    width: 300px;
  }
  
  .sidebar-content {
    padding: 15px;
  }
  
  .section {
    padding: 15px;
  }
  
  .button-group {
    flex-direction: column;
  }
  
  .btn-primary, .btn-secondary, .btn-clear, .btn-copy, .btn-import {
    width: 100%;
    justify-content: center;
  }
}
</style>
