extend("test")
extend("math")

describe("math:pow usage", () => {
  it("computes integer exponentiation as float", () => {
    expect_equal(math:pow(2, 3), 8.0)
    expect_equal(math:pow(5, 0), 1.0)
    expect_equal(math:pow(9, 0.5), 3.0)
  })

  it("handles negative base and fractional exponent", () => {
    expect_equal(math:pow(-4, 2), 16.0)
    # negative base with odd exponent
    expect_equal(math:pow(-2, 3), -8.0)
  })

  it("supports partial application for base", () => {
    pow2 = math:pow(2)
    expect_equal(pow2(4), 16.0)
  })

  it("supports partial application for exponent", () => {
    cube = math:pow(_, 3)
    expect_equal(cube(2), 8.0)
    expect_equal(cube(10), 1000.0)
  })

  it("supports double placeholder for both arguments", () => {
    pow_partial = math:pow(_, _)
    expect_equal(pow_partial(3, 4), 81.0)
  })
})

describe("math:mod usage", () => {
  it("returns the modulo for two ints", () => {
    expect_equal(math:mod(10, 3), 1)
    expect_equal(math:mod(25, 5), 0)
    expect_equal(math:mod(-7, 4), -3)
  })

  it("supports partial application (dividend)", () => {
    mod10 = math:mod(_, 10)
    expect_equal(mod10(37), 7)
  })

  it("supports partial application (divisor)", () => {
    modBy3 = math:mod(20)
    expect_equal(modBy3(6), 2)
  })

  it("supports double placeholder for both arguments", () => {
    mod_partial = math:mod(_, _)
    expect_equal(mod_partial(17, 6), 5)
  })

  it("returns error on divide by zero", () => {
    test:expect_error(() => math:mod(10, 0))
    test:expect_error(() => math:mod(_, 0)(100))
  })
})

describe("math:rotate_point usage", () => {
  it("rotates a point (1, 0) by 90 degrees (pi/2 radians)", () => {
    res = math:rotate_point(1, 0, 1.5707963267948966)  # pi/2
    # Should be approximately [0, 1]
    expect_equal(type(res), "float_array")
    expect_equal(res[0] > -1e-6 && res[0] < 1e-6, true)
    expect_equal(res[1] > 0.99999 && res[1] < 1.00001, true)
  })

  it("supports partial usage for (x,y), then rad", () => {
    rotate_origin = math:rotate_point(0, 1)
    out = rotate_origin(3.141592653589793) # pi radians
    # (0,1) rotated 180 degrees should be (0,-1)
    expect_equal(out[0] > -1e-6 && out[0] < 1e-6, true)
    expect_equal(out[1] > -1.00001 && out[1] < -0.99999, true)
  })

  it("supports placeholder usage for all arguments", () => {
    partial_all = math:rotate_point(_, _, _)
    expect_equal(
      partial_all(1, 0, 3.141592653589793),  # pi radians
      [-1.0, 0.0]
    )
  })

  it("supports mix of known/unknown arguments", () => {
    rotate90 = math:rotate_point(_, _, 1.5707963267948966)
    expect_equal(rotate90(0, 2)[0] > -1e-6 && rotate90(0, 2)[0] < 1e-6, true)
    expect_equal(rotate90(0, 2)[1] > -2.00001 && rotate90(0, 2)[1] < -1.99999, false) # Should be [~0,2]
  })

  it("errors if passed the wrong types", () => {
    test:expect_error(() => math:rotate_point("x", 1, 2))
    test:expect_error(() => math:rotate_point(1, "y", 2))
    test:expect_error(() => math:rotate_point(1, 2, "rad"))
  })
})

