-- The optional property of matcher context is true if undefined.

function isExpand(expand: boolean?)
	return expand ~= false
end

local PRINT_LIMIT = 3

local NO_ARGUMENTS = "called with 0 arguments"

function printExpectedArgs(expected: Array<any>): string
	if #expected == 0 then
		return NO_ARGUMENTS
	else
		return Array.join(
			Array.map(expected, function(arg)
				return printExpected(arg)
			end),
			", "
		)
	end
end

function printReceivedArgs(received: Array<any>, expected: Array<any>): string
	if #received == 0 then
		return NO_ARGUMENTS
	else
		return Array.join(
			Array.map(received, function(arg, i)
				if Array.isArray(expected) and i <= #expected and isEqualValue(expected[i], arg) then
					return printCommon(arg)
				else
					return printReceived(arg)
				end
			end),
			", "
		)
	end
end

function printCommon(val: any)
	return DIM_COLOR(stringify(val))
end

function isEqualValue(expected: any, received: any): boolean
	return equals(expected, received, { iterableEquality })
end

function isEqualCall(expected: Array<any>, received: Array<any>): boolean
	return isEqualValue(expected, received)
end

function isEqualReturn(expected, result): boolean
	return result.type == "return" and isEqualValue(expected, result.value)
end

function countReturns(results: Array<any>): number
	return Array.reduce(results, function(n: number, result: any)
		if result.type == "return" then
			return n + 1
		else
			return n
		end
	end, 0)
end

function printNumberOfReturns(countReturns_: number, countCalls: number): string
	local retval = string.format("\nNumber of returns: %s", printReceived(countReturns_))
	if countCalls ~= countReturns_ then
		retval = retval .. string.format("\nNumber of calls:   %s", printReceived(countCalls))
	end

	return retval
end

type PrintLabel = (string, boolean) -> string
