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

/**
 * 站点批量生成器：横向 / 纵向 / 矩阵 / 沿路径 / 环形阵列。
 * 每个函数返回 batch ops 列表，调用方再 `mapEditApi.batch(ops)` 一次落地，
 * 同时把这条命令塞进 useHistory 栈实现整体撤销。
 *
 * 坐标单位毫米；沿路径采样用直线段近似（贝塞尔 / 弧线后续可改为参数化采样）。
 */

export interface LinearGenOpts {
  count: number
  layer?: string
  namePrefix?: string
}

/** 横向：从 (x1, y) → (x2, y) 等距生成 count 个站点（含两端）。 */
export function genLinearH(x1: number, x2: number, y: number, opts: LinearGenOpts): BatchOp[] {
  return genLinear(x1, y, x2, y, opts)
}

export function genLinearV(x: number, y1: number, y2: number, opts: LinearGenOpts): BatchOp[] {
  return genLinear(x, y1, x, y2, opts)
}

function genLinear(x1: number, y1: number, x2: number, y2: number, opts: LinearGenOpts): BatchOp[] {
  const ops: BatchOp[] = []
  const n = Math.max(2, Math.floor(opts.count))
  for (let i = 0; i < n; i++) {
    const t = i / (n - 1)
    const data: CreateSitePayload = {
      x: x1 + (x2 - x1) * t,
      y: y1 + (y2 - y1) * t,
      name: `${opts.namePrefix ?? 'S'}_${i + 1}`,
      layer: opts.layer
    }
    ops.push({ action: 'create', kind: 'site', data: data as unknown as Record<string, unknown> })
  }
  return ops
}

export interface MatrixGenOpts {
  rows: number
  cols: number
  layer?: string
  namePrefix?: string
}

export function genMatrix(x1: number, y1: number, x2: number, y2: number, opts: MatrixGenOpts): BatchOp[] {
  const ops: BatchOp[] = []
  const rows = Math.max(1, Math.floor(opts.rows))
  const cols = Math.max(1, Math.floor(opts.cols))
  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      const tx = cols === 1 ? 0 : c / (cols - 1)
      const ty = rows === 1 ? 0 : r / (rows - 1)
      ops.push({
        action: 'create',
        kind: 'site',
        data: {
          x: x1 + (x2 - x1) * tx,
          y: y1 + (y2 - y1) * ty,
          name: `${opts.namePrefix ?? 'M'}_${r + 1}_${c + 1}`,
          layer: opts.layer
        } as unknown as Record<string, unknown>
      })
    }
  }
  return ops
}

export interface CircularGenOpts {
  count: number
  layer?: string
  namePrefix?: string
  startAngleDeg?: number
  endAngleDeg?: number
}

export function genCircular(cx: number, cy: number, radius: number, opts: CircularGenOpts): BatchOp[] {
  const ops: BatchOp[] = []
  const n = Math.max(1, Math.floor(opts.count))
  const start = ((opts.startAngleDeg ?? 0) * Math.PI) / 180
  const end = ((opts.endAngleDeg ?? 360) * Math.PI) / 180
  const span = end - start
  for (let i = 0; i < n; i++) {
    // 闭合环：end-start = 2π 时不要把第 0 个与第 n 个重叠
    const denom = Math.abs(span - Math.PI * 2) < 1e-6 ? n : n - 1
    const t = denom === 0 ? 0 : i / denom
    const a = start + span * t
    ops.push({
      action: 'create',
      kind: 'site',
      data: {
        x: cx + Math.cos(a) * radius,
        y: cy + Math.sin(a) * radius,
        name: `${opts.namePrefix ?? 'C'}_${i + 1}`,
        layer: opts.layer
      } as unknown as Record<string, unknown>
    })
  }
  return ops
}

export interface AlongPathGenOpts {
  /** 路径折线点数组：[x, y, x, y, ...]。 */
  polyline: number[]
  /** 站点之间间距 mm，过密会自动按总长度调整。 */
  stepMm: number
  layer?: string
  namePrefix?: string
}

export function genAlongPath(opts: AlongPathGenOpts): BatchOp[] {
  const pts: number[][] = []
  const p = opts.polyline
  if (p.length < 4) return []
  for (let i = 0; i < p.length; i += 2) pts.push([p[i]!, p[i + 1]!])

  const seg = [] as { x1: number; y1: number; x2: number; y2: number; len: number }[]
  let total = 0
  for (let i = 0; i < pts.length - 1; i++) {
    const [x1, y1] = pts[i]!
    const [x2, y2] = pts[i + 1]!
    const len = Math.hypot(x2 - x1, y2 - y1)
    seg.push({ x1: x1!, y1: y1!, x2: x2!, y2: y2!, len })
    total += len
  }
  if (total < 1) return []

  const step = Math.max(1, opts.stepMm)
  const ops: BatchOp[] = []
  let traveled = 0
  let sIdx = 0
  let nameIdx = 1
  while (traveled <= total + 1e-3) {
    while (sIdx < seg.length && traveled > (seg[sIdx]!.len + accumulatedUpTo(seg, sIdx))) sIdx++
    if (sIdx >= seg.length) break
    const s = seg[sIdx]!
    const baseTraveled = accumulatedUpTo(seg, sIdx)
    const local = traveled - baseTraveled
    const t = s.len === 0 ? 0 : local / s.len
    ops.push({
      action: 'create',
      kind: 'site',
      data: {
        x: s.x1 + (s.x2 - s.x1) * t,
        y: s.y1 + (s.y2 - s.y1) * t,
        name: `${opts.namePrefix ?? 'P'}_${nameIdx}`,
        layer: opts.layer
      } as unknown as Record<string, unknown>
    })
    nameIdx++
    traveled += step
  }
  return ops
}

function accumulatedUpTo(seg: { len: number }[], idx: number) {
  let s = 0
  for (let i = 0; i < idx; i++) s += seg[i]!.len
  return s
}
