-- Sometimes, e.g. when comparing two numbers, the output from jest-diff
-- does not contain more information than the 'Expected:' / 'Received:' already gives.
-- In those cases, we do not print a diff to make the output shorter and  not redundant.

function shouldPrintDiff(actual: any, expected: any)
	if typeof(actual) == "number" and typeof(expected) == "number" then
		return false
	end

	-- ROBLOX deviation: excluded if statement checking bigint types

	if typeof(actual) == "boolean" and typeof(expected) == "boolean" then
		return false
	end

	return true
end

function replaceMatchedToAsymmetricMatcher(
	replacedExpected: any,
	replacedReceived: any,
	expectedCycles: Array<any>,
	receivedCycles: Array<any>
)
	if not Replaceable.isReplaceable(replacedExpected, replacedReceived) then
		return {
			replacedExpected = replacedExpected,
			replacedReceived = replacedReceived,
		}
	end

	if
		Array.indexOf(expectedCycles, replacedExpected) ~= -1
		or Array.indexOf(receivedCycles, replacedReceived) ~= -1
	then
		return {
			replacedExpected = replacedExpected,
			replacedReceived = replacedReceived,
		}
	end

	table.insert(expectedCycles, replacedExpected)
	table.insert(receivedCycles, replacedReceived)

	local expectedReplaceable = Replaceable.new(replacedExpected)
	local receivedReplaceable = Replaceable.new(replacedReceived)

	expectedReplaceable:forEach(function(expectedValue: any, key: any)
		local receivedValue = receivedReplaceable:get(key)
		if isAsymmetricMatcher(expectedValue) then
			if expectedValue:asymmetricMatch(receivedValue) then
				receivedReplaceable:set(key, expectedValue)
			end
		elseif isAsymmetricMatcher(receivedValue) then
			if receivedValue:asymmetricMatch(expectedValue) then
				expectedReplaceable:set(key, receivedValue)
			end
		elseif Replaceable.isReplaceable(expectedValue, receivedValue) then
			local replaced = replaceMatchedToAsymmetricMatcher(
				expectedValue,
				receivedValue,
				expectedCycles,
				receivedCycles
			)
			expectedReplaceable:set(key, replaced.replacedExpected)
			receivedReplaceable:set(key, replaced.replacedReceived)
		end
	end)

	return {
		replacedExpected = expectedReplaceable.object,
		replacedReceived = receivedReplaceable.object,
	}
end
