/**
 * Radial Mindmap Layout - 放射思维导图布局
 * 
 * 结构：
 *                    孙节点1.1
 *                       │
 *         子节点1 ──────┼────── 孙节点1.2
 *            │          │
 *            ├───── 根节点（中心） ─────┤
 *            │                            │
 *         子节点2                      子节点3
 *            │                            │
 *            ├───── 孙节点2.1           孙节点3.1
 *            │
 *          孙节点2.2
 * 
 * 特点：
 * - 根节点在中心
 * - 子节点左右对称分布
 * - 一级子节点数量决定分布策略
 * - 符合经典思维导图视觉效果
 * 
 * 行业标准：
 * - 遵循 Tony Buzan 思维导图理论
 * - 类似 XMind、MindManager 的标准思维导图模式
 */

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

export class RadialMindmapLayout extends LayoutEngine {
  readonly type = 'radial-mindmap' as const

  /** 默认配置 */
  protected config = {
    nodeSpacingX: 200,
    nodeSpacingY: 60,
    rootPosition: { x: 400, y: 300 },  // 根节点在画布中心
    levelGap: 180,          // 层级间距
    siblingGap: 50,         // 兄弟节点间距
    subtreeGap: 30,         // 子树间距
    minBranchHeight: 60     // 最小分支高度
  }

  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 })

    // 获取一级子节点
    const level1Children = graph.getChildren(root.id).filter(n => !n.hidden)
    
    if (level1Children.length === 0) return positions

    // 将一级子节点分成左右两组
    const { leftNodes, rightNodes } = this.splitLeftRight(level1Children)

    // 布局右侧节点
    this.layoutBranch(rightNodes, root, graph, positions, 1)
    
    // 布局左侧节点
    this.layoutBranch(leftNodes, root, graph, positions, -1)

    return positions
  }

  /**
   * 将节点分成左右两组
   * 策略：奇数节点放右侧，偶数节点放左侧，保持平衡
   */
  private splitLeftRight(nodes: Node[]): { leftNodes: Node[]; rightNodes: Node[] } {
    const leftNodes: Node[] = []
    const rightNodes: Node[] = []

    nodes.forEach((node, index) => {
      // 奇数索引放右侧，偶数索引放左侧
      if (index % 2 === 0) {
        rightNodes.push(node)
      } else {
        leftNodes.push(node)
      }
    })

    return { leftNodes, rightNodes }
  }

  /**
   * 布局一个分支（左侧或右侧）
   * @param nodes 一级子节点
   * @param root 根节点
   * @param graph 图模型
   * @param positions 位置映射
   * @param direction 方向：1=右侧，-1=左侧
   */
  private layoutBranch(
    nodes: Node[],
    root: Node,
    graph: IGraphModel,
    positions: Map<string, Point>,
    direction: 1 | -1
  ): void {
    const rootPos = positions.get(root.id)!
    
    // 计算该分支的总高度
    const totalHeight = nodes.reduce((sum, node) => {
      const subtreeSize = this.calcSubtreeSize(node, graph, 36, this.config.subtreeGap)
      return sum + subtreeSize
    }, 0)

    // 起始Y坐标（从上到下布局）
    let currentY = rootPos.y - totalHeight / 2

    // 一级子节点的X坐标
    const level1X = rootPos.x + direction * this.config.levelGap

    nodes.forEach(node => {
      const subtreeSize = this.calcSubtreeSize(node, graph, 36, this.config.subtreeGap)
      const nodeY = currentY + subtreeSize / 2

      // 设置一级子节点位置
      positions.set(node.id, { x: level1X, y: nodeY })

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

      currentY += subtreeSize
    })
  }

  /**
   * 递归布局子节点
   */
  private layoutChildren(
    parent: Node,
    graph: IGraphModel,
    positions: Map<string, Point>,
    parentX: number,
    direction: 1 | -1,
    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

    // 计算所有子节点的总高度
    const totalHeight = children.reduce((sum, child) => {
      const subtreeSize = this.calcSubtreeSize(child, graph, 36, this.config.subtreeGap)
      return sum + subtreeSize
    }, 0)

    // 子节点的起始Y坐标
    let currentY = parentPos.y - totalHeight / 2

    // 子节点的X坐标（向同一方向延伸）
    const childX = parentX + direction * this.config.levelGap

    children.forEach(child => {
      const subtreeSize = this.calcSubtreeSize(child, graph, 36, this.config.subtreeGap)
      const childY = currentY + subtreeSize / 2

      positions.set(child.id, { x: childX, y: childY })

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

      currentY += subtreeSize
    })
  }
}

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

export default RadialMindmapLayout
