/**
 * 军事钳形箭头多边形生成
 * 支持两种形态：
 * 1) 底宽头小 + 曲线轮廓 + 生长动画（单头）
 * 2) 集团军级三叉戟（Pro Tactical Trident）：22 点逻辑模型，基座→柄部收腰→三支独立箭指（左/右副箭 + 主箭），腋下回撤无自交
 */

export type LngLat = [number, number]

// ---------------------------------------------------------------------------
// 集团军级三叉戟（18 点一笔画）：基座 4 → 右颈 → 右副 3 → 右缝槽 → 主箭 3 → 左缝槽 → 左副 3 → 左颈 → 闭合
// 生长时 t>progress 则 offset 归零，前沿齐平防自交
// ---------------------------------------------------------------------------

/**
 * 18 点三叉戟：槽位在指缝 (0.4L)，左正右负；t>progress 时收束到 progress 中心线
 */
function createProTacticalTrident(
  start: LngLat,
  end: LngLat,
  progress: number
): LngLat[] {
  const [x1, y1] = start
  const dx = end[0] - x1
  const dy = end[1] - y1
  const L = Math.hypot(dx, dy) || 1e-6
  const nx = -dy / L
  const ny = dx / L

  const pt = (tAlong: number, nOffset: number): LngLat => {
    if (tAlong > progress) {
      return [x1 + dx * progress, y1 + dy * progress]
    }
    const lateral = nOffset * L
    return [x1 + dx * tAlong + nx * lateral, y1 + dy * tAlong + ny * lateral]
  }

  const GROOVE = 0.07

  return [
    pt(0, 0.15),
    pt(0.05, 0.16),
    pt(0.05, -0.16),
    pt(0, -0.15),
    pt(0.35, -0.05),
    pt(0.45, -0.12),
    pt(0.9, -0.18),
    pt(0.55, -0.06),
    pt(0.4, -GROOVE),
    pt(0.65, -0.04),
    pt(1, 0),
    pt(0.65, 0.04),
    pt(0.4, GROOVE),
    pt(0.55, 0.06),
    pt(0.9, 0.18),
    pt(0.45, 0.12),
    pt(0.35, 0.05),
    pt(0, 0.15),
  ]
}

export function createArmyGroupPincer(
  start: LngLat,
  end: LngLat,
  _prongCount: number = 3
): LngLat[] {
  return createProTacticalTrident(start, end, 1)
}

/**
 * 生长动画：progress 0→1，t>progress 时收束到中心线
 */
export function createArmyGroupPincerAtProgress(
  start: LngLat,
  end: LngLat,
  progress: number,
  _prongCount: number = 3
): LngLat[] {
  if (progress <= 0.02) {
    const [x1, y1] = start
    const dx = end[0] - x1
    const dy = end[1] - y1
    const L = Math.hypot(dx, dy) || 1e-6
    const nx = -dy / L
    const ny = dx / L
    const w = L * 0.15 * 0.5
    const left: LngLat = [x1 + nx * w, y1 + ny * w]
    const right: LngLat = [x1 - nx * w, y1 - ny * w]
    return [left, right, [x1, y1], left]
  }
  return createProTacticalTrident(start, end, progress)
}

// ---------------------------------------------------------------------------
// 单头钳形（底宽头小、曲线、生长）
// ---------------------------------------------------------------------------

export interface TacticalPincerOptions {
  /** 箭尾宽度系数（底宽），建议 0.04–0.1，默认 0.06 */
  widthFactor?: number
  /** 头部相对底部的宽度比（<1 即头小），默认 0.45 */
  headWidthRatio?: number
  /** 箭头头部占进攻方向向量的比例，默认 0.22 */
  headLengthRatio?: number
  /** 是否在箭体两侧用贝塞尔曲线平滑（底→肩），默认 true */
  curved?: boolean
  /** 曲线插值点数（每侧），默认 6 */
  curveSteps?: number
}

const DEFAULT_OPTS: Required<Omit<TacticalPincerOptions, 'curved'>> & { curved: boolean } = {
  widthFactor: 0.055,
  headWidthRatio: 0.48,
  headLengthRatio: 0.24,
  curved: true,
  curveSteps: 10,
}

/** 二次贝塞尔 B(t) = (1-t)²P0 + 2(1-t)t P1 + t² P2 */
function quadraticBezier(P0: LngLat, P1: LngLat, P2: LngLat, t: number): LngLat {
  const u = 1 - t
  return [
    u * u * P0[0] + 2 * u * t * P1[0] + t * t * P2[0],
    u * u * P0[1] + 2 * u * t * P1[1] + t * t * P2[1],
  ]
}

/** 在箭体两侧（左尾→左肩、右肩→右尾）插入贝塞尔曲线点，使轮廓柔和 */
function smoothRingWithCurves(
  ring: LngLat[],
  n: number,
  leftTail: LngLat,
  leftShoulder: LngLat,
  rightTail: LngLat,
  rightShoulder: LngLat,
  nx: number,
  ny: number
): LngLat[] {
  const curveBulge = 0.2
  // 左缘：leftTail -> leftShoulder，贝塞尔控制点向外凸出，箭体呈弧线
  const leftMid: LngLat = [
    (leftTail[0] + leftShoulder[0]) / 2 + nx * curveBulge,
    (leftTail[1] + leftShoulder[1]) / 2 + ny * curveBulge,
  ]
  const leftCurve: LngLat[] = []
  for (let i = 1; i <= n; i++) {
    leftCurve.push(quadraticBezier(leftTail, leftMid, leftShoulder, i / (n + 1)))
  }
  // 右缘：rightShoulder -> rightTail，控制点向外凸出
  const rightMid: LngLat = [
    (rightShoulder[0] + rightTail[0]) / 2 - nx * curveBulge,
    (rightShoulder[1] + rightTail[1]) / 2 - ny * curveBulge,
  ]
  const rightCurve: LngLat[] = []
  for (let i = 1; i <= n; i++) {
    rightCurve.push(quadraticBezier(rightShoulder, rightMid, rightTail, i / (n + 1)))
  }
  // Ring: 0 leftTail, 1 rightTail, 2 shoulderR, 3 barbR, 4 tip, 5 barbL, 6 shoulderL, 7 leftTail
  // 顺序：左尾 → 左曲线 → 左肩 → 左倒钩 → 顶点 → 右倒钩 → 右肩 → 右曲线 → 右尾 → 闭合
  const out: LngLat[] = [
    leftTail,
    ...leftCurve,
    leftShoulder,
    ring[5], // barbLeft
    ring[4], // tip
    ring[3], // barbRight
    rightShoulder,
    ...rightCurve,
    rightTail,
    leftTail,
  ]
  return out
}

function computeKeyPoints(
  start: LngLat,
  end: LngLat,
  progress: number,
  opts: Required<TacticalPincerOptions> & { curved: boolean }
): { ring: LngLat[]; nx: number; ny: number } {
  const [x1, y1] = start
  const dx = end[0] - x1
  const dy = end[1] - y1
  const tipX = x1 + progress * dx
  const tipY = y1 + progress * dy
  const headLen = opts.headLengthRatio
  const BbackX = tipX - headLen * dx
  const BbackY = tipY - headLen * dy

  const nx = -dy * opts.widthFactor
  const ny = dx * opts.widthFactor
  const headScale = opts.headWidthRatio

  const leftTail: LngLat = [x1 + nx, y1 + ny]
  const rightTail: LngLat = [x1 - nx, y1 - ny]
  const shoulderRight: LngLat = [BbackX - nx * headScale * 0.5, BbackY - ny * headScale * 0.5]
  const barbRight: LngLat = [BbackX - nx * headScale * 1.2, BbackY - ny * headScale * 1.2]
  const tip: LngLat = [tipX, tipY]
  const barbLeft: LngLat = [BbackX + nx * headScale * 1.2, BbackY + ny * headScale * 1.2]
  const shoulderLeft: LngLat = [BbackX + nx * headScale * 0.5, BbackY + ny * headScale * 0.5]

  const ring: LngLat[] = [
    leftTail,
    rightTail,
    shoulderRight,
    barbRight,
    tip,
    barbLeft,
    shoulderLeft,
    leftTail,
  ]
  return { ring, nx, ny }
}

/**
 * 生成军事钳形箭头（底宽头小、可选曲线）
 */
export function createTacticalPincer(
  start: LngLat,
  end: LngLat,
  widthFactor: number = DEFAULT_OPTS.widthFactor
): LngLat[] {
  return createTacticalPincerExplicit(start, end, { widthFactor })
}

export function createTacticalPincerExplicit(
  start: LngLat,
  end: LngLat,
  options: TacticalPincerOptions = {}
): LngLat[] {
  const opts = { ...DEFAULT_OPTS, ...options }
  const { ring, nx, ny } = computeKeyPoints(start, end, 1, opts as any)
  if (!opts.curved) return ring
  const steps = opts.curveSteps ?? 6
  return smoothRingWithCurves(
    ring,
    steps,
    ring[0],
    ring[6],
    ring[1],
    ring[2],
    nx,
    ny
  )
}

/**
 * 生长动画：progress 0→1 表示箭头从起点延伸到终点
 * progress < headLengthRatio 时画三角 stub，否则画完整箭头
 */
export function createTacticalPincerAtProgress(
  start: LngLat,
  end: LngLat,
  progress: number,
  options: TacticalPincerOptions = {}
): LngLat[] {
  const opts = { ...DEFAULT_OPTS, ...options }
  const [x1, y1] = start
  const dx = end[0] - x1
  const dy = end[1] - y1
  const tipX = x1 + progress * dx
  const tipY = y1 + progress * dy
  const nx = -dy * opts.widthFactor
  const ny = dx * opts.widthFactor

  if (progress <= 0.02) {
    const leftTail: LngLat = [x1 + nx * 0.5, y1 + ny * 0.5]
    const rightTail: LngLat = [x1 - nx * 0.5, y1 - ny * 0.5]
    return [leftTail, rightTail, [x1, y1], leftTail]
  }
  if (progress < opts.headLengthRatio) {
    const leftTail: LngLat = [x1 + nx, y1 + ny]
    const rightTail: LngLat = [x1 - nx, y1 - ny]
    const tip: LngLat = [tipX, tipY]
    return [leftTail, rightTail, tip, leftTail]
  }

  const { ring, nx: nxx, ny: nyy } = computeKeyPoints(start, end, progress, opts as any)
  if (!opts.curved) return ring
  const steps = opts.curveSteps ?? 6
  return smoothRingWithCurves(ring, steps, ring[0], ring[6], ring[1], ring[2], nxx, nyy)
}
