// js/chatbot/utils/drawio-layout-optimizer.js

/**
 * Draw.io XML 布局优化工具
 *
 * 参考 smart-drawio-next 的优化思路，针对 draw.io XML 格式设计
 * 主要优化：
 * 0. Dagre 布局 - 使用标准 Sugiyama 算法进行层次化布局（推荐，显著减少交叉）
 * 1. 网格对齐 - 确保所有坐标对齐到网格
 * 2. 自动间距 - 避免节点重叠和拥挤，考虑连接关系智能排列
 * 3. 避免穿透 - 检测连线是否穿过节点，调整节点位置避让
 * 4. 智能连接 - 优化箭头的出入点位置，移除错误的 mxPoint 子元素
 * 5. 连线理线 - 检测交叉并通过调整节点位置减少交叉
 * 6. 样式统一 - 统一相同类型元素的样式
 *
 * @version 1.3.0 - 集成 Dagre.js 标准布局算法
 * @date 2025-01-16
 */

/**
 * 从 XML 字符串解析出 mxCell 节点
 * @param {string} xmlString - draw.io XML 字符串
 * @returns {Document} 解析后的 XML 文档对象
 */
function parseDrawioXml(xmlString) {
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(xmlString, 'text/xml');

  // 检查解析错误
  const parserError = xmlDoc.querySelector('parsererror');
  if (parserError) {
    throw new Error('XML 解析失败: ' + parserError.textContent);
  }

  return xmlDoc;
}

/**
 * 将 XML 文档序列化回字符串
 * @param {Document} xmlDoc - XML 文档对象
 * @returns {string} XML 字符串
 */
function serializeDrawioXml(xmlDoc) {
  const serializer = new XMLSerializer();
  return serializer.serializeToString(xmlDoc);
}

/**
 * 获取节点的几何信息
 * @param {Element} cell - mxCell 元素
 * @returns {Object|null} {x, y, width, height} 或 null
 */
function getCellGeometry(cell) {
  const geometry = cell.querySelector('mxGeometry');
  if (!geometry) return null;

  return {
    x: parseFloat(geometry.getAttribute('x')) || 0,
    y: parseFloat(geometry.getAttribute('y')) || 0,
    width: parseFloat(geometry.getAttribute('width')) || 100,
    height: parseFloat(geometry.getAttribute('height')) || 100
  };
}

/**
 * 设置节点的几何信息
 * @param {Element} cell - mxCell 元素
 * @param {Object} geometry - {x, y, width, height}
 */
function setCellGeometry(cell, geometry) {
  let geometryElem = cell.querySelector('mxGeometry');
  if (!geometryElem) {
    geometryElem = cell.ownerDocument.createElement('mxGeometry');
    geometryElem.setAttribute('as', 'geometry');
    cell.appendChild(geometryElem);
  }

  if (geometry.x !== undefined) geometryElem.setAttribute('x', geometry.x);
  if (geometry.y !== undefined) geometryElem.setAttribute('y', geometry.y);
  if (geometry.width !== undefined) geometryElem.setAttribute('width', geometry.width);
  if (geometry.height !== undefined) geometryElem.setAttribute('height', geometry.height);
}

/**
 * 网格对齐优化
 * 确保所有坐标都对齐到网格（默认 10px）
 *
 * @param {Document} xmlDoc - XML 文档对象
 * @param {number} gridSize - 网格大小，默认 10
 */
function optimizeGridAlignment(xmlDoc, gridSize = 10) {
  const cells = xmlDoc.querySelectorAll('mxCell[vertex="1"]');
  let optimizedCount = 0;

  cells.forEach(cell => {
    const geometry = getCellGeometry(cell);
    if (!geometry) return;

    // 对齐到网格
    const alignedX = Math.round(geometry.x / gridSize) * gridSize;
    const alignedY = Math.round(geometry.y / gridSize) * gridSize;

    if (alignedX !== geometry.x || alignedY !== geometry.y) {
      setCellGeometry(cell, {
        x: alignedX,
        y: alignedY,
        width: geometry.width,
        height: geometry.height
      });
      optimizedCount++;
    }
  });

  console.log(`[DrawioOptimizer] 网格对齐: ${optimizedCount} 个节点已优化`);
  return optimizedCount;
}

/**
 * 检测节点重叠
 * @param {Object} rect1 - {x, y, width, height}
 * @param {Object} rect2 - {x, y, width, height}
 * @param {number} minSpacing - 最小间距
 * @returns {boolean} 是否重叠或过近
 */
function isOverlapping(rect1, rect2, minSpacing = 20) {
  return !(
    rect1.x + rect1.width + minSpacing < rect2.x ||
    rect2.x + rect2.width + minSpacing < rect1.x ||
    rect1.y + rect1.height + minSpacing < rect2.y ||
    rect2.y + rect2.height + minSpacing < rect1.y
  );
}

/**
 * 使用 Dagre 算法进行层次化布局（Sugiyama 算法）
 * 这是图布局的标准算法，能显著减少连线交叉
 *
 * @param {Document} xmlDoc - XML 文档对象
 * @param {Object} options - 布局选项
 * @returns {number} 调整的节点数量
 */
function applyDagreLayout(xmlDoc, options = {}) {
  // 检查 dagre 和 graphlib 是否可用（它们是两个独立的全局变量）
  if (typeof window.dagre === 'undefined') {
    console.warn('[DrawioOptimizer] ❌ Dagre 库未加载，跳过 Dagre 布局');
    return 0;
  }
  if (typeof window.graphlib === 'undefined') {
    console.warn('[DrawioOptimizer] ❌ Graphlib 库未加载，跳过 Dagre 布局');
    return 0;
  }

  console.log('[DrawioOptimizer] 🎯 应用 Dagre 层次化布局算法 (LR 模式)...');

  const defaultOptions = {
    rankdir: 'LR',      // 方向：LR (从左到右) - 层级横向展开，同层节点纵向排列
    nodesep: 100,       // 同层节点间距（LR模式下是垂直间距）- 增加以减少交叉
    ranksep: 180,       // 不同层间距（LR模式下是水平间距）- 增加以减少交叉
    edgesep: 20,        // 边之间的间距
    ranker: 'network-simplex',  // 使用 network-simplex 算法（最佳层分配）
    marginx: 20,        // 水平边距
    marginy: 20         // 垂直边距
  };

  const opts = { ...defaultOptions, ...options };

  try {
    const allCells = Array.from(xmlDoc.querySelectorAll('mxCell[vertex="1"]'));
    const allEdges = Array.from(xmlDoc.querySelectorAll('mxCell[edge="1"]'));
    const cellMap = new Map();

    // 构建 ID -> Cell 映射
    xmlDoc.querySelectorAll('mxCell[id]').forEach(cell => {
      cellMap.set(cell.getAttribute('id'), cell);
    });

    let adjustedCount = 0;

    // 1. 识别 subgraph 容器（swimlane）和顶层节点
    const subgraphContainers = [];
    const topLevelCells = [];
    const subgraphMembers = new Set(); // 记录 subgraph 内部节点

    allCells.forEach(cell => {
      const style = cell.getAttribute('style') || '';
      const parent = cell.getAttribute('parent');

      if (style.includes('swimlane')) {
        // 这是一个 subgraph 容器
        subgraphContainers.push(cell);
      } else {
        // 检查是否是 subgraph 内部节点
        const parentCell = cellMap.get(parent);
        if (parentCell && (parentCell.getAttribute('style') || '').includes('swimlane')) {
          // 这是 subgraph 内部的节点
          subgraphMembers.add(cell.getAttribute('id'));
        } else {
          // 这是顶层节点
          topLevelCells.push(cell);
        }
      }
    });

    console.log(`[DrawioOptimizer] 📊 发现 ${subgraphContainers.length} 个子图, ${topLevelCells.length} 个顶层节点`);

    // 2. 对每个 subgraph 内部单独进行 Dagre 布局
    subgraphContainers.forEach(container => {
      const containerId = container.getAttribute('id');
      const containerGeo = getCellGeometry(container);
      if (!containerGeo) return;

      // 找出属于这个 subgraph 的所有节点
      const members = allCells.filter(cell =>
        cell.getAttribute('parent') === containerId
      );

      if (members.length === 0) return;

      console.log(`[DrawioOptimizer]   🔹 子图 "${containerId}" 内部布局 (${members.length} 个节点)...`);

      // 创建子图的 Dagre 图
      const subG = new graphlib.Graph();
      subG.setGraph({
        ...opts,
        marginx: 20,
        marginy: 30  // 顶部留空间给 swimlane 标题
      });
      subG.setDefaultEdgeLabel(() => ({}));

      // 添加成员节点
      members.forEach(cell => {
        const id = cell.getAttribute('id');
        const geo = getCellGeometry(cell);
        if (!geo) return;

        subG.setNode(id, {
          width: geo.width,
          height: geo.height,
          originalGeo: geo,
          cell: cell
        });
      });

      // 添加子图内部的边
      allEdges.forEach(edge => {
        const source = edge.getAttribute('source');
        const target = edge.getAttribute('target');
        if (source && target && subG.hasNode(source) && subG.hasNode(target)) {
          subG.setEdge(source, target);
        }
      });

      // 执行子图布局
      dagre.layout(subG);

      // 应用布局结果（相对于 subgraph 容器的坐标）
      // 先收集所有节点的原始坐标
      const nodePositions = [];
      let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;

      subG.nodes().forEach(nodeId => {
        const node = subG.node(nodeId);
        if (!node) return;

        const { cell, width, height } = node;
        const rawX = Math.round(node.x - width / 2);
        const rawY = Math.round(node.y - height / 2);

        nodePositions.push({ cell, width, height, rawX, rawY });

        minX = Math.min(minX, rawX);
        minY = Math.min(minY, rawY);
        maxX = Math.max(maxX, rawX + width);
        maxY = Math.max(maxY, rawY + height);
      });

      console.log(`[DrawioOptimizer]     📍 原始节点范围: (${minX}, ${minY}) 到 (${maxX}, ${maxY})`);

      // 计算需要的偏移量，确保节点在容器内正确位置
      // swimlane 标题高度是 30px，左边距至少 20px
      const targetMinX = 20;  // 左边距
      const targetMinY = 40;  // 标题栏30px + 顶部边距10px

      // 只在节点坐标异常时才应用偏移量
      // 如果节点已经在合理位置（正数且接近目标），保持原位
      let offsetX = 0;
      let offsetY = 0;

      // 只在节点出现负坐标或严重偏移时才修正
      if (minX < 0) {
        offsetX = targetMinX - minX;  // 修正负坐标
      } else if (minX < 10) {
        offsetX = targetMinX - minX;  // 太靠近边缘，加点边距
      }

      if (minY < 0) {
        offsetY = targetMinY - minY;  // 修正负坐标
      } else if (minY < 30) {
        offsetY = targetMinY - minY;  // 太靠近标题栏，加点边距
      }

      console.log(`[DrawioOptimizer]     📐 应用偏移量: (${offsetX}, ${offsetY}) ${offsetX === 0 && offsetY === 0 ? '(无需调整)' : ''}`);

      // 应用偏移后的坐标
      let finalMinX = Infinity, finalMinY = Infinity, finalMaxX = -Infinity, finalMaxY = -Infinity;

      nodePositions.forEach(({ cell, width, height, rawX, rawY }) => {
        const finalX = rawX + offsetX;
        const finalY = rawY + offsetY;

        finalMinX = Math.min(finalMinX, finalX);
        finalMinY = Math.min(finalMinY, finalY);
        finalMaxX = Math.max(finalMaxX, finalX + width);
        finalMaxY = Math.max(finalMaxY, finalY + height);

        setCellGeometry(cell, {
          x: finalX,
          y: finalY,
          width: width,
          height: height
        });

        adjustedCount++;
      });

      console.log(`[DrawioOptimizer]     ✅ 最终节点范围: (${finalMinX}, ${finalMinY}) 到 (${finalMaxX}, ${finalMaxY})`);

      // 调整 subgraph 容器大小以包含所有成员
      if (finalMinX !== Infinity && finalMinY !== Infinity) {
        // 容器需要的尺寸 = 节点最大范围 + 底部/右侧边距
        const requiredWidth = Math.ceil(finalMaxX + 20);   // 右侧留20px边距
        const requiredHeight = Math.ceil(finalMaxY + 20);  // 底部留20px边距

        setCellGeometry(container, {
          x: containerGeo.x,
          y: containerGeo.y,
          width: Math.max(requiredWidth, 300),   // 最小300px
          height: Math.max(requiredHeight, 200)  // 最小200px
        });

        console.log(`[DrawioOptimizer]     📏 容器调整: ${requiredWidth}x${requiredHeight}`);
      }
    });

    // 3. 对顶层节点 + subgraph 容器进行全局 Dagre 布局
    if (topLevelCells.length > 0 || subgraphContainers.length > 0) {
      console.log(`[DrawioOptimizer] 🌍 全局布局 (${topLevelCells.length + subgraphContainers.length} 个顶层元素)...`);

      const g = new graphlib.Graph();
      g.setGraph(opts);
      g.setDefaultEdgeLabel(() => ({}));

      // 添加顶层节点和 subgraph 容器
      [...topLevelCells, ...subgraphContainers].forEach(cell => {
        const id = cell.getAttribute('id');
        const geo = getCellGeometry(cell);
        if (!geo) return;

        g.setNode(id, {
          width: geo.width,
          height: geo.height,
          originalGeo: geo,
          cell: cell
        });
      });

      // 添加顶层的边（不包括 subgraph 内部的边）
      allEdges.forEach(edge => {
        const source = edge.getAttribute('source');
        const target = edge.getAttribute('target');

        // 只添加至少有一端是顶层节点的边
        if (source && target && g.hasNode(source) && g.hasNode(target)) {
          g.setEdge(source, target);
        }
      });

      // 执行全局布局
      dagre.layout(g);

      // 应用全局布局结果
      g.nodes().forEach(nodeId => {
        const node = g.node(nodeId);
        if (!node) return;

        const { cell, width, height } = node;
        const newX = Math.round(node.x - width / 2);
        const newY = Math.round(node.y - height / 2);

        const geo = getCellGeometry(cell);
        if (!geo) return;

        // 直接设置容器位置
        // 注意：subgraph 容器内的节点坐标是相对的，容器移动时会自动跟随，不需要单独调整
        setCellGeometry(cell, {
          x: newX,
          y: newY,
          width: width,
          height: height
        });

        adjustedCount++;
      });
    }

    console.log(`[DrawioOptimizer] ✅ Dagre 布局完成: ${adjustedCount} 个节点已优化`);
    return adjustedCount;

  } catch (error) {
    console.error('[DrawioOptimizer] ❌ Dagre 布局失败:', error);
    return 0;
  }
}

/**
 * 自动间距优化（增强版 - 考虑连线关系）
 * 检测并修复节点重叠问题，同时尽量减少连线交叉
 *
 * @param {Document} xmlDoc - XML 文档对象
 * @param {number} minSpacing - 最小间距，默认 30px
 */
function optimizeSpacing(xmlDoc, minSpacing = 30) {
  const cells = Array.from(xmlDoc.querySelectorAll('mxCell[vertex="1"]'));
  const geometries = cells.map(cell => ({
    cell,
    id: cell.getAttribute('id'),
    ...getCellGeometry(cell)
  })).filter(g => g.x !== undefined);

  // 构建连接关系图
  const edges = xmlDoc.querySelectorAll('mxCell[edge="1"]');
  const connections = new Map(); // nodeId -> [targetIds]

  edges.forEach(edge => {
    const sourceId = edge.getAttribute('source');
    const targetId = edge.getAttribute('target');
    if (sourceId && targetId) {
      if (!connections.has(sourceId)) {
        connections.set(sourceId, []);
      }
      connections.get(sourceId).push(targetId);
    }
  });

  let adjustedCount = 0;

  // 按 Y 坐标分层
  const layers = new Map();
  geometries.forEach(g => {
    const layerY = Math.round(g.y / 50) * 50; // 按 50px 分层
    if (!layers.has(layerY)) {
      layers.set(layerY, []);
    }
    layers.get(layerY).push(g);
  });

  // 对每一层进行排序优化，减少交叉
  layers.forEach((nodesInLayer, layerY) => {
    if (nodesInLayer.length <= 1) return;

    // 按连接关系排序：如果节点有共同的目标，应该相邻放置
    nodesInLayer.sort((a, b) => {
      const aTargets = connections.get(a.id) || [];
      const bTargets = connections.get(b.id) || [];

      // 如果有共同目标，按第一个目标的 X 坐标排序
      if (aTargets.length > 0 && bTargets.length > 0) {
        // 简化：按第一个目标的 ID 字母序排序
        return aTargets[0].localeCompare(bTargets[0]);
      }

      // 否则按当前 X 坐标排序
      return a.x - b.x;
    });

    // 重新分配 X 坐标，保持间距
    let currentX = nodesInLayer[0].x;
    nodesInLayer.forEach((g, index) => {
      if (index > 0) {
        currentX += nodesInLayer[index - 1].width + minSpacing;
      }

      if (Math.abs(g.x - currentX) > 5) {
        setCellGeometry(g.cell, {
          x: currentX,
          y: g.y,
          width: g.width,
          height: g.height
        });
        adjustedCount++;
      }

      g.x = currentX;
    });
  });

  // 传统的重叠检测（跨层）
  for (let i = 0; i < geometries.length; i++) {
    for (let j = i + 1; j < geometries.length; j++) {
      const g1 = geometries[i];
      const g2 = geometries[j];

      // 如果在不同层，跳过（已经在上面处理了）
      const layer1 = Math.round(g1.y / 50) * 50;
      const layer2 = Math.round(g2.y / 50) * 50;
      if (layer1 === layer2) continue;

      if (isOverlapping(g1, g2, minSpacing)) {
        // 横向推开第二个节点
        const newX = g1.x + g1.width + minSpacing;
        setCellGeometry(g2.cell, {
          x: newX,
          y: g2.y,
          width: g2.width,
          height: g2.height
        });
        g2.x = newX; // 更新缓存
        adjustedCount++;
      }
    }
  }

  console.log(`[DrawioOptimizer] 间距优化: ${adjustedCount} 个节点已调整`);
  return adjustedCount;
}

/**
 * 计算两个节点的最佳连接边缘
 * 根据相对位置判断应该从哪条边连接
 *
 * 对于 LR 布局（从左到右）：强制从左右边连接，不使用上下边
 *
 * @param {Object} sourceGeometry - 源节点几何信息
 * @param {Object} targetGeometry - 目标节点几何信息
 * @param {string} layoutDirection - 布局方向：'LR' 或 'TB'，默认 'LR'
 * @returns {Object} {exitX, exitY, entryX, entryY} - 归一化坐标 (0-1)
 */
function calculateOptimalConnection(sourceGeometry, targetGeometry, layoutDirection = 'LR') {
  if (!sourceGeometry || !targetGeometry) {
    return { exitX: 0.5, exitY: 0.5, entryX: 0.5, entryY: 0.5 };
  }

  // 计算中心点
  const sourceCenterX = sourceGeometry.x + sourceGeometry.width / 2;
  const sourceCenterY = sourceGeometry.y + sourceGeometry.height / 2;
  const targetCenterX = targetGeometry.x + targetGeometry.width / 2;
  const targetCenterY = targetGeometry.y + targetGeometry.height / 2;

  // 计算相对位置
  const dx = targetCenterX - sourceCenterX;
  const dy = targetCenterY - sourceCenterY;

  let exitX = 0.5, exitY = 0.5, entryX = 0.5, entryY = 0.5;

  if (layoutDirection === 'LR') {
    // LR 布局：强制使用左右边连接
    if (dx > 0) {
      // 目标在右侧 - 标准流向
      exitX = 1; exitY = 0.5;   // 从右边出发
      entryX = 0; entryY = 0.5; // 从左边进入
    } else {
      // 目标在左侧 - 反向连接
      exitX = 0; exitY = 0.5;   // 从左边出发
      entryX = 1; entryY = 0.5; // 从右边进入
    }
  } else {
    // TB 布局：根据相对位置自动选择
    const isHorizontal = Math.abs(dx) > Math.abs(dy);

    if (isHorizontal) {
      if (dx > 0) {
        exitX = 1; exitY = 0.5;
        entryX = 0; entryY = 0.5;
      } else {
        exitX = 0; exitY = 0.5;
        entryX = 1; entryY = 0.5;
      }
    } else {
      if (dy > 0) {
        exitX = 0.5; exitY = 1;
        entryX = 0.5; entryY = 0;
      } else {
        exitX = 0.5; exitY = 0;
        entryX = 0.5; entryY = 1;
      }
    }
  }

  return { exitX, exitY, entryX, entryY };
}

/**
 * 检测两条连线是否交叉
 * @param {Object} edge1 - {source, target, sourceGeo, targetGeo}
 * @param {Object} edge2 - {source, target, sourceGeo, targetGeo}
 * @returns {boolean} 是否交叉
 */
function detectEdgeCrossing(edge1, edge2) {
  // 简化：检测线段的包围盒是否重叠
  const box1 = {
    minX: Math.min(edge1.sourceGeo.x, edge1.targetGeo.x),
    maxX: Math.max(edge1.sourceGeo.x + edge1.sourceGeo.width, edge1.targetGeo.x + edge1.targetGeo.width),
    minY: Math.min(edge1.sourceGeo.y, edge1.targetGeo.y),
    maxY: Math.max(edge1.sourceGeo.y + edge1.sourceGeo.height, edge1.targetGeo.y + edge1.targetGeo.height)
  };

  const box2 = {
    minX: Math.min(edge2.sourceGeo.x, edge2.targetGeo.x),
    maxX: Math.max(edge2.sourceGeo.x + edge2.sourceGeo.width, edge2.targetGeo.x + edge2.targetGeo.width),
    minY: Math.min(edge2.sourceGeo.y, edge2.targetGeo.y),
    maxY: Math.max(edge2.sourceGeo.y + edge2.sourceGeo.height, edge2.targetGeo.y + edge2.targetGeo.height)
  };

  // 包围盒重叠检测
  const overlapping = !(box1.maxX < box2.minX || box2.maxX < box1.minX ||
                        box1.maxY < box2.minY || box2.maxY < box1.minY);

  if (!overlapping) return false;

  // 进一步检测：如果是垂直布局（上下关系），检查是否交叉连接
  const edge1IsVertical = Math.abs(edge1.targetGeo.y - edge1.sourceGeo.y) > 50;
  const edge2IsVertical = Math.abs(edge2.targetGeo.y - edge2.sourceGeo.y) > 50;

  if (edge1IsVertical && edge2IsVertical) {
    // 检查交叉连接模式：A→C 和 B→D，如果 A 在 B 右侧但 C 在 D 左侧
    const edge1SourceCenter = edge1.sourceGeo.x + edge1.sourceGeo.width / 2;
    const edge1TargetCenter = edge1.targetGeo.x + edge1.targetGeo.width / 2;
    const edge2SourceCenter = edge2.sourceGeo.x + edge2.sourceGeo.width / 2;
    const edge2TargetCenter = edge2.targetGeo.x + edge2.targetGeo.width / 2;

    // 交叉模式检测
    if ((edge1SourceCenter > edge2SourceCenter && edge1TargetCenter < edge2TargetCenter) ||
        (edge1SourceCenter < edge2SourceCenter && edge1TargetCenter > edge2TargetCenter)) {
      return true;
    }
  }

  return false;
}

/**
 * 避免连线穿过节点的优化
 * 检测连线路径是否穿过其他节点，并调整节点位置来避让
 *
 * @param {Document} xmlDoc - XML 文档对象
 * @returns {number} 调整的节点数量
 */
function optimizeEdgeNodeAvoidance(xmlDoc) {
  console.log('[DrawioOptimizer] 🎯 检测连线-节点冲突...');

  const edges = xmlDoc.querySelectorAll('mxCell[edge="1"]');
  const vertices = Array.from(xmlDoc.querySelectorAll('mxCell[vertex="1"]'));
  const cellMap = new Map();

  // 构建 ID -> Cell 的映射
  xmlDoc.querySelectorAll('mxCell[id]').forEach(cell => {
    cellMap.set(cell.getAttribute('id'), cell);
  });

  // 收集所有节点的几何信息
  const nodeGeometries = vertices.map(cell => ({
    cell,
    id: cell.getAttribute('id'),
    ...getCellGeometry(cell)
  })).filter(g => g.x !== undefined);

  let adjustedCount = 0;

  // 检测每条连线
  edges.forEach(edge => {
    const sourceId = edge.getAttribute('source');
    const targetId = edge.getAttribute('target');
    if (!sourceId || !targetId) return;

    const sourceCell = cellMap.get(sourceId);
    const targetCell = cellMap.get(targetId);
    if (!sourceCell || !targetCell) return;

    const sourceGeo = getCellGeometry(sourceCell);
    const targetGeo = getCellGeometry(targetCell);
    if (!sourceGeo || !targetGeo) return;

    // 计算连线的包围盒（简化的正交路径）
    // 正交路径：source中心 → 垂直移动 → 水平移动 → 垂直移动 → target中心
    const sourceCenterX = sourceGeo.x + sourceGeo.width / 2;
    const sourceCenterY = sourceGeo.y + sourceGeo.height / 2;
    const targetCenterX = targetGeo.x + targetGeo.width / 2;
    const targetCenterY = targetGeo.y + targetGeo.height / 2;

    // 连线的包围盒（留10px余量）
    const edgeBox = {
      minX: Math.min(sourceCenterX, targetCenterX) - 10,
      maxX: Math.max(sourceCenterX, targetCenterX) + 10,
      minY: Math.min(sourceCenterY, targetCenterY) - 10,
      maxY: Math.max(sourceCenterY, targetCenterY) + 10
    };

    // 检测是否有其他节点在连线路径上
    nodeGeometries.forEach(node => {
      // 跳过连线的起点和终点
      if (node.id === sourceId || node.id === targetId) return;

      // 检测节点是否在连线的包围盒内
      const nodeBox = {
        minX: node.x,
        maxX: node.x + node.width,
        minY: node.y,
        maxY: node.y + node.height
      };

      // 包围盒相交检测
      const isIntersecting = !(
        nodeBox.maxX < edgeBox.minX ||
        nodeBox.minX > edgeBox.maxX ||
        nodeBox.maxY < edgeBox.minY ||
        nodeBox.minY > edgeBox.minY
      );

      if (isIntersecting) {
        // 检测节点是否在连线的"中间区域"（不是起点或终点附近）
        const isInMiddleRegion =
          nodeBox.minX > Math.min(sourceGeo.x + sourceGeo.width, targetGeo.x + targetGeo.width) &&
          nodeBox.maxX < Math.max(sourceGeo.x, targetGeo.x);

        if (isInMiddleRegion) {
          // 需要调整节点位置
          // 策略：将节点向左或向右移动，偏离连线路径
          const edgeCenterX = (sourceCenterX + targetCenterX) / 2;
          const nodeCenterX = node.x + node.width / 2;

          // 计算移动方向（远离连线中心）
          let newX;
          if (nodeCenterX < edgeCenterX) {
            // 节点在连线左侧，继续向左移
            newX = edgeBox.minX - node.width - 30;
          } else {
            // 节点在连线右侧，继续向右移
            newX = edgeBox.maxX + 30;
          }

          // 确保新位置不是负数
          newX = Math.max(0, newX);

          // 更新节点位置
          setCellGeometry(node.cell, {
            x: newX,
            y: node.y,
            width: node.width,
            height: node.height
          });

          node.x = newX; // 更新缓存
          adjustedCount++;

          console.log(`[DrawioOptimizer] 调整节点 ${node.id}，避让连线 ${sourceId}->${targetId}`);
        }
      }
    });
  });

  console.log(`[DrawioOptimizer] ✅ 连线-节点避让: ${adjustedCount} 个节点已调整`);
  return adjustedCount;
}

/**
 * 智能连接优化（增强版 - 包含理线功能）
 * 自动设置连接线的出入点，并尝试减少交叉
 *
 * @param {Document} xmlDoc - XML 文档对象
 * @param {string} layoutDirection - 布局方向：'LR' 或 'TB'，默认 'LR'
 */
function optimizeConnections(xmlDoc, layoutDirection = 'LR') {
  const edges = xmlDoc.querySelectorAll('mxCell[edge="1"]');
  const cellMap = new Map();

  // 构建 ID -> Cell 的映射
  xmlDoc.querySelectorAll('mxCell[id]').forEach(cell => {
    cellMap.set(cell.getAttribute('id'), cell);
  });

  // 收集所有连线信息
  const edgeInfos = [];
  edges.forEach(edge => {
    const sourceId = edge.getAttribute('source');
    const targetId = edge.getAttribute('target');

    if (!sourceId || !targetId) return;

    const sourceCell = cellMap.get(sourceId);
    const targetCell = cellMap.get(targetId);

    if (!sourceCell || !targetCell) return;

    const sourceGeo = getCellGeometry(sourceCell);
    const targetGeo = getCellGeometry(targetCell);

    if (!sourceGeo || !targetGeo) return;

    edgeInfos.push({
      edge,
      sourceId,
      targetId,
      sourceCell,
      targetCell,
      sourceGeo,
      targetGeo
    });
  });

  // 检测交叉并记录
  let crossingCount = 0;
  const crossingPairs = [];

  for (let i = 0; i < edgeInfos.length; i++) {
    for (let j = i + 1; j < edgeInfos.length; j++) {
      if (detectEdgeCrossing(edgeInfos[i], edgeInfos[j])) {
        crossingCount++;
        crossingPairs.push([i, j]);
      }
    }
  }

  if (crossingCount > 0) {
    console.log(`[DrawioOptimizer] 检测到 ${crossingCount} 处连线交叉，尝试优化...`);
  }

  let optimizedCount = 0;

  // 为每条连线设置最佳连接点
  edgeInfos.forEach(info => {
    const { edge, sourceGeo, targetGeo } = info;

    // 计算最佳连接点（传入布局方向）
    const connection = calculateOptimalConnection(sourceGeo, targetGeo, layoutDirection);

    // 获取或创建 mxGeometry（必须是自闭合标签，不能有子元素）
    let geometry = edge.querySelector('mxGeometry');
    if (!geometry) {
      geometry = xmlDoc.createElement('mxGeometry');
      geometry.setAttribute('relative', '1');
      geometry.setAttribute('as', 'geometry');
      edge.appendChild(geometry);
    }

    // ❌ 删除任何 mxPoint 子元素（这会导致 "Could not add object mxGeometry" 错误）
    const mxPoints = geometry.querySelectorAll('mxPoint');
    mxPoints.forEach(point => point.remove());

    // ✅ 连接点信息应该只放在 style 属性中，不要创建 mxPoint 子元素
    // 更新样式：添加 exitX/exitY/entryX/entryY
    const style = edge.getAttribute('style') || '';
    const styleMap = new Map();
    style.split(';').forEach(pair => {
      const [key, value] = pair.split('=');
      if (key) styleMap.set(key.trim(), value || '');
    });

    styleMap.set('exitX', connection.exitX);
    styleMap.set('exitY', connection.exitY);
    styleMap.set('entryX', connection.entryX);
    styleMap.set('entryY', connection.entryY);

    // 添加正交路由样式（美观且减少交叉）
    if (!styleMap.has('edgeStyle')) {
      styleMap.set('edgeStyle', 'orthogonalEdgeStyle');
    }
    if (!styleMap.has('rounded')) {
      styleMap.set('rounded', '0');
    }

    const newStyle = Array.from(styleMap.entries())
      .map(([k, v]) => v ? `${k}=${v}` : k)
      .join(';');

    edge.setAttribute('style', newStyle);
    optimizedCount++;
  });

  console.log(`[DrawioOptimizer] 连接优化: ${optimizedCount} 条连接线已优化`);
  return optimizedCount;
}

/**
 * 样式统一优化
 * 为相同类型的节点应用一致的样式
 *
 * @param {Document} xmlDoc - XML 文档对象
 */
function optimizeStyles(xmlDoc) {
  const cells = xmlDoc.querySelectorAll('mxCell[vertex="1"]');

  // 按节点类型分组（根据 style 中的 shape 或默认形状）
  const typeGroups = new Map();

  cells.forEach(cell => {
    const style = cell.getAttribute('style') || '';
    let type = 'default';

    // 提取形状类型
    const shapeMatch = style.match(/shape=([^;]+)/);
    if (shapeMatch) {
      type = shapeMatch[1];
    } else if (style.includes('rounded=1')) {
      type = 'rounded';
    } else if (style.includes('ellipse')) {
      type = 'ellipse';
    }

    if (!typeGroups.has(type)) {
      typeGroups.set(type, []);
    }
    typeGroups.get(type).push(cell);
  });

  let optimizedCount = 0;

  // 为每个类型组应用统一样式
  typeGroups.forEach((cells, type) => {
    if (cells.length < 2) return; // 少于2个节点，无需统一

    // 收集第一个节点的样式作为基准
    const referenceStyle = cells[0].getAttribute('style') || '';
    const styleMap = new Map();
    referenceStyle.split(';').forEach(pair => {
      const [key, value] = pair.split('=');
      if (key) styleMap.set(key.trim(), value || '');
    });

    // 确保有基本样式
    if (!styleMap.has('fillColor')) {
      // 根据类型设置默认颜色
      const colors = {
        'default': '#dae8fc',
        'rounded': '#d5e8d4',
        'ellipse': '#ffe6cc',
        'swimlane': '#f5f5f5'
      };
      styleMap.set('fillColor', colors[type] || '#ffffff');
    }

    if (!styleMap.has('strokeColor')) {
      styleMap.set('strokeColor', '#6c8ebf');
    }

    // 应用到所有同类型节点
    const unifiedStyle = Array.from(styleMap.entries())
      .map(([k, v]) => v ? `${k}=${v}` : k)
      .join(';');

    cells.forEach((cell, index) => {
      if (index === 0) return; // 跳过参考节点
      cell.setAttribute('style', unifiedStyle);
      optimizedCount++;
    });
  });

  console.log(`[DrawioOptimizer] 样式统一: ${optimizedCount} 个节点已优化`);
  return optimizedCount;
}

/**
 * 主优化函数
 * 依次执行所有优化步骤
 *
 * @param {string} xmlString - 原始 draw.io XML 字符串
 * @param {Object} options - 优化选项
 * @param {boolean} options.gridAlignment - 是否网格对齐，默认 true
 * @param {boolean} options.spacing - 是否间距优化，默认 true
 * @param {boolean} options.connections - 是否连接优化，默认 true
 * @param {boolean} options.styles - 是否样式统一，默认 false
 * @returns {string} 优化后的 XML 字符串
 */
function optimizeDrawioLayout(xmlString, options = {}) {
  const defaultOptions = {
    dagreLayout: true,     // 使用 Dagre 算法进行层次化布局（新增，默认开启）
    gridAlignment: true,
    spacing: true,
    connections: true,
    styles: false // 默认关闭，避免覆盖用户自定义样式
  };

  const opts = { ...defaultOptions, ...options };

  try {
    console.log('[DrawioOptimizer] 开始优化布局...');

    // 解析 XML
    const xmlDoc = parseDrawioXml(xmlString);

    let totalOptimized = 0;

    // 0. Dagre 层次化布局（优先级最高，使用标准 Sugiyama 算法）
    if (opts.dagreLayout) {
      totalOptimized += applyDagreLayout(xmlDoc, {
        rankdir: 'LR',   // 从左到右布局，层级横向展开
        nodesep: 100,    // 同层节点垂直间距 - 增加以减少交叉
        ranksep: 180,    // 不同层水平间距 - 增加以减少交叉
        edgesep: 20,     // 边之间的间距
        ranker: 'network-simplex'  // 最佳层分配算法
      });
    }

    // 1. 网格对齐
    if (opts.gridAlignment) {
      totalOptimized += optimizeGridAlignment(xmlDoc, 10);
    }

    // 2. 间距优化（如果没有使用 dagre，则进行间距优化）
    if (opts.spacing && !opts.dagreLayout) {
      totalOptimized += optimizeSpacing(xmlDoc, 30);
    }

    // 3. 避免连线穿过节点
    if (opts.spacing) {
      totalOptimized += optimizeEdgeNodeAvoidance(xmlDoc);
    }

    // 4. 连接优化（传入布局方向）
    if (opts.connections) {
      totalOptimized += optimizeConnections(xmlDoc, 'LR');
    }

    // 5. 样式统一
    if (opts.styles) {
      totalOptimized += optimizeStyles(xmlDoc);
    }

    console.log(`[DrawioOptimizer] ✅ 优化完成，共优化 ${totalOptimized} 处`);

    // 序列化回 XML
    return serializeDrawioXml(xmlDoc);

  } catch (error) {
    console.error('[DrawioOptimizer] ❌ 优化失败:', error);
    return xmlString; // 失败时返回原始 XML
  }
}

/**
 * 对单个 diagram 进行优化（多页支持）
 * @param {Element} diagram - diagram 元素
 * @param {Object} opts - 优化选项
 * @returns {number} 优化次数
 */
function optimizeDiagram(diagram, opts) {
  const diagramName = diagram.getAttribute('name') || 'Unnamed';

  // 创建临时文档，只包含当前 diagram
  const tempDoc = document.implementation.createDocument(null, 'mxfile', null);
  const tempDiagram = diagram.cloneNode(true);
  tempDoc.documentElement.appendChild(tempDiagram);

  let optimized = 0;

  // 获取布局方向（默认 TB）
  const layoutDir = opts.layoutDirection || 'TB';

  // 应用所有优化（使用临时文档）
  if (opts.dagreLayout) {
    // 根据布局方向调整参数
    const dagreOpts = layoutDir === 'TB' ? {
      rankdir: 'TB',       // 从上到下
      nodesep: 80,         // 同层节点横向间距
      ranksep: 120,        // 不同层纵向间距（更紧凑）
      edgesep: 10,
      ranker: 'network-simplex'
    } : {
      rankdir: 'LR',       // 从左到右
      nodesep: 100,        // 同层节点纵向间距
      ranksep: 180,        // 不同层横向间距
      edgesep: 20,
      ranker: 'network-simplex'
    };

    optimized += applyDagreLayout(tempDoc, dagreOpts);
  }

  if (opts.gridAlignment) {
    optimized += optimizeGridAlignment(tempDoc, 10);
  }

  if (opts.spacing && !opts.dagreLayout) {
    optimized += optimizeSpacing(tempDoc, 30);
  }

  if (opts.spacing) {
    optimized += optimizeEdgeNodeAvoidance(tempDoc);
  }

  if (opts.connections) {
    optimized += optimizeConnections(tempDoc, layoutDir);
  }

  if (opts.styles) {
    optimized += optimizeStyles(tempDoc);
  }

  // 将优化后的节点同步回原始 diagram
  const optimizedDiagram = tempDoc.querySelector('diagram');
  const originalCells = diagram.querySelectorAll('mxCell[id]');
  const optimizedCells = optimizedDiagram.querySelectorAll('mxCell[id]');

  const cellMap = new Map();
  optimizedCells.forEach(cell => {
    cellMap.set(cell.getAttribute('id'), cell);
  });

  originalCells.forEach(originalCell => {
    const id = originalCell.getAttribute('id');
    const optimizedCell = cellMap.get(id);
    if (!optimizedCell) return;

    // 同步几何信息和样式
    const originalGeo = originalCell.querySelector('mxGeometry');
    const optimizedGeo = optimizedCell.querySelector('mxGeometry');

    if (originalGeo && optimizedGeo) {
      // 同步所有属性
      ['x', 'y', 'width', 'height', 'relative', 'as', 'exitX', 'exitY', 'entryX', 'entryY'].forEach(attr => {
        if (optimizedGeo.hasAttribute(attr)) {
          originalGeo.setAttribute(attr, optimizedGeo.getAttribute(attr));
        }
      });
    }

    // 同步样式
    if (optimizedCell.hasAttribute('style')) {
      originalCell.setAttribute('style', optimizedCell.getAttribute('style'));
    }
  });

  return optimized;
}

/**
 * 主优化函数（支持多页图表）
 * @param {string} xmlString - 原始 draw.io XML 字符串
 * @param {Object} options - 优化选项
 * @returns {string} 优化后的 XML 字符串
 */
function optimizeDrawioLayoutMultiPage(xmlString, options = {}) {
  const defaultOptions = {
    dagreLayout: true,
    gridAlignment: true,
    spacing: true,
    connections: true,
    styles: false
  };

  const opts = { ...defaultOptions, ...options };

  try {
    const xmlDoc = parseDrawioXml(xmlString);
    const diagrams = Array.from(xmlDoc.querySelectorAll('diagram'));

    if (diagrams.length === 0) {
      console.warn('[DrawioOptimizer] ⚠️ 未找到 diagram 元素，使用旧版单页优化');
      return optimizeDrawioLayout(xmlString, options);
    }

    console.log(`[DrawioOptimizer] 🎯 检测到 ${diagrams.length} 个页面，开始独立优化...`);

    let totalOptimized = 0;

    diagrams.forEach((diagram, index) => {
      const name = diagram.getAttribute('name') || `Page ${index + 1}`;
      console.log(`[DrawioOptimizer] 📄 优化页面 "${name}"...`);
      const count = optimizeDiagram(diagram, opts);
      console.log(`[DrawioOptimizer] ✅ 页面 "${name}" 完成，优化 ${count} 处`);
      totalOptimized += count;
    });

    console.log(`[DrawioOptimizer] ✅ 全部完成，共优化 ${totalOptimized} 处`);
    return serializeDrawioXml(xmlDoc);

  } catch (error) {
    console.error('[DrawioOptimizer] ❌ 多页优化失败，回退到单页模式:', error);
    return optimizeDrawioLayout(xmlString, options);
  }
}

// 导出到全局
window.DrawioLayoutOptimizer = {
  optimizeDrawioLayout: optimizeDrawioLayoutMultiPage,  // 使用新的多页版本
  optimizeDrawioLayoutLegacy: optimizeDrawioLayout      // 保留旧版本
};
