import type { BatchOp } from '@/api/mapEdit'

/**
 * 对齐算法：纯前端计算每个选中对象的新坐标，再以 batch ops（patch）回写到反射 API。
 * 仅支持有 (x, y) 坐标的对象（site / image / text / model 等 UIHelper 子类）；
 * track 是端点连线，没有自己的坐标，alignment 不影响 track。
 */

export interface AlignTarget {
  kind: string
  id: number
  x: number
  y: number
  width?: number
  height?: number
}

export type AlignMode =
  | 'left'
  | 'right'
  | 'top'
  | 'bottom'
  | 'centerH'
  | 'centerV'
  | 'center'
  | 'distributeH'
  | 'distributeV'
  | 'toFirst'
  | 'toLast'

/**
 * 根据对齐模式计算 patch ops。返回值为 mapEdit.batch 直接消费的 BatchOp 数组。
 * 输入要求至少 2 个对象（distribute 需要 ≥ 3 才有意义）。
 */
export function buildAlignOps(targets: AlignTarget[], mode: AlignMode): BatchOp[] {
  if (targets.length < 2) return []

  const ops: BatchOp[] = []

  const xs = targets.map((t) => t.x)
  const ys = targets.map((t) => t.y)
  const minX = Math.min(...xs)
  const maxX = Math.max(...xs)
  const minY = Math.min(...ys)
  const maxY = Math.max(...ys)
  const avgX = xs.reduce((a, b) => a + b, 0) / xs.length
  const avgY = ys.reduce((a, b) => a + b, 0) / ys.length

  switch (mode) {
    case 'left':
      for (const t of targets) ops.push(patch(t, { x: minX }))
      break
    case 'right':
      for (const t of targets) ops.push(patch(t, { x: maxX }))
      break
    case 'top':
      // 工程坐标 y 向上为正：top 取 max
      for (const t of targets) ops.push(patch(t, { y: maxY }))
      break
    case 'bottom':
      for (const t of targets) ops.push(patch(t, { y: minY }))
      break
    case 'centerH':
      for (const t of targets) ops.push(patch(t, { x: avgX }))
      break
    case 'centerV':
      for (const t of targets) ops.push(patch(t, { y: avgY }))
      break
    case 'center':
      for (const t of targets) ops.push(patch(t, { x: avgX, y: avgY }))
      break
    case 'distributeH': {
      const sorted = [...targets].sort((a, b) => a.x - b.x)
      const step = (sorted[sorted.length - 1]!.x - sorted[0]!.x) / (sorted.length - 1)
      sorted.forEach((t, i) => {
        const x = sorted[0]!.x + step * i
        if (Math.abs(x - t.x) > 0.5) ops.push(patch(t, { x }))
      })
      break
    }
    case 'distributeV': {
      const sorted = [...targets].sort((a, b) => a.y - b.y)
      const step = (sorted[sorted.length - 1]!.y - sorted[0]!.y) / (sorted.length - 1)
      sorted.forEach((t, i) => {
        const y = sorted[0]!.y + step * i
        if (Math.abs(y - t.y) > 0.5) ops.push(patch(t, { y }))
      })
      break
    }
    case 'toFirst': {
      const ref = targets[0]!
      for (const t of targets.slice(1)) ops.push(patch(t, { x: ref.x, y: ref.y }))
      break
    }
    case 'toLast': {
      const ref = targets[targets.length - 1]!
      for (const t of targets.slice(0, -1)) ops.push(patch(t, { x: ref.x, y: ref.y }))
      break
    }
  }
  return ops
}

function patch(t: AlignTarget, data: Record<string, unknown>): BatchOp {
  return { action: 'patch', kind: t.kind, id: t.id, data }
}
