///|
/// Q16.16 定点数。
///
/// 为什么需要它:回滚同步要求「同一串输入在任何后端、任何 CPU 上产生逐位相同的轨迹」。
/// 浮点运算在 `js` 与 `wasm-gc` 上实测一致(见 README),但 native 与跨平台仍受
/// 编译器优化与 FMA 收缩影响。`Fixed` 用整数运算,语义由 MoonBit 的 Int64 保证,
/// 不依赖任何浮点库。
///
/// 内部表示:`v = value * 65536`。所有中间运算走 Int64,
/// 因此实际可用范围是 Int32 区间,约 `[-32768, 32767]`。
pub struct Fixed {
  v : Int64
} derive(Eq)

///|
const FIXED_SCALE : Int64 = 65536L

///|
/// 从原始定点整数构造(`v = value * 65536`)。
pub fn Fixed::from_raw(v : Int64) -> Fixed {
  { v, }
}

///|
/// 取出原始定点整数,用于序列化与状态哈希。
pub fn Fixed::raw(self : Fixed) -> Int64 {
  self.v
}

///|
/// 整数 -> 定点数。
pub fn Fixed::from_int(value : Int) -> Fixed {
  { v: value.to_int64() * FIXED_SCALE }
}

///|
/// 浮点数 -> 定点数(四舍五入,仅用于初始化与测试,不参与模拟核心)。
pub fn Fixed::from_double(value : Double) -> Fixed {
  let scaled = value * 65536.0
  let rounded = if scaled >= 0.0 {
    (scaled + 0.5).to_int64()
  } else {
    (scaled - 0.5).to_int64()
  }
  { v: rounded }
}

///|
/// 定点数 -> 浮点数(仅用于渲染与打印,不参与模拟核心)。
pub fn Fixed::to_double(self : Fixed) -> Double {
  self.v.to_double() / 65536.0
}

///|
pub fn Fixed::abs(self : Fixed) -> Fixed {
  if self.v < 0L {
    { v: -self.v }
  } else {
    self
  }
}

///|
pub impl Neg for Fixed with fn neg(self) {
  { v: -self.v }
}

///|
pub impl Add for Fixed with fn add(self, other) {
  { v: self.v + other.v }
}

///|
pub impl Sub for Fixed with fn sub(self, other) {
  { v: self.v - other.v }
}

///|
pub impl Mul for Fixed with fn mul(self, other) {
  { v: (self.v * other.v) >> 16 }
}

///|
pub impl Div for Fixed with fn div(self, other) {
  { v: (self.v << 16) / other.v }
}

///|
pub impl Compare for Fixed with fn compare(self, other) -> Int {
  if self.v < other.v {
    -1
  } else if self.v > other.v {
    1
  } else {
    0
  }
}

///|
/// 整数平方根(牛顿迭代,纯整数,确定性)。
fn isqrt(n : Int64) -> Int64 {
  if n < 2L {
    return n
  }
  let mut x = n
  let mut y = (x + 1L) >> 1
  while y < x {
    x = y
    y = (x + n / x) >> 1
  }
  x
}

///|
/// 定点开方:`sqrt(x)` 仍是 Q16.16。
///
/// 推导:`sqrt(v / 2^16) * 2^16 = sqrt(v * 2^16)`,
/// 因此对 `v << 16` 求整数平方根即可。
pub fn Fixed::sqrt(self : Fixed) -> Fixed {
  if self.v <= 0L {
    return { v: 0L }
  }
  let n = self.v << 16
  let r = isqrt(n)
  // 四舍五入到最近的定点值:比较 r 与 r+1 谁更接近 sqrt(n)
  let below = n - r * r
  let above = (r + 1L) * (r + 1L) - n
  if above < below {
    { v: r + 1L }
  } else {
    { v: r }
  }
}

///|
/// 线性插值:`a + (b - a) * t`。
pub fn lerp(a : Fixed, b : Fixed, t : Fixed) -> Fixed {
  a + (b - a) * t
}

///|
pub fn clamp(value : Fixed, lo : Fixed, hi : Fixed) -> Fixed {
  if value < lo {
    lo
  } else if value > hi {
    hi
  } else {
    value
  }
}