/**
 * Fishbone Layout - 鱼骨图（石川图）布局
 * 
 * 结构：
 *   根节点 ─────●────────●────────●─────→ 主干线（水平）
 *              /║\       /║\       /║\
 *             / ║ \     / ║ \     / ║ \
 *        二级节点║三级  二级节点║三级  二级节点
 *            (45°║继续)  (45°║)     (45°║)
 *                ║          ║         ║
 *            四级节点    四级节点   四级节点
 *            (22.5°)     (22.5°)    (22.5°)
 * 
 * 层级关系：根节点 → 二级节点 → 三级节点 → 四级节点...
 * 
 * 特点：
 * - 根节点在左侧（鱼头）
 * - 主干线水平延伸
 * - 二级节点斜向分出，上下交替（45度）
 * - 三级节点沿同一方向继续延伸（保持45度）
 * - 四级及以下角度减半（22.5度）
 * - Canvas渲染可以完美实现
 */

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

/** 鱼骨图分支信息 */
interface BranchInfo {
  id: string
  attachPoint: Point      // 主干线上的附着点
  direction: -1 | 1       // -1 向上，1 向下
  childNodes: string[]    // 该分支的子节点
}

export class FishboneLayout extends LayoutEngine {
  readonly type = 'fishbone' as const

  protected config = {
    nodeSpacingX: 150,
    nodeSpacingY: 60,
    rootPosition: { x: 100, y: 300 },
    backboneStartX: 200,      // 主干线起点X
    branchSpacing: 120,       // 分支点间距
    branchAngle: 45,          // 斜线角度（度）
    branchLength: 80,         // 二级节点斜线长度
    levelGap: 70,            // 父节点到第一个子节点的间距（层级间间距，较大以区分层级）
    level3Spacing: 50,       // 三级节点之间的间距（同级间距）
    level4Spacing: 50,       // 四级及以下节点之间的间距（同级间距）
    level4Angle: 0.5          // 四级节点角度系数（减半）
  }

  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 rootPos = positions.get(root.id)!
    const backboneY = rootPos.y  // 主干线Y坐标

    // 获取二级节点（根节点的子节点）
    const level2Nodes = graph.getChildren(root.id).filter(n => !n.hidden)

    if (level2Nodes.length === 0) return positions

    // 计算分支点位置和方向
    const branches: BranchInfo[] = level2Nodes.map((node, index) => ({
      id: node.id,
      attachPoint: {
        x: this.config.backboneStartX + index * this.config.branchSpacing,
        y: backboneY
      },
      direction: index % 2 === 0 ? -1 : 1 as -1 | 1,  // 偶数向上，奇数向下
      childNodes: graph.getChildren(node.id).filter(n => !n.hidden).map(n => n.id)
    }))

    // 布局二级节点和他们的子节点
    branches.forEach((branch, index) => {
      const angleRad = this.config.branchAngle * Math.PI / 180
      
      // 二级节点位置（45度斜线末端）
      const childX = branch.attachPoint.x + Math.cos(angleRad) * this.config.branchLength
      const childY = branch.attachPoint.y + branch.direction * Math.sin(angleRad) * this.config.branchLength

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

      // 布局三级节点（沿同一方向继续延伸）
      this.layoutLevel3Nodes(
        branch,
        childX,
        childY,
        angleRad,  // 保持45度角
        branch.direction,
        graph,
        positions
      )
    })

    // 存储主干线信息（供渲染器使用）
    this.storeBackboneInfo(rootPos, branches, positions)

    return positions
  }

  /**
   * 布局三级节点
   * 沿二级节点的方向继续延伸，保持45度角
   */
  private layoutLevel3Nodes(
    branch: BranchInfo,
    startX: number,
    startY: number,
    angleRad: number,
    direction: -1 | 1,
    graph: IGraphModel,
    positions: Map<string, Point>
  ): void {
    const children = graph.getChildren(branch.id).filter(n => !n.hidden)
    if (children.length === 0) return

    // 第一个子节点从父节点位置偏移 levelGap（确保层级间有间距）
    let currentX = startX + Math.cos(angleRad) * this.config.levelGap
    let currentY = startY + direction * Math.sin(angleRad) * this.config.levelGap

    children.forEach((child, index) => {
      if (index > 0) {
        // 后续节点使用同级间距
        currentX += Math.cos(angleRad) * this.config.level3Spacing
        currentY += direction * Math.sin(angleRad) * this.config.level3Spacing
      }

      positions.set(child.id, { x: currentX, y: currentY })

      // 布局四级及以下节点（保持同一角度）
      const grandChildren = graph.getChildren(child.id).filter(n => !n.hidden)
      if (grandChildren.length > 0) {
        this.layoutLevel4AndBeyond(child, currentX, currentY, angleRad, direction, graph, positions)
      }
    })
  }

  /**
   * 递归布局四级及以下节点
   * 角度减半（约22.5度），更平缓
   */
  private layoutLevel4AndBeyond(
    parent: Node,
    startX: number,
    startY: number,
    angleRad: number,
    direction: -1 | 1,
    graph: IGraphModel,
    positions: Map<string, Point>
  ): void {
    const children = graph.getChildren(parent.id).filter(n => !n.hidden)
    if (children.length === 0) return

    // 第一个子节点从父节点位置偏移 levelGap（确保层级间有间距）
    let currentX = startX + Math.cos(angleRad) * this.config.levelGap
    let currentY = startY + direction * Math.sin(angleRad) * this.config.levelGap

    children.forEach((child, index) => {
      if (index > 0) {
        // 后续节点使用同级间距
        currentX += Math.cos(angleRad) * this.config.level4Spacing
        currentY += direction * Math.sin(angleRad) * this.config.level4Spacing
      }

      positions.set(child.id, { x: currentX, y: currentY })

      // 递归布局更深层节点（保持同一角度）
      this.layoutLevel4AndBeyond(child, currentX, currentY, angleRad, direction, graph, positions)
    })
  }

  /**
   * 存储主干线信息（供渲染器使用）
   * 这是Canvas渲染层的优势：可以自由绘制主干线
   */
  private storeBackboneInfo(
    rootPos: Point,
    branches: BranchInfo[],
    positions: Map<string, Point>
  ): void {
    // 主干线起点
    const backboneStart: Point = { x: rootPos.x, y: rootPos.y }
    
    // 主干线终点（最后一个分支点）
    const backboneEnd: Point = branches.length > 0
      ? { x: branches[branches.length - 1].attachPoint.x + 50, y: rootPos.y }
      : { x: rootPos.x + 100, y: rootPos.y }

    // 将主干线信息存储到特殊位置（供渲染器读取）
    positions.set('__backbone_start__', backboneStart)
    positions.set('__backbone_end__', backboneEnd)

    // 存储每个分支点信息
    branches.forEach((branch, index) => {
      positions.set(`__branch_${index}__`, branch.attachPoint)
    })
  }

  /**
   * 获取主干线信息（供渲染器调用）
   */
  static getBackboneInfo(positions: Map<string, Point>): {
    start: Point
    end: Point
    branches: Point[]
  } {
    const start = positions.get('__backbone_start__') || { x: 0, y: 0 }
    const end = positions.get('__backbone_end__') || { x: 100, y: 0 }
    
    const branches: Point[] = []
    let index = 0
    while (positions.has(`__branch_${index}__`)) {
      branches.push(positions.get(`__branch_${index}__`)!)
      index++
    }

    return { start, end, branches }
  }
}

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

export default FishboneLayout
