import { Node, Edge } from '@vue-flow/core'
import { TopoGroup, NodeData } from '../types'

/**
 * 从节点数据构建分组树状结构
 * 规则:
 * 1. 优先根据连接线(edges)的source->target关系构建树
 * 2. source节点为父节点，target节点为子节点
 * 3. 如果没有连接线，则所有节点都作为根节点
 */
export function buildGroupTreeFromNodes(nodes: Node[], edges: Edge[] = []): TopoGroup[] {
  if (nodes.length === 0) return []

  // 始终使用边关系构建树
  return buildFromEdges(nodes, edges)
}

/**
 * 方式1: 使用level和parentId信息构建分组树
 */
function buildFromLevelInfo(nodes: Node[]): TopoGroup[] {
  // 找出所有一级节点(level=0)
  const rootNodes = nodes.filter((node) => {
    const data = node.data as NodeData
    return data.level === 0
  })

  // 为每个一级节点构建分组树
  return rootNodes.map((rootNode) => buildGroupFromNode(rootNode, nodes))
}

/**
 * 方式2: 根据连接线自动推断层级关系
 */
function buildFromEdges(nodes: Node[], edges: Edge[]): TopoGroup[] {
  // 构建连接关系图: 找出每个节点的子节点
  const childrenMap = new Map<string, string[]>()
  const hasParent = new Set<string>()

  edges.forEach((edge) => {
    const sourceId = edge.source
    const targetId = edge.target

    if (!childrenMap.has(sourceId)) {
      childrenMap.set(sourceId, [])
    }
    childrenMap.get(sourceId)!.push(targetId)
    hasParent.add(targetId)
  })

  // 找出根节点(没有父节点的)
  const rootNodes = nodes.filter((node) => !hasParent.has(node.id))

  // 如果没有边,则所有节点都是根节点
  if (edges.length === 0) {
    return nodes.map((node) => {
      const data = node.data as NodeData
      return {
        id: node.id,
        name: data.label || `节点${node.id}`,
        nodeId: node.id,
        level: 0,
        parentId: undefined,
        children: undefined,
      }
    })
  }

  // 为每个根节点构建分组树
  return rootNodes.map((rootNode) => buildGroupFromEdges(rootNode, nodes, childrenMap, 0))
}

/**
 * 根据连接关系递归构建分组
 */
function buildGroupFromEdges(node: Node, allNodes: Node[], childrenMap: Map<string, string[]>, level: number): TopoGroup {
  const data = node.data as NodeData
  const childIds = childrenMap.get(node.id) || []

  const children =
    childIds.length > 0
      ? childIds
          .map((childId) => allNodes.find((n) => n.id === childId))
          .filter((n): n is Node => n !== undefined)
          .map((childNode) => buildGroupFromEdges(childNode, allNodes, childrenMap, level + 1))
      : undefined

  return {
    id: node.id,
    name: data.label || `节点${node.id}`,
    nodeId: node.id,
    level,
    parentId: undefined,
    children,
  }
}

/**
 * 使用level/parentId信息递归构建单个节点的分组树
 */
function buildGroupFromNode(node: Node, allNodes: Node[]): TopoGroup {
  const data = node.data as NodeData

  // 查找当前节点的所有子节点
  const childNodes = allNodes.filter((n) => {
    const nodeData = n.data as NodeData
    return nodeData.parentId === node.id
  })

  // 递归构建子分组
  const children = childNodes.length > 0 ? childNodes.map((childNode) => buildGroupFromNode(childNode, allNodes)) : undefined

  return {
    id: node.id,
    name: data.label,
    nodeId: node.id,
    level: data.level || 0,
    parentId: data.parentId || undefined,
    children,
  }
}

/**
 * 获取分组下的所有节点ID(包括子分组的节点)
 */
export function getGroupNodeIds(group: TopoGroup): string[] {
  const ids = [group.nodeId]

  if (group.children) {
    group.children.forEach((child) => {
      ids.push(...getGroupNodeIds(child))
    })
  }

  return ids
}

/**
 * 根据分组筛选节点和边
 */
export function filterByGroup(nodes: Node[], edges: Edge[], selectedGroup: string | null): { nodes: Node[]; edges: Edge[] } {
  if (!selectedGroup) {
    return { nodes, edges }
  }

  // 找到选中的分组
  const allGroups = buildGroupTreeFromNodes(nodes, edges)
  const group = findGroupById(allGroups, selectedGroup)

  if (!group) {
    return { nodes, edges }
  }

  // 获取分组下的所有节点ID
  const nodeIds = getGroupNodeIds(group)

  // 筛选节点
  const filteredNodes = nodes.filter((node) => nodeIds.includes(node.id))

  // 筛选边(只保留两端都在分组内的边)
  const filteredEdges = edges.filter((edge) => nodeIds.includes(edge.source) && nodeIds.includes(edge.target))

  return { nodes: filteredNodes, edges: filteredEdges }
}

/**
 * 在分组树中查找指定ID的分组
 */
function findGroupById(groups: TopoGroup[], id: string): TopoGroup | null {
  for (const group of groups) {
    if (group.id === id) {
      return group
    }
    if (group.children) {
      const found = findGroupById(group.children, id)
      if (found) {
        return found
      }
    }
  }
  return null
}
