<template>
  <div class="stream-test-container">
    <div class="test-form">
      <div class="input-group">
        <label for="message">消息内容：</label>
        <textarea 
          id="message"
          v-model="message" 
          placeholder="请输入要发送的消息...（按空格键发送）"
          rows="3"
          @keydown="handleKeyDown"
        ></textarea>
      </div>
      
      <div class="input-group">
        <label for="model">模型（可选）：</label>
        <input 
          id="model"
          v-model="model" 
          placeholder="模型名称，留空使用默认"
          type="text"
        />
      </div>
      
      <div class="button-group">
        <button 
          @click="startStream" 
          :disabled="isStreaming || !message.trim()"
          class="start-btn"
        >
          {{ isStreaming ? '发送中...' : '开始流式+数据库测试' }}
        </button>
        <button 
          @click="stopStream" 
          :disabled="!isStreaming"
          class="stop-btn"
        >
          停止
        </button>
        <button 
          @click="clearResponse" 
          class="clear-btn"
        >
          清空响应
        </button>
      </div>
    </div>
    
    <div class="response-section">
      <div class="response-header">
        <h3>流式+数据库响应：</h3>
        <div class="status-indicator" :class="{ active: isStreaming }">
          {{ isStreaming ? '连接中...' : '已断开' }}
        </div>
      </div>
      
      <div class="response-content" ref="responseContainer">
        <div v-if="!responseContent && !isStreaming" class="empty-state">
          暂无响应内容
        </div>
        <div v-else class="stream-content">
          <!-- 预览模式 -->
          <div class="formatted-content vditor-reset" v-html="formattedHtml"></div>
          
          <div v-if="isStreaming" class="typing-indicator">
            <span class="dot"></span>
            <span class="dot"></span>
            <span class="dot"></span>
          </div>
        </div>
      </div>
      
      <div v-if="dbInfo" class="db-info">
        <strong>数据库信息：</strong>
        <div>对话ID: {{ dbInfo.ai_conversation_id }}</div>
        <div>消息ID: {{ dbInfo.ai_message_id }}</div>
      </div>
      
      <div v-if="errorMessage" class="error-message">
        <strong>错误：</strong>{{ errorMessage }}
      </div>
    </div>
  </div>
</template>

<script>
import request from '../request/axios.js'
import { apis } from '../request/apis.js'
import Vditor from 'vditor'
import 'vditor/dist/index.css'

export default {
  name: 'LiuShiTest',
  data() {
    return {
      message: '',
      model: '',
      isStreaming: false,
      responseContent: '',
      responseChunks: [],
      errorMessage: '',
      eventSource: null,
      buffer: '',
      formattedHtml: '',
      dbInfo: null
    }
  },
  watch: {
    responseContent: {
      handler(newContent) {
        if (newContent) {
          this.renderWithVditor(newContent)
        } else {
          this.formattedHtml = ''
        }
      },
      immediate: true
    }
  },
  methods: {
    // 开始流式请求
    async startStream() {
      if (!this.message.trim()) {
        this.errorMessage = '请输入消息内容'
        return
      }
      
      this.isStreaming = true
      this.responseContent = ''
      this.responseChunks = []
      this.errorMessage = ''
      
      try {
        // 使用流式+数据库集成接口
        const response = await fetch('http://127.0.0.1:22000/apiv1/stream/chat-with-db', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            message: this.message,
            user_id: 598,
            ai_conversation_id: 0, // 0表示新建对话
            business_type: 0,
            exam_name: '流式测试',
            ai_message_id: 0
          })
        })
        
        if (!response.ok) {
          throw new Error(`HTTP错误: ${response.status}`)
        }
        
        // 使用ReadableStream处理流式响应
        const reader = response.body.getReader()
        const decoder = new TextDecoder('utf-8')
        
        while (true) {
          const { done, value } = await reader.read()
          
          if (done) {
            break
          }
          
          const chunk = decoder.decode(value, { stream: true })
          this.processStreamChunk(chunk)
        }
        
      } catch (error) {
        console.error('流式请求错误:', error)
        this.errorMessage = `请求失败: ${error.message}`
      } finally {
        this.isStreaming = false
      }
    },
    
    processStreamChunk(chunk) {
      // 调试：打印原始数据块
      console.log('原始数据块:', chunk)
      
      // 使用缓冲区处理跨chunk的数据
      if (!this.buffer) {
        this.buffer = ''
      }
      
      this.buffer += chunk
      
      // 处理完整的数据行（按换行符分割）
      const lines = this.buffer.split('\n')
      this.buffer = lines.pop() || '' // 保留最后一个不完整的行
      
        for (const line of lines) {
          if (line.trim() === '') continue
          
          console.log('收到数据行:', line)
          
          if (line.startsWith('data: ')) {
            const data = line.substring(6)
            
            if (data === '[DONE]') {
              console.log('收到结束信号 [DONE]')
              this.handleStreamEnd()
              return
            }
            
            try {
              // 尝试解析JSON数据
              const parsed = JSON.parse(data)
              
              // 处理初始响应（包含数据库ID）
              if (parsed.type === 'initial') {
                console.log('收到初始响应:', parsed)
                console.log('对话ID:', parsed.ai_conversation_id)
                console.log('消息ID:', parsed.ai_message_id)
                // 保存数据库信息到界面
                this.dbInfo = {
                  ai_conversation_id: parsed.ai_conversation_id,
                  ai_message_id: parsed.ai_message_id
                }
                continue
              }
              
              if (parsed.error) {
                this.errorMessage = parsed.error
                return
              }
              
              // 处理流式响应数据
              if (parsed.choices && parsed.choices.length > 0) {
                const choice = parsed.choices[0]
                console.log('解析的choice:', choice)
                if (choice.delta && choice.delta.content) {
                  console.log('添加内容:', choice.delta.content)
                  this.responseChunks.push(choice.delta.content)
                  this.responseContent += choice.delta.content
                }
                
                // 检查是否完成
                if (choice.finish_reason) {
                  console.log('收到完成信号:', choice.finish_reason)
                  this.handleStreamEnd()
                  break
                }
              } else {
                // JSON解析成功但没有choices，可能是纯数字或其他简单JSON值
                console.log('JSON解析成功但无choices，数据:', parsed)
                console.log('将作为文本内容处理:', String(parsed))
                
                // 将解析结果转换为字符串并添加
                const textContent = String(parsed)
                this.responseChunks.push(textContent)
                this.responseContent += textContent
              }
            } catch (e) {
              // 如果不是JSON格式，直接作为文本内容处理
              console.log('收到文本内容:', data)
              console.log('JSON解析失败，原因:', e.message)
              
              // 处理转义的换行符，将\n转换回真正的换行符
              const processedData = data.replace(/\\n/g, '\n')
              
              this.responseChunks.push(processedData)
              this.responseContent += processedData
            }
          }
        }
    },
    
    // 处理流式结束
    handleStreamEnd() {
      // 强制最终渲染，确保所有内容都被正确解析
      this.renderWithVditor(this.responseContent)
      console.log('流式响应结束，执行最终渲染')
    },

    renderWithVditor(content) {
      try {
        console.log('开始使用Vditor渲染，内容长度:', content.length)
        console.log('原始内容:', content)
        
        // 创建一个临时的DOM元素
        const tempDiv = document.createElement('div')
        tempDiv.style.display = 'none'
        document.body.appendChild(tempDiv)
        
        // 使用Vditor.preview方法渲染 - 简化配置
        Vditor.preview(tempDiv, content, {
          mode: 'light',
          markdown: {
            toc: false,
            mark: false,
            footnotes: false,
            autoSpace: false,
            fixTermTypo: false,
            chinesePunct: false,
            linkBase: '',
            linkPrefix: '',
            listStyle: false,
            paragraphBeginningSpace: false
          },
          theme: {
            current: 'light',
            path: 'https://cdn.jsdelivr.net/npm/vditor@3.10.9/dist/css/content-theme'
          },
          after: () => {
            // 获取Vditor渲染的结果并进行规范引用处理
            let html = tempDiv.innerHTML
            
            // 处理规范引用 - 将中括号内容转换为可点击的规范引用
            html = this.processStandardReferences(html)
            
            this.formattedHtml = html
            console.log('Vditor渲染完成，HTML长度:', this.formattedHtml.length)
            console.log('HTML预览:', this.formattedHtml.substring(0, 200) + '...')
            
            // 清理临时元素
            document.body.removeChild(tempDiv)
            
            // 等待DOM更新后绑定点击事件
            this.$nextTick(() => {
              this.bindStandardReferenceEvents()
            })
          }
        })
        
      } catch (error) {
        console.error('Vditor渲染错误:', error)
        // 渲染失败时使用简单HTML转换
        this.formattedHtml = content.replace(/\n/g, '<br>')
      }
    },
    
    // 处理规范引用 - 将中括号内容转换为可点击的规范引用
    processStandardReferences(html) {
      if (!html) return html
      
      console.log('开始处理规范引用，HTML长度:', html.length)
      
      // 处理中括号为可点击的标准引用/普通引用
      const processedHtml = html.replace(/\[([^\[\]]+)\]/g, (match, content) => {
        console.log('发现规范引用:', content)
        
        // 检查是否已经是处理过的规范引用
        if (/^<span\s+class="standard-reference"/i.test(content)) {
          return match
        }
        
        // 检查是否是标准格式：书名号+内容+括号+编号
        const standardMatch = content.match(/^([《「『【]?[\s\S]*?[》」』】]?)[\s]*\(([^)]+)\)$/)
        if (standardMatch) {
          const standardName = standardMatch[1]
          const standardNumber = standardMatch[2]
          console.log('标准格式规范:', { standardName, standardNumber })
          return `<span class="standard-reference" data-standard="${content}" data-name="${standardName}" data-number="${standardNumber}" title="点击查看标准详情" style="background-color: #EAEAEE; color: #616161; font-size: 0.75rem; padding: 3px 8px; border-radius: 6px; cursor: pointer; display: inline-block; margin: 4px 2px; border: 1px solid #EAEAEE; font-weight: 500; transition: all 0.2s ease; line-height: 1.4;">${content}</span>`
        }
        
        // 普通引用格式
        console.log('普通格式规范:', content)
        return `<span class="standard-reference" data-reference="${content}" title="点击查看详情" style="background-color: #EAEAEE; color: #616161; font-size: 0.75rem; padding: 3px 8px; border-radius: 6px; cursor: pointer; display: inline-block; margin: 4px 2px; border: 1px solid #EAEAEE; font-weight: 500; transition: all 0.2s ease; line-height: 1.4;">${content}</span>`
      })
      
      console.log('规范引用处理完成')
      return processedHtml
    },
    
    // 绑定规范引用点击事件
    bindStandardReferenceEvents() {
      const references = document.querySelectorAll('.standard-reference')
      console.log('找到规范引用元素数量:', references.length)
      
      references.forEach((ref, index) => {
        // 移除之前的事件监听器
        ref.removeEventListener('click', this.handleStandardReferenceClick)
        
        // 添加新的点击事件监听器
        ref.addEventListener('click', this.handleStandardReferenceClick)
        
        console.log(`绑定规范引用 ${index + 1}:`, ref.textContent)
      })
    },
    
    // 处理规范引用点击事件
    async handleStandardReferenceClick(event) {
      event.preventDefault()
      event.stopPropagation()
      
      const element = event.currentTarget
      const content = element.textContent
      const standardName = element.getAttribute('data-name')
      const standardNumber = element.getAttribute('data-number')
      const standardData = element.getAttribute('data-standard')
      const referenceData = element.getAttribute('data-reference')
      
      console.log('点击规范引用:', {
        content,
        standardName,
        standardNumber,
        standardData,
        referenceData
      })
      
      // 确定要查询的文件名
      let fileName = ''
      if (standardData) {
        fileName = standardData
      } else if (referenceData) {
        fileName = referenceData
      }
      
      if (fileName) {
        try {
          console.log('正在获取文件链接，文件名:', fileName)
          
          // 调用后端接口获取文件链接
          const response = await apis.getFileLink({ fileName })
          console.log('获取文件链接响应:', response)
          
          if (response.statusCode === 200 && response.data) {
            const fileLink = response.data
            console.log('获取到文件链接:', fileLink)
            
            // 如果有文件链接，打开预览
            if (fileLink) {
              // 在新窗口中打开文件链接
              window.open(fileLink, '_blank')
              console.log('文件已在新窗口中打开')
            } else {
              console.log('暂无文件')
              alert('暂无文件')
            }
          } else {
            console.log('暂无文件')
            alert('暂无文件')
          }
        } catch (error) {
          console.error('获取文件链接失败:', error)
          alert('获取文件失败，请稍后重试')
        }
      }
    },
    
    // 停止流式请求
    stopStream() {
      this.isStreaming = false
      if (this.eventSource) {
        this.eventSource.close()
        this.eventSource = null
      }
    },
    
    // 清空响应
    clearResponse() {
      this.responseContent = ''
      this.responseChunks = []
      this.formattedHtml = ''
      this.errorMessage = ''
      this.dbInfo = null
    },
    
    // 处理键盘事件
    handleKeyDown(event) {
      // 空格键发送
      if (event.code === 'Space' && !event.shiftKey && !event.ctrlKey && !event.altKey) {
        // 阻止默认的空格输入行为
        event.preventDefault()
        
        // 检查是否可以发送
        if (!this.isStreaming && this.message.trim()) {
          this.startStream()
        }
      }
    }
  },
  
  async mounted() {
    // 组件挂载后初始化
    await this.$nextTick()
  },
  
  beforeUnmount() {
    // 清理资源
    if (this.eventSource) {
      this.eventSource.close()
      this.eventSource = null
    }
  }
}
</script>

<style scoped>
.stream-test-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  font-family: Arial, sans-serif;
}

.test-form {
  background: #f8f9fa;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
}

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

.input-group label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
  color: #333;
}

.input-group textarea,
.input-group input {
  width: 100%;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
  box-sizing: border-box;
}

.input-group textarea {
  resize: vertical;
  min-height: 80px;
}

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

.button-group button {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: background-color 0.3s;
}

.start-btn {
  background: #007bff;
  color: white;
}

.start-btn:hover:not(:disabled) {
  background: #0056b3;
}

.start-btn:disabled {
  background: #6c757d;
  cursor: not-allowed;
}

.stop-btn {
  background: #dc3545;
  color: white;
}

.stop-btn:hover:not(:disabled) {
  background: #c82333;
}

.stop-btn:disabled {
  background: #6c757d;
  cursor: not-allowed;
}

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

.clear-btn:hover {
  background: #545b62;
}

.response-section {
  background: white;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

.response-header {
  background: #f8f9fa;
  padding: 15px 20px;
  border-bottom: 1px solid #ddd;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.response-header h3 {
  margin: 0;
  color: #333;
}

.status-indicator {
  padding: 5px 10px;
  border-radius: 4px;
  font-size: 12px;
  background: #6c757d;
  color: white;
}

.status-indicator.active {
  background: #28a745;
}

.response-content {
  padding: 20px;
  min-height: 200px;
  max-height: 600px;
  overflow-y: auto;
}

.empty-state {
  text-align: center;
  color: #6c757d;
  font-style: italic;
}

.stream-content {
  line-height: 1.6;
}

.formatted-content {
  margin-bottom: 20px;
}

.typing-indicator {
  display: flex;
  align-items: center;
  gap: 4px;
  color: #6c757d;
  font-style: italic;
}

.dot {
  width: 6px;
  height: 6px;
  background: #6c757d;
  border-radius: 50%;
  animation: typing 1.4s infinite ease-in-out;
}

.dot:nth-child(2) {
  animation-delay: 0.2s;
}

.dot:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes typing {
  0%, 60%, 100% {
    transform: translateY(0);
    opacity: 0.5;
  }
  30% {
    transform: translateY(-8px);
    opacity: 1;
  }
}

.db-info {
  background: #d1ecf1;
  color: #0c5460;
  padding: 10px;
  border-radius: 4px;
  margin-top: 10px;
  border: 1px solid #bee5eb;
}

.db-info div {
  margin: 2px 0;
}

.error-message {
  background: #f8d7da;
  color: #721c24;
  padding: 10px;
  border-radius: 4px;
  margin-top: 10px;
  border: 1px solid #f5c6cb;
}

/* 规范引用样式 */
:deep(.standard-reference) {
  background-color: #EAEAEE !important;
  color: #616161 !important;
  font-size: 0.75rem !important;
  padding: 3px 8px !important;
  border-radius: 6px !important;
  cursor: pointer !important;
  display: inline-block !important;
  margin: 4px 2px !important;
  border: 1px solid #EAEAEE !important;
  font-weight: 500 !important;
  transition: all 0.2s ease !important;
  line-height: 1.4 !important;
}

:deep(.standard-reference:hover) {
  background-color: #d1d5db !important;
  border-color: #d1d5db !important;
}
</style>