import {type Edge, type Node} from '@xyflow/react'

export const buildEL = (nodes: Node[], edges: Edge[]): string => {
  const nodeMap: Map<string, Node> = new Map<string, Node>()
  // 构建邻接列表和内图
  const adjList = new Map<string, string[]>()
  const inDegree = new Map<string, number>()
  for (const node of nodes) {
    nodeMap.set(node.id, node)
    adjList.set(node.id, [])
    inDegree.set(node.id, 0)
  }
  for (const edge of edges) {
    adjList.get(edge.source)!.push(edge.target)
    inDegree.set(edge.target, inDegree.get(edge.target)! + 1)
  }

  // Compute levels (longest path from start)
  const levelMap = new Map<string, number>()

  function computeLevel(nodeId: string): number {
    if (levelMap.has(nodeId)) return levelMap.get(nodeId)!
    const preds = edges.filter(e => e.target === nodeId).map(e => e.source)
    const level = preds.length === 0 ? 0 : Math.max(...preds.map(p => computeLevel(p))) + 1
    levelMap.set(nodeId, level)
    return level
  }

  for (const node of nodes) computeLevel(node.id)

  // Group nodes by level
  const maxLevel = Math.max(...Array.from(levelMap.values()))
  const levels: string[][] = Array.from({length: maxLevel + 1}, () => [])
  for (const node of nodes) levels[levelMap.get(node.id)!].push(node.id)

  const covertNodeFromId = (id: string) => {
    let node = nodeMap.get(id)!
    return `node("${node.type}").bind("nodeId", ${node.id})`
  }

  // Build EL expression
  const expressions: string[] = []
  for (let i = 0; i <= maxLevel; i++) {
    const nodesAtLevel = levels[i]
    if (nodesAtLevel.length === 0) continue

    // 识别从这个级别开始的串行链
    const serialChains: string[] = []
    for (const nodeId of nodesAtLevel) {
      let chain = [nodeId]
      let current = nodeId
      while (adjList.get(current)?.length === 1) {
        const next = adjList.get(current)![0]
        if (inDegree.get(next) === 1 && levelMap.get(next) === i + chain.length) {
          chain.push(next)
          current = next
        } else break
      }
      if (chain.length > 1) {
        serialChains.push(`THEN(${chain.map(id => covertNodeFromId(id)).join(',')})`)
        // Remove processed nodes from their levels
        for (let j = 1; j < chain.length; j++) {
          const level = levelMap.get(chain[j])!
          levels[level] = levels[level].filter(n => n !== chain[j])
        }
      } else {
        serialChains.push(covertNodeFromId(nodeId))
      }
    }

    // Combine chains or nodes at this level
    expressions.push(serialChains.length > 1 ? `WHEN(${serialChains.join(', ')})` : serialChains[0])
  }

  return `THEN(${expressions.join(',')})`
}