-- ROBLOX deviation: Roblox Instance matchers

local function toMatchInstance(
	-- ROBLOX deviation: self param in Lua needs to be explicitely defined
	self: MatcherState,
	received: any,
	expected: any
)
	local matcherName = "toMatchInstance"
	local options: MatcherHintOptions = {
		isNot = self.isNot,
		promise = self.promise,
	}

	if getType(received) ~= "Instance" or received == nil then
		error(
			Error(
				matcherErrorMessage(
					matcherHint(matcherName, nil, nil, options),
					string.format("%s value must be a Roblox Instance", RECEIVED_COLOR("received")),
					printWithType("Received", received, printReceived)
				)
			)
		)
	end

	if typeof(expected) ~= "table" or expected == nil then
		error(
			Error(
				matcherErrorMessage(
					matcherHint(matcherName, nil, nil, options),
					string.format("%s value must be a table", EXPECTED_COLOR("expected")),
					printWithType("Expected", expected, printExpected)
				)
			)
		)
	end

	local pass = equals(received, expected, { instanceSubsetEquality })

	local message
	if pass then
		message = function()
			local retval = matcherHint(matcherName, nil, nil, options)
				.. "\n\n"
				.. string.format("Expected: never %s", printExpected(expected))
			if stringify(expected) ~= stringify(received) then
				return retval .. string.format("\nReceived:       %s", printReceived(received))
			end
			return retval
		end
	else
		local receivedSubset, expectedSubset = getInstanceSubset(received, expected)
		message = function()
			return matcherHint(matcherName, nil, nil, options)
				.. "\n\n"
				.. printDiffOrStringify(
					expectedSubset,
					receivedSubset,
					EXPECTED_LABEL,
					RECEIVED_LABEL,
					isExpand(self.expand)
				)
		end
	end

	return { message = message, pass = pass }
end

local matchers: MatchersObject = {
	toBe = toBe,
	toBeCloseTo = toBeCloseTo,
	toBeDefined = toBeDefined,
	toBeFalsy = toBeFalsy,
	toBeGreaterThan = toBeGreaterThan,
	toBeGreaterThanOrEqual = toBeGreaterThanOrEqual,
	toBeInstanceOf = toBeInstanceOf,
	toBeLessThan = toBeLessThan,
	toBeLessThanOrEqual = toBeLessThanOrEqual,
	toBeNan = toBeNan,
	toBeNaN = toBeNan, -- ROBLOX deviation: aliased to toBeNan
	toBeNil = toBeNil,
	toBeNull = toBeNil, -- ROBLOX deviation: aliased to toBeNil
	toBeTruthy = toBeTruthy,
	toBeUndefined = toBeUndefined,
	toContain = toContain,
	toContainEqual = toContainEqual,
	toEqual = toEqual,
	toHaveLength = toHaveLength,
	toHaveProperty = toHaveProperty,
	toMatch = toMatch,
	toMatchObject = toMatchObject,
	toStrictEqual = toStrictEqual,

	-- ROBLOX deviation: Roblox Instance matchers
	toMatchInstance = toMatchInstance,
}

return matchers
