<template>
  <div class="chat-container">
    <div class="chat-messages" ref="messageBox">
      <div v-for="(message, index) in chatHistory" 
           :key="index" 
           :class="['message', message.type]">
        <div class="message-content">
          <div v-if="isLoading && message === currentStreamingMessage && message.type === 'ai'"  class="message-loading">
            <i class="el-icon-loading"></i>
          </div>
          <div v-if="message.type === 'ai'" class="message-actions">
            <template v-if="message === currentStreamingMessage">
              <el-button  
                  type="text"
                    @click="stopGeneration" 
                    title="停止生成">
                停止生成
              </el-button>
            </template>
            <template v-else>
              <el-button type="text" @click="copyMessage(message.content)" title="复制">
                <i class="el-icon-document-copy"></i>
              </el-button>
              <el-button type="text"
                      @click="regenerateResponse(index)" 
                      title="重新生成"
                      :disabled="isLoading">
                <i class="el-icon-refresh"></i>
              </el-button>
            </template>
            
          </div>
          <!-- <div class="content-text">{{ message.isTyping ? message.displayContent : message.content }}</div> -->
          <!-- <div class="content-text markdown-body" 
               v-html="message.isTyping ? 
                      renderMarkdown(message.displayContent) : 
                      renderMarkdown(message.content)">
                      
          </div> -->
          <!-- <div class="content-text markdown-body" 
               v-html="message.isTyping ? 
                      renderContent(message.displayContent) : 
                      renderContent(message.content)">
          </div> -->
          <div class="content-text markdown-body">
            <template v-for="(block, blockIndex) in parseMessage(
              message.isTyping ? message.displayContent : message.content
            )" >
              <code-block :key="blockIndex" v-if="block.type === 'code'"
                         :language="block.language"
                         :code="block.content" />
              <div :key="blockIndex" v-else v-html="renderMarkdown(block.content)"></div>
            </template>
          </div>
          <div class="message-time">{{ message.timestamp }}</div>
        </div>
      </div>
    </div>
    
    <div class="input-area">
      <!-- <div class="typing-status" v-if="isLoading">AI正在思考中...</div> -->
      <select v-model="selectedQuestion" class="preset-questions">
        <option value="">选择预设问题...</option>
        <option v-for="(q, index) in presetQuestions" 
                :key="index" 
                :value="q.question">
          {{ q.question }}
        </option>
      </select>
      
      <div class="input-group">
        <input type="text" 
               v-model="userInput" 
               @keyup.enter="sendMessage"
               placeholder="输入您的问题...">
        <button @click="sendMessage" :disabled="isLoading">发送</button>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios'
import MarkdownIt from 'markdown-it'
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css'; // 或其他主题样式
import 'github-markdown-css/github-markdown.css';
import DOMPurify from 'dompurify'; // 用

import CodeBlock from './CodeBlock.vue';

import { h, render } from 'vue';

export default {
  name: 'AIChatBox',
  components: {
    CodeBlock
  },
  data() {
    return {
      userInput: '',
      selectedQuestion: '',
      chatHistory: [],
      presetQuestions: [
        {
          question: "你好，请问你是谁？",
        },
        {
          question: "现在几点了？",
        },
        {
          question: "你能做什么？",
        },
        {
          question: "今天天气怎么样？",
        }
      ],
      isLoading: false,
      currentStreamingMessage: null,
      controller: null, // 用于中止请求
      typingSpeed: 20, // 打字机效果的速度（毫秒）
      scrollLock:true,
      md: null,
    }
  },
  
  created() {
    // 从 localStorage 加载历史记录
    const savedHistory = localStorage.getItem('chatHistory')
    if (savedHistory) {
      this.chatHistory = JSON.parse(savedHistory)
    }

    // 初始化 markdown-it
    this.md = new MarkdownIt({
      // highlight: function(str, lang) {
      //   if (lang && hljs.getLanguage(lang)) {
      //     try {
      //       // return `<div class="code-block">
      //       //           <div class="code-block-header">
      //       //             <span class="language-label">${lang}</span>
      //       //             <button class="copy-button" onclick="copyCode(this)">复制</button>
      //       //           </div>
      //       //           <pre><code class="hljs ${lang}">${hljs.highlight(str, { language: lang }).value}</code></pre>
      //       //         </div>`;
      //       return hljs.highlight(str, { language: lang }).value;
      //     } catch (__) {}
      //   }
      //   return `<pre><code class="hljs">${this.md.utils.escapeHtml(str)}</code></pre>`;
      // },
      highlight: (str, lang) => {
        // 返回一个占位符，后续会被替换为组件
        return `<code-block language="${lang}" code="${this.escapeHtml(str)}"></code-block>`;
      },
      html: true, // 允许 HTML 标签
      breaks: true,
      linkify: true,
    });

    // 添加复制功能到全局
    window.copyCode = async (button) => {
      const codeBlock = button.closest('.code-block');
      const code = codeBlock.querySelector('code').textContent;
      
      try {
        await navigator.clipboard.writeText(code);
        const originalText = button.textContent;
        button.textContent = '已复制';
        setTimeout(() => {
          button.textContent = originalText;
        }, 2000);
      } catch (err) {
        console.error('复制失败:', err);
      }
    };
  },
  
  watch: {
    chatHistory: {
      handler(newVal) {
        // 保存到 localStorage
        localStorage.setItem('chatHistory', JSON.stringify(newVal))
      },
      deep: true
    },
    selectedQuestion(val) {
      if (val) {
        this.userInput = val;
      }
    }
  },
  mounted() {
    // 添加滚动事件监听
    const messageBox = this.$refs.messageBox;
    if (messageBox) {
      messageBox.addEventListener('scroll', this.handleScroll);
    }
    
    // 初始滚动到底部
    this.scrollToBottom();
  },

  beforeDestroy() {
    // 移除滚动事件监听
    const messageBox = this.$refs.messageBox;
    if (messageBox) {
      messageBox.removeEventListener('scroll', this.handleScroll);
    }
  },

  updated() {
    // 当内容更新时滚动到底部
    this.scrollToBottom();
  },
  
  methods: {
    //发送信息
    async sendMessage() {
      if (!this.userInput.trim()) return;
      
      const userMessage = {
        type: 'user',
        content: this.userInput,
        timestamp: new Date().toLocaleTimeString()
      };
      
      this.chatHistory.push(userMessage);
      this.isLoading = true;
      
      const aiMessage = {
        type: 'ai',
        content: '',
        displayContent: '', // 用于打字机效果
        isTyping: true,
        timestamp: new Date().toLocaleTimeString()
      };
      
      this.chatHistory.push(aiMessage);
      this.currentStreamingMessage = aiMessage;
      
      try {
        await this.getAIResponse(this.userInput);
      } catch (error) {
        if (error.name === 'AbortError') {
          this.currentStreamingMessage.content += '\n[生成已停止]';
        } else {
          console.error('AI响应错误:', error);
          this.currentStreamingMessage.content = '抱歉，服务出现了问题，请稍后再试。';
        }
      } finally {
        this.isLoading = false;
        this.userInput = '';
        this.selectedQuestion = '';
        await this.finishTypingEffect(this.currentStreamingMessage);
        this.currentStreamingMessage = null;
        this.controller = null;
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      }
    },
    //获取回复信息
    async getAIResponse(message) {
      this.controller = new AbortController();
      const formatCodeBlock = (text) => {
        return text.replace(/```(\w+)?\n([\s\S]+?)```/g, (match, lang, code) => {
          return `\n\`\`\`${lang || ''}\n${code.trim()}\n\`\`\`\n`;
        });
      };
      try {
        let data = {
          messages: [
            {
              role: 'user',
              content: message
            }
          ],
          // model: 'deepseek-r1:14b',
          stream: true,
        }
        const response = await fetch('/AI/api/AI/chat', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'text/event-stream',
          },
          body: JSON.stringify(data),
          signal: this.controller.signal
        });
        console.log(response)
        if (!response.ok) throw new Error('AI API 调用失败');

        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);
          const lines = chunk
            .split('\n')
            .filter(line => line.trim() !== '' && line.trim() !== 'data: [DONE]');

          for (const line of lines) {
            try {
              const jsonStr = line.replace(/^data: /, '');
              const json = JSON.parse(jsonStr);
              
              if (json.choices[0]?.delta?.content) {
                const newContent = json.choices[0].delta.content;
                this.currentStreamingMessage.content += newContent;
                // await this.typeWriter(this.currentStreamingMessage, newContent);
                // 格式化完整的内容
                const formattedContent = formatCodeBlock(this.currentStreamingMessage.content);
                await this.typeWriter(this.currentStreamingMessage, newContent, formattedContent);
              }
            } catch (e) {
              console.error('解析响应数据出错:', e);
            }
          }
        }
      } catch (error) {
        throw error;
      }
    },
    
    async typeWriter(message, newContent,formattedContent) {
      const currentLength = message.displayContent.length;
      const targetLength = message.content.length;
      
      if (currentLength < targetLength) {
        message.displayContent = message.content.substring(0, currentLength + newContent.length);
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      }
    },

    async finishTypingEffect(message) {
      message.displayContent = message.content;
      message.isTyping = false;
    },

    //停止生成
    stopGeneration() {
      if (this.controller) {
        this.controller.abort();
      }
    },

    //重新生成
    async regenerateResponse(index) {
      const originalUserMessage = this.chatHistory[index - 1];
      if (!originalUserMessage || originalUserMessage.type !== 'user') return;
      
      // 删除当前回复
      this.chatHistory.splice(index, 1);
      
      // 重新发送请求
      const aiMessage = {
        type: 'ai',
        content: '',
        displayContent: '',
        isTyping: true,
        timestamp: new Date().toLocaleTimeString()
      };
      
      this.chatHistory.push(aiMessage);
      this.currentStreamingMessage = aiMessage;
      this.isLoading = true;
      
      try {
        await this.getAIResponse(originalUserMessage.content);
      } catch (error) {
        console.error('重新生成失败:', error);
        this.currentStreamingMessage.content = '重新生成失败，请稍后再试。';
      } finally {
        this.isLoading = false;
        await this.finishTypingEffect(this.currentStreamingMessage);
        this.currentStreamingMessage = null;
      }
    },

    //复制信息
    async copyMessage(content) {
      try {
        await navigator.clipboard.writeText(content);
        // 可以添加一个提示，表示复制成功
        this.$message?.success?.('复制成功') || alert('复制成功');
      } catch (err) {
        console.error('复制失败:', err);
        this.$message?.error?.('复制失败') || alert('复制失败');
      }
    },

    //滚动到最底端
    scrollToBottom() {
      if (!this.scrollLock) return;
      
      this.$nextTick(() => {
        const messageBox = this.$refs.messageBox;
        if (messageBox) {
          // 使用平滑滚动效果
          messageBox.scrollTo({
            top: messageBox.scrollHeight,
            behavior: 'instant'
          });
        }
      });
    },

    // 监听滚动事件
    handleScroll() {
      const messageBox = this.$refs.messageBox;
      if (!messageBox) return;

      // 计算是否在底部附近（允许 100px 的误差）
      const isNearBottom = 
        messageBox.scrollHeight - messageBox.scrollTop - messageBox.clientHeight < 100;
      
      this.scrollLock = isNearBottom;
    },

    //清空历史
    clearHistory() {
      if (confirm('确定要清空聊天记录吗？')) {
        this.chatHistory = [];
        localStorage.removeItem('chatHistory');
      }
    },

    // renderMarkdown(text) {
    //   try {
    //     text = this.preprocessCodeBlocks(text);
    //     const rendered = this.md.render(text);
    //     return DOMPurify.sanitize(rendered);
    //   } catch (e) {
    //     console.error('Markdown rendering error:', e);
    //     return text;
    //   }
    // },
    parseMessage(text) {
      const blocks = [];
      let currentText = '';
      
      // 使用正则表达式匹配代码块
      const regex = /```(\w*)\n([\s\S]+?)```/g;
      let lastIndex = 0;
      let match;
      
      while ((match = regex.exec(text)) !== null) {
        // 添加代码块之前的文本
        if (match.index > lastIndex) {
          blocks.push({
            type: 'text',
            content: text.slice(lastIndex, match.index)
          });
        }
        
        // 添加代码块
        blocks.push({
          type: 'code',
          language: match[1] || '',
          content: match[2].trim()
        });
        
        lastIndex = regex.lastIndex;
      }
      
      // 添加剩余的文本
      if (lastIndex < text.length) {
        blocks.push({
          type: 'text',
          content: text.slice(lastIndex)
        });
      }
      
      return blocks;
    },
    renderMarkdown(text) {
      // 只渲染非代码块的文本
      return this.md.render(text);
    },
    
    preprocessCodeBlocks(text) {
      // 确保代码块格式正确
      return text.replace(/```(\w*)\n([\s\S]+?)```/g, (_, lang, code) => {
        return `\n\`\`\`${lang}\n${code.trim()}\n\`\`\`\n`;
      });
    },

    escapeHtml(text) {
      return text
        .replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');
    },
  }
}
</script>

<style scoped>
.chat-container {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

.chat-messages {
  height: 400px;
  overflow-y: auto;
  padding: 20px;
  background: #f5f5f5;
  scroll-behavior: smooth; 
}

.message {
  margin-bottom: 15px;
  /* max-width: 80%; */
  position:relative;
}

.message.user {
  /* margin-left: auto; */
  display: flex;
  flex-direction: row-reverse;
}

.message-content {
  padding: 10px 15px;
  border-radius: 15px;
  display: inline-block;
  white-space: pre-wrap;
  word-break: break-word;
  position: relative;
  padding-right: 30px; /* 为按钮留出空间 */
  max-width: 80%;
}

.user .message-content {
  /* background: #007bff; */
  background: white;
  color: white;
}

.ai .message-content {
  background: white;
  color: #333;
}

.input-area {
  padding: 15px;
  background: white;
}

.input-group {
  display: flex;
  margin-top: 10px;
}

input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  margin-right: 10px;
}

/* button {
  padding: 8px 20px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background: #0056b3;
} */

.preset-questions {
  width: 100%;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.typing-status {
  padding: 8px;
  color: #666;
  font-style: italic;
}

.message-time {
  font-size: 0.8em;
  color: #999;
  margin-top: 4px;
}

/* 添加一个清空历史记录的按钮样式 */
.clear-history {
  position: absolute;
  top: 10px;
  right: 10px;
  padding: 5px 10px;
  background: #dc3545;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.message-loading{
  position: absolute;
  left: -20px;
  top: 0px;
  width: 20px;
  height: 20px;
}

.message-actions {
  position: absolute;
  /* top: 5px; */
  top: calc(100% + 5px);
  /* right: 5px; */
  display: flex;
  gap: 5px;
  opacity: 1;
  transition: opacity 0.2s;
}

.message:hover .message-actions {
  /* opacity: 1; */
}

.action-btn {
  padding: 4px 8px;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid #ddd;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
  color: #666;
  transition: all 0.2s;
}

.action-btn:hover {
  background: #f0f0f0;
  color: #333;
}

.action-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.content-text {
  white-space: pre-wrap;
  word-break: break-word;
}

/* 添加闪烁的光标效果 */
.message.ai .content-text[data-typing="true"]::after {
  content: '|';
  animation: blink 1s infinite;
}

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

/* 自定义滚动条样式 */
.chat-messages::-webkit-scrollbar {
  width: 8px;
}

.chat-messages::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 4px;
}

.chat-messages::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 4px;
}

.chat-messages::-webkit-scrollbar-thumb:hover {
  background: #555;
}


/* 导入 GitHub Markdown 样式 */
/* @import 'github-markdown-css'; */

/* 自定义 Markdown 样式 */
.markdown-body {
  font-size: 14px;
  line-height: 1.6;
}

.markdown-body pre {
  background-color: #f6f8fa;
  border-radius: 6px;
  padding: 16px;
  margin: 8px 0;
}

.markdown-body code {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
  font-size: 12px;
  padding: 2px 4px;
  background-color: rgba(27,31,35,0.05);
  border-radius: 3px;
}

.markdown-body pre code {
  padding: 0;
  background-color: transparent;
}

/* 代码块复制按钮 */
.code-block-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: #f1f1f1;
  padding: 4px 8px;
  border-radius: 6px 6px 0 0;
  font-size: 12px;
}

.copy-button {
  padding: 2px 6px;
  font-size: 12px;
  color: #666;
  background: transparent;
  border: 1px solid #ddd;
  border-radius: 3px;
  cursor: pointer;
}

.copy-button:hover {
  background: #e9e9e9;
}



/* .code-block {
  margin: 1em 0;
  border-radius: 6px;
  overflow: hidden;
  background: #f6f8fa;
}

.code-block-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 16px;
  background: #f1f1f1;
  border-bottom: 1px solid #ddd;
}

.language-label {
  font-size: 12px;
  color: #666;
  text-transform: uppercase;
}

.copy-button {
  padding: 4px 8px;
  font-size: 12px;
  color: #666;
  background: transparent;
  border: 1px solid #ddd;
  border-radius: 3px;
  cursor: pointer;
  transition: all 0.2s;
}

.copy-button:hover {
  background: #e9e9e9;
}

.code-block pre {
  margin: 0;
  padding: 16px;
}

.code-block code {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-size: 13px;
  line-height: 1.45;
}
.message .code-block {
  max-width: 100%;
  box-sizing: border-box;
} */
</style> 