/**
 * 因果链图算法 — 供 ConnectionLines / MapCanvas 共用
 * 连线数据: { from: 'financial-0', to: 'customer-1', effect?: 'positive'|'negative', label?: string }
 */

export interface ChainResult {
  /** 链上节点 key 集合 */
  nodes: string[]
  /** 链上连线索引集合 */
  connIdxs: number[]
}

interface AdjNode {
  out: Set<string>
  in: Set<string>
}

function buildAdjacency(connections: any[]): Map<string, AdjNode> {
  const adj = new Map<string, AdjNode>()
  for (const c of connections) {
    if (!c?.from || !c?.to) continue
    if (!adj.has(c.from)) adj.set(c.from, { out: new Set(), in: new Set() })
    if (!adj.has(c.to)) adj.set(c.to, { out: new Set(), in: new Set() })
    adj.get(c.from)!.out.add(c.to)
    adj.get(c.to)!.in.add(c.from)
  }
  return adj
}

/** 从 start 沿 out 边 BFS（下游） */
function descendants(adj: Map<string, AdjNode>, start: string): Set<string> {
  const seen = new Set<string>([start])
  const queue = [start]
  while (queue.length) {
    const cur = queue.shift()!
    for (const next of adj.get(cur)?.out ?? []) {
      if (!seen.has(next)) {
        seen.add(next)
        queue.push(next)
      }
    }
  }
  return seen
}

/** 从 start 沿 in 边 BFS（上游） */
function ancestors(adj: Map<string, AdjNode>, start: string): Set<string> {
  const seen = new Set<string>([start])
  const queue = [start]
  while (queue.length) {
    const cur = queue.shift()!
    for (const prev of adj.get(cur)?.in ?? []) {
      if (!seen.has(prev)) {
        seen.add(prev)
        queue.push(prev)
      }
    }
  }
  return seen
}

/**
 * 某条连线的完整因果链：源节点的所有下游 + 目标节点的所有上游
 * （即"从因到果"整条路径上的节点与连线）
 */
export function getChainForConnection(connections: any[], connIdx: number): ChainResult | null {
  const conn = connections[connIdx]
  if (!conn?.from || !conn?.to) return null
  const adj = buildAdjacency(connections)
  const nodeSet = new Set<string>([...descendants(adj, conn.from), ...ancestors(adj, conn.to)])
  const connIdxs: number[] = []
  connections.forEach((c, i) => {
    if (c?.from && c?.to && nodeSet.has(c.from) && nodeSet.has(c.to)) connIdxs.push(i)
  })
  return { nodes: [...nodeSet], connIdxs }
}

/**
 * 某节点的相关因果链：其上游（原因）+ 下游（结果）全部节点与连线
 */
export function getChainForNode(connections: any[], nodeKey: string): ChainResult | null {
  const adj = buildAdjacency(connections)
  if (!adj.has(nodeKey)) return null
  const nodeSet = new Set<string>([...descendants(adj, nodeKey), ...ancestors(adj, nodeKey)])
  if (nodeSet.size <= 1) return { nodes: [nodeKey], connIdxs: [] }
  const connIdxs: number[] = []
  connections.forEach((c, i) => {
    if (c?.from && c?.to && nodeSet.has(c.from) && nodeSet.has(c.to)) connIdxs.push(i)
  })
  return { nodes: [...nodeSet], connIdxs }
}
