local ____lualib = require("lualib_bundle")
local __TS__ArraySlice = ____lualib.__TS__ArraySlice
local ____exports = {}
local ____types = require("functions.types")
local isNumber = ____types.isNumber
local isString = ____types.isString
local isTable = ____types.isTable
local function sortNormal(self, a, b)
    if not isNumber(nil, a) and not isString(nil, a) then
        error("Failed to normal sort since the first value was not a number or string and was instead: " .. type(a))
    end
    if not isNumber(nil, b) and not isString(nil, b) then
        error("Failed to normal sort since the second value was not a number or string and was instead: " .. type(b))
    end
    if a < b then
        return -1
    end
    if a > b then
        return 1
    end
    return 0
end
--- Helper function to sort an array of objects by one of the object keys.
-- 
-- For example:
-- 
-- ```ts
-- const myArray = [
--   {
--     name: "alice",
--     age: 30,
--   },
--   {
--     name: "bob",
--     age: 20,
--   },
-- ];
-- myArray.sort(sortObjectArrayByKey("age"));
-- ```
function ____exports.sortObjectArrayByKey(self, key)
    return function(____, a, b)
        if not isTable(nil, a) then
            error((("Failed to sort an object array by the key of \"" .. key) .. "\" since the first element was not a table and was instead: ") .. type(a))
        end
        if not isTable(nil, b) then
            error(((("Failed to sort an object array by the key of \"" .. key) .. "\" since the second element was not a table and was instead: ") .. type(b)) .. ".")
        end
        local aValue = a[key]
        local bValue = b[key]
        return sortNormal(nil, aValue, bValue)
    end
end
--- Helper function to sort a two-dimensional array by the first element.
-- 
-- For example:
-- 
-- ```ts
-- const myArray = [[1, 2], [2, 3], [3, 4]];
-- myArray.sort(twoDimensionalSort);
-- ```
-- 
-- This function also properly handles when the array elements are strings or numbers (instead of
-- another array).
-- 
-- From:
-- https://stackoverflow.com/questions/16096872/how-to-sort-2-dimensional-array-by-column-value
function ____exports.sortTwoDimensionalArray(self, a, b)
    local aType = type(a)
    local bType = type(b)
    if aType ~= bType then
        error(((((((("Failed to two-dimensional sort since the two elements were disparate types: " .. tostring(a)) .. " & ") .. tostring(b)) .. " (") .. aType) .. " & ") .. bType) .. ")")
    end
    if aType == "string" or aType == "number" then
        return sortNormal(nil, a, b)
    end
    if aType ~= "table" then
        error("Failed to two-dimensional sort since the first element was not a string, number, or table.")
    end
    if bType ~= "table" then
        error("Failed to two-dimensional sort since the second element was not a string, number, or table.")
    end
    local firstElement1 = a[1]
    local firstElement2 = b[1]
    if firstElement1 == nil or firstElement1 == nil then
        error("Failed to two-dimensional sort since the first element of the first array was undefined.")
    end
    if firstElement2 == nil or firstElement2 == nil then
        error("Failed to two-dimensional sort since the first element of the second array was undefined.")
    end
    local elementType1 = type(firstElement1)
    local elementType2 = type(firstElement2)
    if elementType1 ~= elementType2 then
        error(((((((("Failed to two-dimensional sort since the first element of each array were disparate types: " .. tostring(firstElement1)) .. " & ") .. tostring(firstElement2)) .. " (") .. elementType1) .. " & ") .. elementType2) .. ")")
    end
    return sortNormal(nil, firstElement1, firstElement2)
end
--- Helper function to sort an array in a stable way.
-- 
-- This is useful because by default, the transpiled `Array.sort` method from TSTL is not stable.
-- 
-- Under the hood, this uses the merge sort algorithm.
function ____exports.stableSort(self, array, sortFunc)
    if sortFunc == nil then
        sortFunc = sortNormal
    end
    if #array <= 1 then
        return array
    end
    local middleIndex = math.floor(#array / 2)
    local leftArray = __TS__ArraySlice(array, 0, middleIndex)
    local rightArray = __TS__ArraySlice(array, middleIndex)
    local sortedLeftArray = ____exports.stableSort(nil, leftArray, sortFunc)
    local sortedRightArray = ____exports.stableSort(nil, rightArray, sortFunc)
    local mergedArray = {}
    local leftIndex = 0
    local rightIndex = 0
    while leftIndex < #sortedLeftArray and rightIndex < #sortedRightArray do
        local left = sortedLeftArray[leftIndex + 1]
        local right = sortedRightArray[rightIndex + 1]
        local sortResult = sortFunc(nil, left, right)
        if sortResult == -1 or sortResult == 0 then
            mergedArray[#mergedArray + 1] = left
            leftIndex = leftIndex + 1
        else
            mergedArray[#mergedArray + 1] = right
            rightIndex = rightIndex + 1
        end
    end
    while leftIndex < #sortedLeftArray do
        local left = sortedLeftArray[leftIndex + 1]
        mergedArray[#mergedArray + 1] = left
        leftIndex = leftIndex + 1
    end
    while rightIndex < #sortedRightArray do
        local right = sortedRightArray[rightIndex + 1]
        mergedArray[#mergedArray + 1] = right
        rightIndex = rightIndex + 1
    end
    return mergedArray
end
return ____exports
