// js/chatbot/chatbot-mermaid-renderer.js

/**
 * 本地 HTML 转义函数（用于错误消息防护）
 * 如果 ChatbotUtils.escapeHtml 不可用时的降级方案
 * @param {string} str - 需要转义的字符串
 * @returns {string} 转义后的安全字符串
 */
function localEscapeHtml(str) {
  if (typeof str !== 'string') return '';
  return str.replace(/[&<>"']/g, function (c) {
    return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;','\'':'&#39;'}[c];
  });
}

/**
 * 安全地转义 HTML（优先使用 ChatbotUtils，降级到本地实现）
 * @param {string} str - 需要转义的字符串
 * @returns {string} 转义后的安全字符串
 */
function safeEscapeHtml(str) {
  if (typeof window.ChatbotUtils !== 'undefined' && typeof window.ChatbotUtils.escapeHtml === 'function') {
    return window.ChatbotUtils.escapeHtml(str);
  }
  return localEscapeHtml(str);
}

/**
 * 渲染聊天内容中的所有 Mermaid 代码块。
 *
 * 主要流程：
 * 1. 查找所有 code.language-mermaid 代码块。
 * 2. 对每个代码块：
 *    - 清理和修正 Mermaid 代码（如去除 HTML 标签、<br>等）。
 *    - 创建 div.mermaid 容器，设置唯一ID。
 *    - 使用 mermaid.init 渲染 SVG。
 *    - 渲染成功则显示 SVG，并添加"放大"按钮。
 *    - 渲染失败则回退显示上一次成功的 SVG，或显示错误信息。
 *    - 支持多次尝试渲染（异步加载 mermaid.js 时）。
 * @param {HTMLElement} chatBodyElement - 聊天消息容器 DOM 元素。
 */
async function renderAllMermaidBlocksInternal(chatBodyElement) {
  if (!window.mermaidLoaded || typeof window.mermaid === 'undefined') return;
  if (!chatBodyElement) {
    console.warn('ChatbotMermaidRenderer: chatBodyElement 为空，跳过 Mermaid 渲染。');
    return;
  }

  // 按钮添加辅助函数（避免代码重复）
  const addMermaidButtons = (mermaidDiv, currentCodeForError) => {
    setTimeout(() => {
      try {
        // 查看代码按钮
        if (!mermaidDiv.querySelector('.mermaid-code-btn')) {
          const codeBtn = document.createElement('button');
          codeBtn.className = 'mermaid-action-btn mermaid-code-btn';
          codeBtn.title = '查看/隐藏代码';
          codeBtn.innerHTML = `<svg viewBox="0 0 20 20" fill="currentColor" width="18" height="18"><path d="M10 12.5a2.5 2.5 0 100-5 2.5 2.5 0 000 5z"></path><path fill-rule="evenodd" d="M.664 10.59a1.651 1.651 0 010-1.186A10.004 10.004 0 0110 3c4.257 0 7.893 2.66 9.336 6.404a1.651 1.651 0 010 1.186A10.004 10.004 0 0110 17c-4.257 0-7.893-2.66-9.336-6.404zM10 15a5 5 0 100-10 5 5 0 000 10z" clip-rule="evenodd"></path></svg>`;
          codeBtn.style.cssText = `
            position:absolute; top:12px; right:48px;
            background: transparent; color: #64748b;
            border: none; border-radius: 6px; padding: 4px;
            cursor: pointer; opacity:0.7; transition: opacity 0.2s, background-color 0.2s;
            display:flex; align-items:center; justify-content:center;
          `;
          codeBtn.onmouseover = function() { this.style.opacity = '1'; this.style.backgroundColor = 'rgba(0,0,0,0.05)'; };
          codeBtn.onmouseout = function() { this.style.opacity = '0.7'; this.style.backgroundColor = 'transparent'; };
          codeBtn.onclick = function() {
            const codeContainer = mermaidDiv.querySelector('.mermaid-original-code');
            if (codeContainer) {
              if (codeContainer.style.display === 'none') {
                codeContainer.style.display = 'block';
              } else {
                codeContainer.style.display = 'none';
              }
            } else {
              const originalCode = document.createElement('pre');
              originalCode.className = 'mermaid-original-code';
              originalCode.style.cssText = `
                position:relative;
                background:#f8f9fa;
                border:1px solid #e9ecef;
                border-radius:6px;
                padding:12px;
                margin-top:12px;
                font-family:monospace;
                font-size:13px;
                white-space:pre-wrap;
                word-break:break-all;
                max-height:300px;
                overflow-y:auto;
              `;
              originalCode.textContent = currentCodeForError;
              const copyBtn = document.createElement('button');
              copyBtn.textContent = '复制';
              copyBtn.style.cssText = `
                position:absolute;top:8px;right:8px;
                background:#e9ecef;border:none;
                border-radius:4px;padding:2px 8px;
                font-size:12px;cursor:pointer;
              `;
              copyBtn.onclick = function(e) {
                e.stopPropagation();
                navigator.clipboard.writeText(currentCodeForError)
                  .then(() => {
                    const originalText = copyBtn.textContent;
                    copyBtn.textContent = '已复制!';
                    setTimeout(() => { copyBtn.textContent = originalText; }, 2000);
                  })
                  .catch(err => {
                    console.error('复制失败:', err);
                    alert('复制失败: ' + err);
                  });
              };
              originalCode.appendChild(copyBtn);
              mermaidDiv.appendChild(originalCode);
            }
          };
          mermaidDiv.appendChild(codeBtn);
        }
        // 放大按钮（完整功能复用）
        if (!mermaidDiv.querySelector('.mermaid-zoom-btn')) {
          const zoomBtn = document.createElement('button');
          zoomBtn.className = 'mermaid-action-btn mermaid-zoom-btn';
          zoomBtn.title = '放大查看';
          zoomBtn.innerHTML = `<svg viewBox="0 0 20 20" fill="currentColor" width="18" height="18"><path fill-rule="evenodd" d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M9 5.5a.5.5 0 01.5.5v2.5h2.5a.5.5 0 010 1h-2.5v2.5a.5.5 0 01-1 0v-2.5h-2.5a.5.5 0 010-1h2.5v-2.5a.5.5 0 01.5-.5z" clip-rule="evenodd"></path></svg>`;
          zoomBtn.style.cssText = `
            position:absolute; top:12px; right:12px;
            background: transparent; color: #64748b;
            border: none; border-radius: 6px; padding: 4px;
            cursor: pointer; opacity:0.7; transition: opacity 0.2s, background-color 0.2s;
            display:flex; align-items:center; justify-content:center;
          `;
          zoomBtn.onmouseover = function() { this.style.opacity = '1'; this.style.backgroundColor = 'rgba(0,0,0,0.05)'; };
          zoomBtn.onmouseout = function() { this.style.opacity = '0.7'; this.style.backgroundColor = 'transparent'; };
          zoomBtn.onclick = function() {
            try {
              // 创建遮罩和弹窗，显示 SVG 大图
              const overlay = document.createElement('div');
              overlay.style.cssText = 'position:fixed;z-index:999999;left:0;top:0;width:100vw;height:100vh;background:rgba(0,0,0,0.6);display:flex;align-items:center;justify-content:center;padding:20px;box-sizing:border-box;';
              const popup = document.createElement('div');
              popup.style.cssText = 'background:var(--chatbot-bg, #fff);padding:24px;border-radius:12px;box-shadow:0 10px 30px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.05);width:95vw;max-width:1200px;height:90vh;overflow:auto;position:relative;display:flex;flex-direction:column;align-items:center;';
              const title = document.createElement('div');
              title.textContent = 'Mermaid 图表预览';
              title.style.cssText = 'font-weight:bold;font-size:18px;margin-bottom:18px;';
              popup.appendChild(title);
              const svgInMermaidDiv = mermaidDiv.querySelector('svg');
              if (svgInMermaidDiv) {
                const svgClone = svgInMermaidDiv.cloneNode(true);
                svgClone.style.width = '100%';
                svgClone.style.maxWidth = '100%';
                svgClone.style.height = 'auto';
                svgClone.style.flexGrow = '1';
                svgClone.style.display = 'block';
                svgClone.style.margin = '0 auto 16px auto';
                popup.appendChild(svgClone);

                // 弹窗底部操作按钮（导出PNG、SVG、代码、Mermaid.live）
                const popupActions = document.createElement('div');
                popupActions.style.cssText = 'display:flex; flex-wrap:wrap; gap:12px; justify-content:center; padding-top:16px; border-top: 1px solid rgba(0,0,0,0.08); width:100%;';

                // Helper function to create icon buttons for popup
                const createPopupActionButton = (btnTitle, svgIcon, onClickAction) => {
                  const button = document.createElement('button');
                  button.title = btnTitle;
                  button.innerHTML = svgIcon;
                  button.style.cssText = `
                    background: rgba(0,0,0,0.05); color: #334155;
                    border: none; border-radius: 8px; padding: 8px 12px;
                    cursor: pointer; transition: background-color 0.2s, color 0.2s;
                    display: flex; align-items: center; gap: 6px; font-size: 13px;
                  `;
                  button.onmouseover = function() { this.style.backgroundColor = 'rgba(0,0,0,0.1)'; };
                  button.onmouseout = function() { this.style.backgroundColor = 'rgba(0,0,0,0.05)'; };
                  button.onclick = onClickAction;
                  popupActions.appendChild(button);
                  return button;
                };

                // Icons (Heroicons - Outline)
                const iconDownload = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="18" height="18"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" /></svg>';
                const iconCode = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="18" height="18"><path stroke-linecap="round" stroke-linejoin="round" d="M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5" /></svg>';
                const iconExternalLink = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="18" height="18"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" /></svg>';
                const iconPhoto = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="18" height="18"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.158 0L10.5 9.75M16.5 12L18 10.5m-1.5 1.5l-1.5-1.5m0 0L13.5 9.75M12 12.75l1.5-1.5" /></svg>';

                // Export PNG Button (使用 html2canvas)
                const exportPngBtn = createPopupActionButton('导出PNG', iconPhoto + 'PNG', async function() {
                  try {
                    exportPngBtn.innerHTML = iconPhoto + '导出中...';
                    exportPngBtn.disabled = true;

                    // 检查 html2canvas 是否可用
                    if (typeof html2canvas === 'undefined') {
                      throw new Error('html2canvas 库未加载');
                    }

                    // 创建一个临时容器来包裹 SVG
                    const tempContainer = document.createElement('div');
                    tempContainer.style.cssText = 'position: absolute; left: -9999px; top: 0; background: white; padding: 20px;';
                    const svgForExport = svgClone.cloneNode(true);

                    // 获取 SVG 的原始尺寸
                    const svgRect = svgClone.getBoundingClientRect();
                    const originalWidth = svgRect.width || 800;
                    const originalHeight = svgRect.height || 600;

                    // 放大 SVG 以提高清晰度
                    const scaleFactor = 4; // 4倍放大
                    svgForExport.setAttribute('width', originalWidth * scaleFactor);
                    svgForExport.setAttribute('height', originalHeight * scaleFactor);
                    svgForExport.style.display = 'block';
                    svgForExport.style.width = (originalWidth * scaleFactor) + 'px';
                    svgForExport.style.height = (originalHeight * scaleFactor) + 'px';

                    tempContainer.appendChild(svgForExport);
                    document.body.appendChild(tempContainer);

                    // 使用 html2canvas 截图容器（高分辨率）
                    const canvas = await html2canvas(tempContainer, {
                      backgroundColor: '#ffffff',
                      scale: 1, // SVG 已经放大了，这里用 1 即可
                      logging: false,
                      useCORS: true,
                      allowTaint: true,
                      width: originalWidth * scaleFactor + 40, // 加上 padding
                      height: originalHeight * scaleFactor + 40
                    });

                    // 清理临时容器
                    document.body.removeChild(tempContainer);

                    // 下载 PNG
                    canvas.toBlob(function(blob) {
                      const url = URL.createObjectURL(blob);
                      const a = document.createElement('a');
                      a.href = url;
                      a.download = 'mermaid-diagram.png';
                      document.body.appendChild(a);
                      a.click();
                      document.body.removeChild(a);
                      URL.revokeObjectURL(url);

                      exportPngBtn.innerHTML = iconPhoto + '导出PNG';
                      exportPngBtn.disabled = false;
                    }, 'image/png');

                  } catch (e) {
                    console.error('PNG 导出失败:', e);
                    alert('PNG 导出失败: ' + (e.message || e) + '\n\n建议：先导出 SVG，然后使用在线工具转换。');
                    exportPngBtn.innerHTML = iconPhoto + '导出PNG';
                    exportPngBtn.disabled = false;
                  }
                });
                exportPngBtn.innerHTML = iconPhoto + '导出PNG';

                // Export SVG Button
                const exportSvgBtn = createPopupActionButton('导出SVG', iconDownload + 'SVG', function() {
                  try {
                    // 克隆 SVG 用于导出
                    const svgCloneForExport = svgClone.cloneNode(true);

                    // 复制所有计算后的样式到内联样式
                    const copyComputedStyles = (source, target) => {
                      const sourceElements = source.querySelectorAll('*');
                      const targetElements = target.querySelectorAll('*');
                      for (let i = 0; i < sourceElements.length && i < targetElements.length; i++) {
                        const computedStyle = window.getComputedStyle(sourceElements[i]);
                        const cssText = computedStyle.cssText;
                        if (cssText) {
                          targetElements[i].setAttribute('style', cssText);
                        }
                      }
                    };
                    copyComputedStyles(svgClone, svgCloneForExport);

                    const serializer = new XMLSerializer();
                    let svgString = serializer.serializeToString(svgCloneForExport);

                    // 添加 XML 声明
                    svgString = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' + svgString;

                    // 确保有正确的命名空间
                    if (!svgString.includes('xmlns="http://www.w3.org/2000/svg"')) {
                      svgString = svgString.replace(/<svg/, '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"');
                    }

                    const blob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
                    const url = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = 'mermaid-diagram.svg';
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    setTimeout(() => URL.revokeObjectURL(url), 100);
                  } catch (e) {
                    console.error('SVG 导出失败:', e);
                    alert('SVG 导出失败: ' + (e.message || e));
                  }
                });
                exportSvgBtn.innerHTML = iconDownload + '导出SVG';

                // Export Code Button
                const exportCodeBtn = createPopupActionButton('导出代码', iconCode + 'MMD', function() {
                  const blob = new Blob([currentCodeForError], {type: 'text/plain'});
                  const url = URL.createObjectURL(blob);
                  const a = document.createElement('a');
                  a.href = url;
                  a.download = 'mermaid-code.mmd';
                  document.body.appendChild(a);
                  a.click();
                  document.body.removeChild(a);
                  URL.revokeObjectURL(url);
                });
                exportCodeBtn.innerHTML = iconCode + '导出MMD';

                // Open in Mermaid.live Button
                const openLiveBtn = createPopupActionButton('在Mermaid.live中打开', iconExternalLink + 'Mermaid.live', function() {
                  const data = { code: currentCodeForError, mermaid: { theme: 'default' } };
                  const json = JSON.stringify(data);
                  const encoded = btoa(unescape(encodeURIComponent(json)));
                  const liveUrl = `https://mermaid.live/edit#${encoded}`;
                  window.open(liveUrl, '_blank');
                });
                openLiveBtn.innerHTML = iconExternalLink + 'Mermaid.live';

                popup.appendChild(popupActions);
              }

              // 关闭按钮
              const closeBtn = document.createElement('button');
              closeBtn.title = '关闭';
              closeBtn.innerHTML = `<svg viewBox="0 0 20 20" fill="currentColor" width="20" height="20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd"></path></svg>`;
              closeBtn.style.cssText = `
                position:absolute; top:16px; right:16px;
                background: transparent; color: #64748b;
                border: none; border-radius: 50%; padding: 6px;
                cursor: pointer; opacity:0.7; transition: opacity 0.2s, background-color 0.2s;
                display:flex; align-items:center; justify-content:center;
              `;
              closeBtn.onmouseover = function() { this.style.opacity = '1'; this.style.backgroundColor = 'rgba(0,0,0,0.05)';};
              closeBtn.onmouseout = function() { this.style.opacity = '0.7'; this.style.backgroundColor = 'transparent';};
              closeBtn.onclick = function() { document.body.removeChild(overlay); };
              popup.appendChild(closeBtn);
              overlay.appendChild(popup);
              document.body.appendChild(overlay);
            } catch (e) {
              alert('放大预览弹窗出错：'+(e.message||e));
            }
          };
          mermaidDiv.appendChild(zoomBtn);
        }
      } catch (btnError) {
        console.error('添加按钮时发生错误:', btnError);
      }
    }, 100);
  };

  // 查找所有 mermaid 代码块（code.language-mermaid 或 pre code.language-mermaid）
  const mermaidBlocks = chatBodyElement.querySelectorAll('code.language-mermaid, pre code.language-mermaid');

  // 使用 for...of 替代 forEach，确保顺序执行，避免竞态条件
  let blockIndex = 0;
  for (const block of mermaidBlocks) {
    const idx = blockIndex++;
    let currentCodeForError = '';

    try {
      // 检查是否已经渲染过（防止重复渲染）
      if (block.hasAttribute('data-mermaid-rendered')) {
        console.log(`Mermaid 代码块 ${idx} 已渲染，跳过`);
        continue;
      }

      // 标记为正在渲染
      block.setAttribute('data-mermaid-rendered', 'true');
      // 增强的代码清理和预处理
      let rawCode = block.textContent || '';
      if (!rawCode.trim()) {
        console.warn('ChatbotMermaidRenderer: 空的Mermaid代码块，跳过处理');
        return;
      }

      currentCodeForError = rawCode; // Assign for potential error reporting

      // 1. 将 <br> 标签替换为换行
      rawCode = rawCode.replace(/<br\s*\/?\>/gi, '\n');

      // 2. 移除所有 HTML 标签，但保留内容
      rawCode = rawCode.replace(/<[^>]+>/g, '');

      // 3. 移除零宽字符和特殊空白字符
      rawCode = rawCode.replace(/[\u200B-\u200D\uFEFF]/g, '');

      // 4. 统一换行符为 \n
      rawCode = rawCode.replace(/\r\n/g, '\n').replace(/\r/g, '\n');

      // 5. 移除多余的空行（超过2个连续换行）
      rawCode = rawCode.replace(/\n{3,}/g, '\n\n');

      // 6. 移除每行首尾空白，但保持缩进结构
      rawCode = rawCode.split('\n').map(line => line.trimEnd()).join('\n');

      // 7. **关键修正：处理节点标签内的多行文本**
      // Mermaid 不支持 [...] 内的换行符，需要将多行标签转为单行
      rawCode = rawCode.replace(/([A-Za-z0-9_]+)\[([^\]]+)\]/g, (match, nodeId, labelContent) => {
        // 将标签内的换行替换为空格
        let cleanLabel = labelContent.replace(/\n+/g, ' ');
        // 压缩多余空格
        cleanLabel = cleanLabel.replace(/\s+/g, ' ').trim();
        // **替换特殊符号为全角（避免 Mermaid 解析错误）**
        cleanLabel = cleanLabel
          .replace(/\[/g, '［')  // 方括号左
          .replace(/\]/g, '］')  // 方括号右
          .replace(/\(/g, '（')
          .replace(/\)/g, '）')
          .replace(/\|/g, '｜');
        // 限制标签长度（最多80字符）
        if (cleanLabel.length > 80) {
          cleanLabel = cleanLabel.substring(0, 77) + '...';
        }
        return `${nodeId}[${cleanLabel}]`;
      });

      // 8. 修正常见的语法错误
      // 8.1 修正箭头语法（-- > 改为 -->）
      rawCode = rawCode.replace(/--\s+>/g, '-->');
      rawCode = rawCode.replace(/<\s+--/g, '<--');

      // 8.2 修正节点定义后多余的节点名（A[text]A --> B 改为 A[text] --> B）
      // 必须在 8.3 之前执行，避免误判
      // 匹配：节点ID + [ + 内容(可能包含全角］) + ] + 重复的节点ID
      rawCode = rawCode.replace(/([A-Za-z0-9_]+)\[([^\]]*(?:］[^\]]*)*)\]\1(?=\s|$)/g, '$1[$2]');

      // 8.3 修正节点定义后缺少空格的问题（]D --> 改为 ]\nD -->）
      // 只处理半角右括号后紧跟字母的情况
      rawCode = rawCode.replace(/\]([A-Za-z0-9_]+)(\s+-->)/g, ']\n$1$2');
      rawCode = rawCode.replace(/\]([A-Za-z0-9_]+)(\s*$)/gm, ']\n$1');

      // 8.4 修复缺少箭头的节点连接
      // 修复菱形节点缺少结束花括号的情况（如 J{文本 K[...] 改为 J{文本} --> K[...]）
      rawCode = rawCode.replace(/\{([^}]*?)\s{2,}([A-Z][A-Za-z0-9_]*)\[/g, '{$1} --> $2[');
      // 修复 }  [  或 }[  的情况（菱形节点后缺少箭头）
      rawCode = rawCode.replace(/\}(\s{2,}|\s*)\[/g, '} --> [');
      // 修复 ]  [  的情况（方括号节点后缺少箭头，至少2个空格）
      rawCode = rawCode.replace(/\](\s{2,})\[/g, '] --> [');
      // 修复 )  [  的情况（圆括号节点后缺少箭头）
      rawCode = rawCode.replace(/\)(\s{2,})\[/g, ') --> [');

      // 8.5 移除空的 graph 声明
      rawCode = rawCode.replace(/^\s*graph\s*$/gim, '');

      // 9. 修正 subgraph 语法
      rawCode = rawCode.replace(/^\s*subgraph\s+([^\n]+)$/gm, (match, name) => {
        // 移除 subgraph 名称中的括号内容
        let cleanName = name.replace(/\([^\)]*\)/g, '').trim();
        // 移除逗号和句号
        cleanName = cleanName.replace(/[.,，。]/g, '');
        // 压缩多余空格
        cleanName = cleanName.replace(/\s+/g, ' ');
        return cleanName ? `subgraph ${cleanName}` : 'subgraph';
      });

      // 10. 修正 class 语句语法（移除多余的 class 关键字）
      // 例如：class A,B,C class stage1 → class A,B,C stage1
      rawCode = rawCode.replace(/^\s*class\s+([A-Za-z0-9_,\s]+)\s+class\s+([A-Za-z0-9_]+)\s*$/gm, 'class $1 $2');

      // 11. Trim 最终结果
      rawCode = rawCode.trim();
      // 选择父节点（兼容 pre > code 或单独 code）
      let parent;
      try {
        parent = block.parentElement.tagName === 'PRE' ? block.parentElement : block;
      } catch (e) {
        parent = block; // 兜底
      }
      const code = rawCode;
      currentCodeForError = code;

      // 创建 Mermaid 渲染容器
      const mermaidDiv = document.createElement('div');

      // 生成绝对唯一的 ID（使用时间戳 + 索引 + 随机数 + 性能计时器）
      const uniqueId = `mermaid-${Date.now()}-${idx}-${Math.floor(Math.random()*100000)}-${Math.floor(performance.now()*1000)}`;
      mermaidDiv.className = 'mermaid';
      mermaidDiv.id = uniqueId;
      mermaidDiv.setAttribute('data-mermaid-index', idx.toString());
      // 卡片样式
      mermaidDiv.style.background = 'var(--chatbot-bg, #fff)';
      mermaidDiv.style.borderRadius = '12px';
      mermaidDiv.style.boxShadow = '0 2px 8px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.03)';
      mermaidDiv.style.padding = '20px';
      mermaidDiv.style.position = 'relative';
      mermaidDiv.style.width = 'fit-content';
      mermaidDiv.style.maxWidth = '100%';
      mermaidDiv.style.margin = '12px auto';
      mermaidDiv.textContent = code;

      // 检查内容有效性
      const codeTrimmed = code.replace(/\s+/g, '');
      if (!codeTrimmed || /^graph(TD|LR|RL|BT|TB)?$/i.test(codeTrimmed)) {
        mermaidDiv.innerHTML = '<div style="color:#64748b;">无有效Mermaid内容</div>';
        parent.replaceWith(mermaidDiv);
        return;
      }

      // 记录上一次渲染成功的 SVG（用于回退）
      let lastSVG = null;
      if (parent.id && parent.id.startsWith('mermaid-') && parent.querySelector('svg')) {
        lastSVG = parent.querySelector('svg').cloneNode(true);
      } else if (parent.firstElementChild && parent.firstElementChild.id && parent.firstElementChild.id.startsWith('mermaid-') && parent.firstElementChild.querySelector('svg')){
        lastSVG = parent.firstElementChild.querySelector('svg').cloneNode(true);
      }

      // 用新的 mermaidDiv 替换原代码块
      parent.replaceWith(mermaidDiv);

      try {
        // 使用 mermaid.init 渲染 SVG
        await window.mermaid.init(undefined, '#' + uniqueId);
        // 渲染成功，清除错误边框
        mermaidDiv.style.border = '';
        const existingWarning = mermaidDiv.querySelector('.mermaid-render-warning');
        if (existingWarning) existingWarning.remove();

        // 添加按钮
        addMermaidButtons(mermaidDiv, currentCodeForError);
      } catch (renderError) {
        /**
         * Mermaid 渲染失败处理（增强版）：
         * 1. 自动尝试多级修正（无需 data-mermaid-final 标记）
         * 2. 若修正成功则渲染，否则继续下一个修正
         * 3. 若所有修正都失败，显示详细错误信息
         * 4. 若有上一次成功 SVG，可回退显示
         */
        console.warn('Mermaid 初次渲染失败，尝试自动修正...', renderError);

        // 增强的修正函数集合（从最保守到最激进）
        const mermaidFixers = [
          // 修正0a: 修复缺少箭头的节点连接（如 J{text}  K[text] 改为 J{text} --> K[text]）
          code => {
            // 修复菱形节点缺少结束花括号的情况
            code = code.replace(/\{([^}]*?)\s{2,}([A-Z][A-Za-z0-9_]*)\[/g, '{$1} --> $2[');
            // 修复 }  [  或 }[  的情况（菱形节点后缺少箭头）
            code = code.replace(/\}(\s{2,}|\s*)\[/g, '} --> [');
            // 修复 ]  [  的情况（方括号节点后缺少箭头）
            code = code.replace(/\](\s{2,})\[/g, '] --> [');
            // 修复 )  [  的情况（圆括号节点后缺少箭头）
            code = code.replace(/\)(\s{2,})\[/g, ') --> [');
            return code;
          },
          // 修正0b: 处理节点标签中的括号、方括号和管道符（最常见问题）
          code => {
            return code.replace(/\[([^\]]+)\]/g, (match, labelContent) => {
              let cleanLabel = labelContent
                .replace(/\[/g, '［')  // 方括号左
                .replace(/\]/g, '］')  // 方括号右
                .replace(/\(/g, '（')
                .replace(/\)/g, '）')
                .replace(/\|/g, '｜');
              return `[${cleanLabel}]`;
            });
          },
          // 修正1: 处理多行文本和长度限制
          code => {
            return code.replace(/\[([^\]]+)\]/g, (match, labelContent) => {
              let cleanLabel = labelContent.replace(/\n+/g, ' ').replace(/\s+/g, ' ').trim();
              if (cleanLabel.length > 60) {
                cleanLabel = cleanLabel.substring(0, 57) + '...';
              }
              return `[${cleanLabel}]`;
            });
          },
          // 修正2: 修正常见的引号问题
          code => {
            return code.replace(/["']/g, '');
          },
          // 修正3: 将节点标签中的斜杠替换为全角
          code => {
            return code.replace(/\[([^\]]*)\]/g, match => match.replace(/\//g, '／'));
          },
          // 修正4: 移除节点标签中的冒号和破折号
          code => {
            return code.replace(/\[([^\]]*)\]/g, match => match.replace(/[:\-]/g, ''));
          },
          // 修正5: 将所有特殊符号替换为全角或空格
          code => {
            return code.replace(/\[([^\]]*)\]/g, match => {
              return match
                .replace(/\(/g, '（')
                .replace(/\)/g, '）')
                .replace(/\|/g, '｜')
                .replace(/</g, '＜')
                .replace(/>/g, '＞')
                .replace(/\{/g, '｛')
                .replace(/\}/g, '｝');
            });
          },
          // 修正6: 极端修正 - 只保留节点内的中英文、数字和常见符号
          code => {
            return code.replace(/\[([^\]]*)\]/g, match => {
              return match.replace(/[^\u4e00-\u9fa5a-zA-Z0-9\[\]\s\.]/g, '');
            });
          },
          // 修正7: 最激进 - 简化所有节点名称为纯文本
          code => {
            return code.replace(/\[([^\]]*)\]/g, match => {
              const inner = match.slice(1, -1).trim();
              // 只保留前20个字符
              return '[' + inner.substring(0, 20).replace(/[^\u4e00-\u9fa5a-zA-Z0-9\s]/g, '') + ']';
            });
          }
        ];

        let fixSuccess = false;
        let successfulCode = null;

        for (let i = 0; i < mermaidFixers.length && !fixSuccess; i++) {
          try {
            const fixedCode = mermaidFixers[i](code);
            if (fixedCode === code) continue; // 跳过没有改变的修正

            // 重新设置 mermaid div 内容
            mermaidDiv.textContent = fixedCode;
            await window.mermaid.init(undefined, '#' + uniqueId);

            // 验证 SVG 是否真正生成
            const svgElement = mermaidDiv.querySelector('svg');
            if (!svgElement) {
              console.warn(`修正器 ${i + 1} 执行完成但未生成 SVG`);
              continue; // 未生成 SVG，尝试下一个修正器
            }

            // 修正成功！
            fixSuccess = true;
            successfulCode = fixedCode;
            console.log(`Mermaid 修正成功 (修正器 ${i + 1})`, fixedCode);

            // 清除错误边框
            mermaidDiv.style.border = '';

            // 显示警告提示
            const warningDiv = document.createElement('div');
            warningDiv.className = 'mermaid-auto-fix-warning';
            warningDiv.style.cssText = `
              color: #d97706;
              font-size: 12px;
              background: #fef3c7;
              border: 1px solid #fcd34d;
              border-radius: 6px;
              padding: 8px 12px;
              margin-top: 12px;
              text-align: center;
            `;
            warningDiv.innerHTML = `
              <strong>⚠️ 已自动修正语法</strong><br>
              原始代码存在语法问题，已应用修正器 ${i + 1} 进行渲染
            `;
            mermaidDiv.appendChild(warningDiv);

            // 更新 currentCodeForError 为修正后的代码
            currentCodeForError = fixedCode;

            // 添加按钮
            addMermaidButtons(mermaidDiv, currentCodeForError);

            break;
          } catch (e) {
            // 这个修正器失败了，继续尝试下一个
            console.warn(`修正器 ${i + 1} 失败:`, e);
          }
        }

        // 如果所有修正都失败
        if (!fixSuccess) {
          // XSS 防护：安全地转义错误消息和代码
          const escapedErrorMessage = safeEscapeHtml(renderError.str || renderError.message);
          const escapedCode = safeEscapeHtml(currentCodeForError);

          if (lastSVG) {
            // 回退到上一次成功的 SVG
            mermaidDiv.innerHTML = '';
            mermaidDiv.appendChild(lastSVG);
            mermaidDiv.style.border = '2px dashed #f59e0b';
            let warn = mermaidDiv.querySelector('.mermaid-render-warning');
            if (!warn) {
              warn = document.createElement('div');
              warn.className = 'mermaid-render-warning';
              warn.style.cssText = 'color:#d97706;font-size:12px;margin-top:4px;text-align:center;';
              mermaidDiv.appendChild(warn);
            }
            warn.textContent = '⚠️ 当前代码解析失败，显示上一版本。错误: ' + escapedErrorMessage;
          } else {
            // 显示详细错误信息
            mermaidDiv.innerHTML = `
              <div style="color:#e53e3e;font-weight:bold;margin-bottom:8px;">
                ❌ Mermaid 渲染失败
              </div>
              <div style="color:#64748b;font-size:13px;margin-bottom:8px;">
                错误信息: ${escapedErrorMessage}
              </div>
              <details style="margin-top:8px;">
                <summary style="cursor:pointer;color:#6366f1;font-size:13px;font-weight:500;">
                  查看原始代码
                </summary>
                <pre style="color:#64748b;font-size:12px;background:#f3f4f6;border-radius:6px;padding:8px 12px;overflow-x:auto;margin-top:8px;white-space:pre-wrap;word-break:break-all;">${escapedCode}</pre>
              </details>
              <div style="margin-top:12px;font-size:12px;color:#64748b;">
                💡 提示: 可尝试在 <a href="https://mermaid.live" target="_blank" style="color:#6366f1;text-decoration:underline;">Mermaid.live</a> 中调试代码
              </div>
            `;
            mermaidDiv.style.border = '2px solid #e53e3e';
          }
        }
      }
    } catch (generalBlockError) {
      // 兜底：处理 block 解析或 DOM 操作异常
      // XSS 防护：安全地转义错误消息
      const escapedGeneralErrorMessage = safeEscapeHtml(generalBlockError.message);
      console.error('处理Mermaid block时发生一般错误:', generalBlockError, block);
      let errorDisplayDiv = block.parentElement || document.createElement('div');
      if (block.parentElement) {
         let tempDiv = document.createElement('div');
         tempDiv.innerHTML = '<div style="color:#e53e3e;">Mermaid block处理异常: ' + escapedGeneralErrorMessage + '</div>';
         block.replaceWith(tempDiv);
      } else {
        block.innerHTML = '<div style="color:#e53e3e;">Mermaid block处理异常: ' + escapedGeneralErrorMessage + '</div>';
      }
    }
  } // 结束 for...of 循环
}

// 挂载到全局命名空间
if (typeof window.ChatbotRenderingUtils === 'undefined') {
  window.ChatbotRenderingUtils = {};
}
window.ChatbotRenderingUtils.renderAllMermaidBlocks = renderAllMermaidBlocksInternal;