import type { Node, Edge } from 'reactflow';

const HORIZONTAL_SPACING = 220;
const VERTICAL_SPACING = 120;

/**
 * 判断是否应对节点应用自动布局（避免重叠）。
 * 当绝大多数节点在 (0,0) 或存在大量同位置节点时返回 true。
 */
export function shouldApplyLayout(nodes: Node[], edges: Edge[]): boolean {
  if (!nodes.length) return false;
  const atOrigin = nodes.filter((n) => n.position.x === 0 && n.position.y === 0).length;
  if (atOrigin >= nodes.length * 0.8) return true;
  const positionKey = (n: Node) => `${Math.round(n.position.x)}_${Math.round(n.position.y)}`;
  const byPos = new Map<string, number>();
  nodes.forEach((n) => {
    const k = positionKey(n);
    byPos.set(k, (byPos.get(k) || 0) + 1);
  });
  const maxSamePosition = Math.max(...byPos.values(), 0);
  return maxSamePosition >= Math.max(2, Math.ceil(nodes.length * 0.3));
}

/**
 * 根据边的拓扑关系计算层级，再按层级排布节点位置，与流程设计器风格一致，避免重叠。
 */
export function getLayoutedNodes(
  nodes: Node[],
  edges: Edge[],
  options?: { horizontalSpacing?: number; verticalSpacing?: number }
): Node[] {
  const hSpacing = options?.horizontalSpacing ?? HORIZONTAL_SPACING;
  const vSpacing = options?.verticalSpacing ?? VERTICAL_SPACING;

  const idToNode = new Map<string, Node>();
  nodes.forEach((n) => idToNode.set(n.id, n));

  const parents = new Map<string, string[]>();
  const children = new Map<string, string[]>();
  nodes.forEach((n) => {
    parents.set(n.id, []);
    children.set(n.id, []);
  });
  edges.forEach((e) => {
    if (!idToNode.has(e.source) || !idToNode.has(e.target)) return;
    const pl = parents.get(e.target) ?? [];
    if (!pl.includes(e.source)) pl.push(e.source);
    parents.set(e.target, pl);
    const cl = children.get(e.source) ?? [];
    if (!cl.includes(e.target)) cl.push(e.target);
    children.set(e.source, cl);
  });

  const levels = new Map<string, number>();
  function getLevel(id: string): number {
    if (levels.has(id)) return levels.get(id)!;
    const pr = parents.get(id) ?? [];
    const l = pr.length === 0 ? 0 : 1 + Math.max(...pr.map((pid) => getLevel(pid)));
    levels.set(id, l);
    return l;
  }
  nodes.forEach((n) => getLevel(n.id));

  const byLevel = new Map<number, string[]>();
  levels.forEach((level, id) => {
    const list = byLevel.get(level) ?? [];
    list.push(id);
    byLevel.set(level, list);
  });
  const sortedLevels = Array.from(byLevel.keys()).sort((a, b) => a - b);

  const positionById = new Map<string, { x: number; y: number }>();
  sortedLevels.forEach((level) => {
    const ids = byLevel.get(level) ?? [];
    const y = level * vSpacing;
    ids.forEach((id, i) => {
      positionById.set(id, { x: i * hSpacing, y });
    });
  });

  return nodes.map((n) => ({
    ...n,
    position: positionById.get(n.id) ?? n.position,
  }));
}
