import type { Iwt2ArenaBounds, Iwt2Vec2 } from './types'

export const IWT2_ZERO_VECTOR: Iwt2Vec2 = { x: 0, y: 0 }

export function addVec2(a: Iwt2Vec2, b: Iwt2Vec2): Iwt2Vec2 {
  return { x: a.x + b.x, y: a.y + b.y }
}

export function subtractVec2(a: Iwt2Vec2, b: Iwt2Vec2): Iwt2Vec2 {
  return { x: a.x - b.x, y: a.y - b.y }
}

export function scaleVec2(vector: Iwt2Vec2, scale: number): Iwt2Vec2 {
  return { x: vector.x * scale, y: vector.y * scale }
}

export function dotVec2(a: Iwt2Vec2, b: Iwt2Vec2): number {
  return a.x * b.x + a.y * b.y
}

export function lengthSqVec2(vector: Iwt2Vec2): number {
  return dotVec2(vector, vector)
}

export function lengthVec2(vector: Iwt2Vec2): number {
  return Math.sqrt(lengthSqVec2(vector))
}

export function distanceVec2(a: Iwt2Vec2, b: Iwt2Vec2): number {
  return lengthVec2(subtractVec2(a, b))
}

export function normalizeVec2(vector: Iwt2Vec2): Iwt2Vec2 {
  const length = lengthVec2(vector)
  if (length <= 0.0001) return { ...IWT2_ZERO_VECTOR }
  return { x: vector.x / length, y: vector.y / length }
}

export function clamp(value: number, min: number, max: number): number {
  return Math.min(max, Math.max(min, value))
}

export function clampVec2ToArena(position: Iwt2Vec2, radius: number, bounds: Iwt2ArenaBounds): Iwt2Vec2 {
  return {
    x: clamp(position.x, radius, bounds.width - radius),
    y: clamp(position.y, radius, bounds.height - radius),
  }
}

export function moveToward(current: Iwt2Vec2, target: Iwt2Vec2, maxDistance: number): Iwt2Vec2 {
  const offset = subtractVec2(target, current)
  const distance = lengthVec2(offset)
  if (distance <= maxDistance || distance <= 0.0001) return { ...target }
  return addVec2(current, scaleVec2(offset, maxDistance / distance))
}

export function withFallbackFacing(nextFacing: Iwt2Vec2, fallback: Iwt2Vec2): Iwt2Vec2 {
  if (lengthSqVec2(nextFacing) <= 0.0001) return { ...fallback }
  return normalizeVec2(nextFacing)
}
