-- ROBLOX deviation: matchers does not have MatchersObject type annotation and expect
-- does not have Expect type annotation
--[[
	ROBLOX TODO: add default generic param when possible
	original code:
	export const setMatchers = <State extends MatcherState = MatcherState>(
]]

local function setMatchers<State>(matchers: MatchersObject<State>, isInternal: boolean, expect): ()
	for key, matcher in pairs(matchers) do
		-- ROBLOX TODO: assign INTERNAL_MATCHER_FLAG to matchers
		if not isInternal then
			local CustomMatcher = {}
			CustomMatcher.__index = CustomMatcher
			setmetatable(CustomMatcher, AsymmetricMatcher)

			CustomMatcher.new = function(inverse: boolean?, ...)
				inverse = if inverse ~= nil then inverse else false
				local self = AsymmetricMatcher.new({ ... }, inverse)
				setmetatable(self, CustomMatcher)
				return self
			end

			CustomMatcher.asymmetricMatch = function(self, other: any)
				local pass = matcher(self:getMatcherContext(), other, unpack(self.sample)).pass

				return if self.inverse then not pass else pass
			end

			CustomMatcher.toString = function(self)
				if self.inverse then
					return string.format("never.%s", key)
				end
				return tostring(key)
			end

			CustomMatcher.getExpectedType = function(self)
				return "any"
			end

			CustomMatcher.toAsymmetricMatcher = function(self)
				local sample = self.sample
				local i = 1
				local printval = ""
				while i < #sample do
					printval = printval .. tostring(sample[i]) .. ", "
					i += 1
				end
				printval = printval .. tostring(sample[i])
				return string.format("%s<%s>", self:toString(), printval)
			end

			-- ROBLOX deviation start: there is not Object.defineProperty equivalent in Lua
			expect[key] = function(...)
				return CustomMatcher.new(false, ...)
			end
			if not expect.never then
				expect.never = {}
			end
			expect.never[key] = function(...)
				return CustomMatcher.new(true, ...)
			end
			-- ROBLOX deviation end
		end
	end

	Object.assign(_G[JEST_MATCHERS_OBJECT].matchers, matchers)
end

return {
	INTERNAL_MATCHER_FLAG = INTERNAL_MATCHER_FLAG,
	getState = getState,
	setState = setState,
	getMatchers = getMatchers,
	setMatchers = setMatchers,
}
