local g=require(script.Parent.symbols)local S=require(script.Parent.isAMagicMock)local K={}K.__index=K K.__call=function(g,...)return g.inner(...)end local o={}setmetatable(o,{__mode="\107\118"})function K.new(S)local U={[g.isSpy]=true;[g.Calls]={}}setmetatable(U,K)local s=function(...)local K={args=table.pack(...);result=table.pack(S(...))}table.insert(U[g.Calls],K)return table.unpack(K.result)end U.inner=s o[s]=U return U,s end function K.lookup(g)return o[g]end function K.is(K)if not S(K)then return type(K)=="\116\097\098\108\101"and K[g.isSpy]~=nil end return false end return K


local symbols = require(script.Parent.symbols)
local isAMagicMock = require(script.Parent.isAMagicMock)

local Spy = {}
Spy.__index = Spy
Spy.__call = function(self, ...)
	return self.inner(...)
end

local spyLookup = {}
setmetatable(spyLookup, {__mode = "kv"})

function Spy.new(inner)
	local spy = {
		[symbols.isSpy] = true,
		[symbols.Calls] = {}
	}
	setmetatable(spy, Spy)

	local wrapper = function(...)
		local call = {
			args = table.pack(...),
			result = table.pack(inner(...)),
		}
		table.insert(spy[symbols.Calls], call)
		return table.unpack(call.result)
	end

	spy.inner = wrapper
	spyLookup[wrapper] = spy

	return spy, wrapper
end

function Spy.lookup(wrapper)
	return spyLookup[wrapper]
end

function Spy.is(object)
	if not isAMagicMock(object) then
		return type(object) == "table" and object[symbols.isSpy] ~= nil
	end

	return false
end

return Spy
