local ____exports = {}
local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
local Direction = ____isaac_2Dtypescript_2Ddefinitions.Direction
local ____direction = require("functions.direction")
local directionToVector = ____direction.directionToVector
--- Helper function to normalize a number, ensuring that it is within a certain range.
-- 
-- - If `num` is less than `min`, then it will be clamped to `min`.
-- - If `num` is greater than `max`, then it will be clamped to `max`.
function ____exports.clamp(self, num, min, max)
    return math.max(
        min,
        math.min(num, max)
    )
end
function ____exports.getAngleDifference(self, angle1, angle2)
    local subtractedAngle = angle1 - angle2
    return (subtractedAngle + 180) % 360 - 180
end
--- Helper function to get an array of equidistant points on the circumference around a circle.
-- Useful for equally distributing things in a circle pattern.
-- 
-- @param centerPos A position that represents the center of the center to get the points from.
-- @param radius The radius of the circle.
-- @param numPoints The number of points on the circumference of the circle to get.
-- @param xMultiplier An optional multiplier to get the points around an oval. Default is 1.
-- @param yMultiplier An optional multiplier to get the points around an oval. Default is 1.
-- @param initialDirection By default, the first point on the circle will be on the top center, but
-- this can be optionally changed by specifying this argument.
function ____exports.getCircleDiscretizedPoints(self, centerPos, radius, numPoints, xMultiplier, yMultiplier, initialDirection)
    if xMultiplier == nil then
        xMultiplier = 1
    end
    if yMultiplier == nil then
        yMultiplier = 1
    end
    if initialDirection == nil then
        initialDirection = Direction.UP
    end
    local vector = directionToVector(nil, initialDirection)
    local initialPosition = vector * radius
    local positions = {}
    do
        local i = 0
        while i < numPoints do
            local rotatedPosition = initialPosition:Rotated(i * 360 / numPoints)
            rotatedPosition.X = rotatedPosition.X * xMultiplier
            rotatedPosition.Y = rotatedPosition.Y * yMultiplier
            local positionFromCenter = centerPos + rotatedPosition
            positions[#positions + 1] = positionFromCenter
            i = i + 1
        end
    end
    return positions
end
--- Helper function to check if a given position is within a given rectangle.
-- 
-- This is an inclusive check, meaning that it will return true if the position is on the border of
-- the rectangle.
function ____exports.inRectangle(self, position, topLeft, bottomRight)
    return position.X >= topLeft.X and position.X <= bottomRight.X and position.Y >= topLeft.Y and position.Y <= bottomRight.Y
end
--- From: https://www.geeksforgeeks.org/check-if-any-point-overlaps-the-given-circle-and-rectangle/
function ____exports.isCircleIntersectingRectangle(self, circleCenter, circleRadius, rectangleTopLeft, rectangleBottomRight)
    local nearestX = math.max(
        rectangleTopLeft.X,
        math.min(circleCenter.X, rectangleBottomRight.X)
    )
    local nearestY = math.max(
        rectangleTopLeft.Y,
        math.min(circleCenter.Y, rectangleBottomRight.Y)
    )
    local nearestPointToCircleOnRectangle = Vector(nearestX, nearestY)
    local distanceToCenterOfCircle = nearestPointToCircleOnRectangle:Distance(circleCenter)
    return distanceToCenterOfCircle <= circleRadius
end
function ____exports.isEven(self, num)
    return num & 1 == 0
end
function ____exports.isOdd(self, num)
    return num & 1 == 1
end
function ____exports.lerp(self, a, b, pos)
    return a + (b - a) * pos
end
function ____exports.lerpAngleDegrees(self, aStart, aEnd, percent)
    return aStart + ____exports.getAngleDifference(nil, aStart, aEnd) * percent
end
--- If rounding fails, this function returns 0.
-- 
-- From: http://lua-users.org/wiki/SimpleRound
-- 
-- @param num The number to round.
-- @param numDecimalPlaces Optional. Default is 0.
function ____exports.round(self, num, numDecimalPlaces)
    if numDecimalPlaces == nil then
        numDecimalPlaces = 0
    end
    local roundedNum = tonumber(string.format(
        ("%." .. tostring(numDecimalPlaces)) .. "f",
        num
    ))
    return roundedNum or 0
end
---
-- @returns 1 if n is positive, -1 if n is negative, or 0 if n is 0.
function ____exports.sign(self, n)
    if n > 0 then
        return 1
    end
    if n < 0 then
        return -1
    end
    return 0
end
--- Breaks a number into chunks of a given size. This is similar to the `String.split` method, but
-- for a number instead of a string.
-- 
-- For example, `splitNumber(90, 25)` would return an array with four elements:
-- 
-- - [1, 25]
-- - [26, 50]
-- - [51, 75]
-- - [76, 90]
-- 
-- @param num The number to split into chunks. This must be a positive integer.
-- @param size The size of each chunk. This must be a positive integer.
-- @param startAtZero Whether to start at 0. Defaults to false. If true, the chunks will start at 0
-- instead of 1.
function ____exports.splitNumber(self, num, size, startAtZero)
    if startAtZero == nil then
        startAtZero = false
    end
    if num <= 0 then
        error("The number to split needs to be a positive number and is instead: " .. tostring(num))
    end
    if size <= 0 then
        error("The size to split needs to be a positive number and is instead: " .. tostring(num))
    end
    local chunks = {}
    local start = startAtZero and 0 or 1
    while start <= num do
        local ____end = math.min(start + size - 1, num)
        chunks[#chunks + 1] = {start, ____end}
        start = start + size
    end
    return chunks
end
function ____exports.tanh(self, x)
    return (math.exp(x) - math.exp(-x)) / (math.exp(x) + math.exp(-x))
end
return ____exports
