-- Generate a string that will highlight the difference between two values
-- with green and red. (similar to how github does code diffing)
-- eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types

local function diff(a: any, b: any, options: DiffOptions?): string?
	if Object.is(a, b) then
		return getCommonMessage(NO_DIFF_MESSAGE, options)
	end

	local aType = getType(a)
	local expectedType = aType
	local omitDifference = false

	if aType == "table" and getType(a.asymmetricMatch) == "function" then
		if a["$$typeof"] ~= Symbol.for_("jest.asymmetricMatcher") then
			-- Do not know expected type of user-defined asymmetric matcher.
			return nil
		end
		if typeof(a.getExpectedType) ~= "function" then
			-- For example, expect.anything() matches either null or undefined
			return nil
		end
		expectedType = a:getExpectedType()
		-- Primitive types boolean and number omit difference below.
		-- For example, omit difference for expect.stringMatching(regexp)
		omitDifference = expectedType == "string"
	end

	if expectedType ~= getType(b) then
		return string.format(
			"  Comparing two different types of values." .. " Expected %s but " .. "received %s.",
			chalk.green(expectedType),
			chalk.red(getType(b))
		)
	end

	if omitDifference then
		return nil
	end

	if aType == "string" then
		return diffLinesUnified(string.split(a, "\n"), string.split(b, "\n"), options)
	elseif aType == "boolean" or aType == "number" then
		return comparePrimitive(a, b, options)
		-- ROBLOX deviation: omitted, no ordered tables in lua
		-- elseif aType == 'table' then
		-- 	return compareObjects(sortTable(a), sortTable(b), options)
	end
	return compareObjects(a, b, options)
end

function comparePrimitive(a: number | boolean, b: number | boolean, options: DiffOptions?)
	local aFormat = prettyFormat(a, FORMAT_OPTIONS)
	local bFormat = prettyFormat(b, FORMAT_OPTIONS)
	if aFormat == bFormat then
		return getCommonMessage(NO_DIFF_MESSAGE, options)
	end
	return diffLinesUnified(string.split(aFormat, "\n"), string.split(bFormat, "\n"), options)
end
