/**
 * Org Chart Layout - 组织结构图布局
 * 
 * 结构：
 *                    CEO（根节点）
 *                         │
 *         ┌───────────────┼───────────────┐
 *         │               │               │
 *      CTO             CFO             COO
 *         │               │               │
 *    ┌────┴────┐          │          ┌────┴────┐
 *    │         │          │          │         │
 *  Tech1    Tech2      Finance    Ops1      Ops2
 * 
 * 特点：
 * - 根节点在顶部
 * - 下级节点直接在上级节点下方
 * - 同级节点水平均匀分布
 * - 强调层级关系和汇报结构
 * - 子树宽度自适应，避免节点重叠
 * 
 * 适用场景：
 * - 组织架构图
 * - 团队结构
 * - 管理层级
 */

import { LayoutEngine, layoutRegistry } from './LayoutEngine'
import type { Node, Point, IGraphModel } from '../core/types'

export class OrgChartLayout extends LayoutEngine {
  readonly type = 'org-chart' as const

  /** 默认配置 */
  protected config = {
    nodeSpacingX: 200,
    nodeSpacingY: 60,
    rootPosition: { x: 400, y: 50 },
    levelGap: 100,          // 层级垂直间距
    nodeGap: 40,            // 节点水平间距（节点边缘之间的间距）
    minSubtreeGap: 20       // 子树之间的最小间距
  }

  layout(graph: IGraphModel): Map<string, Point> {
    const positions = new Map<string, Point>()
    const root = graph.root

    if (!root) return positions

    // 根节点位置（顶部中央）
    positions.set(root.id, { ...this.config.rootPosition })

    // 递归布局子节点
    this.layoutChildren(root, graph, positions, 1)

    return positions
  }

  /**
   * 计算子树的总宽度（包括所有后代节点）
   * 这确保子树内的节点不会重叠
   */
  private calcSubtreeWidth(
    node: Node,
    graph: IGraphModel
  ): number {
    const children = graph.getChildren(node.id).filter(n => !n.hidden)
    
    if (children.length === 0) {
      // 叶子节点：宽度等于节点本身宽度
      return this.getNodeWidth(node)
    }
    
    // 有子节点：宽度 = 所有子树宽度之和 + 子树间距
    let totalWidth = 0
    children.forEach((child, index) => {
      const childSubtreeWidth = this.calcSubtreeWidth(child, graph)
      totalWidth += childSubtreeWidth
      if (index < children.length - 1) {
        totalWidth += this.config.minSubtreeGap
      }
    })
    
    // 确保至少能容纳所有直接子节点
    const childWidths = children.map(c => this.getNodeWidth(c))
    const totalChildWidth = childWidths.reduce((s, w) => s + w, 0)
    const minChildWidth = totalChildWidth + (children.length - 1) * this.config.nodeGap
    
    return Math.max(totalWidth, minChildWidth)
  }

  /**
   * 递归布局子节点
   */
  private layoutChildren(
    parent: Node,
    graph: IGraphModel,
    positions: Map<string, Point>,
    level: number
  ): void {
    const children = graph.getChildren(parent.id).filter(n => !n.hidden)
    if (children.length === 0) return

    const parentPos = positions.get(parent.id)
    if (!parentPos) return

    // 计算所有子节点的总宽度
    let totalWidth = 0
    const childWidths: number[] = []
    
    children.forEach((child, index) => {
      const width = this.calcSubtreeWidth(child, graph)
      childWidths.push(width)
      totalWidth += width
      if (index < children.length - 1) {
        totalWidth += this.config.minSubtreeGap
      }
    })

    // 子节点的Y坐标
    const childY = parentPos.y + this.config.levelGap

    // 子节点居中于父节点下方，从左侧开始布局
    let currentX = parentPos.x - totalWidth / 2

    children.forEach((child, index) => {
      const childWidth = childWidths[index]
      
      // 子节点居中于其子树宽度内
      const childX = currentX + childWidth / 2
      
      positions.set(child.id, { x: childX, y: childY })

      // 递归布局孙节点
      this.layoutChildren(child, graph, positions, level + 1)

      // 移动到下一个子树位置
      currentX += childWidth + this.config.minSubtreeGap
    })
  }
}

// 注册布局引擎
layoutRegistry.register(new OrgChartLayout())

export default OrgChartLayout
