local m=require(script.Parent.Parent.TrueSignal)local q=require(script.Parent.prepArgs)local x={}x.__index=function(m,q)return rawget(x,q)or rawget(m,q)or m._internal[q]end x.__newindex=function(m,q,x)if q=="\079\110\067\108\105\101\110\116\073\110\118\111\107\101"then m._internal.OnClientInvoke=x for m,q in pairs(m._clientSignals)do q:fire(x(table.unpack(q.args)))q:destroy()end table.clear(m._clientSignals)elseif q=="\079\110\083\101\114\118\101\114\073\110\118\111\107\101"then m._internal.OnServerInvoke=x for q,L in pairs(m._serverSignals)do L:fire(x(m._client,table.unpack(L.args)))L:destroy()end table.clear(m._serverSignals)end end function x.new(m)local q={}q.destroyed=false q._client=m q._internal={}q._clientSignals={}q._serverSignals={}setmetatable(q,x)return q end function x.invokeServer(x,...)if x._internal.OnServerInvoke then return x._internal.OnServerInvoke(x._client,q(...))end local L=m.new()L.args=table.pack(q(...))table.insert(x._serverSignals,L)return L:wait()end function x.invokeClient(L,x,...)assert(x==L._client,"\073\110\118\097\108\105\100 \099\108\105\101\110\116 \112\097\115\115\101\100")if L._internal.OnClientInvoke then return L._internal.OnClientInvoke(q(...))end local E=m.new()E.args=table.pack(q(...))table.insert(L._clientSignals,E)return E:wait()end function x.getClient(m)return m._client end function x.destroy(m)for m,q in pairs(m._clientSignals)do q:destroy()end for m,q in pairs(m._serverSignals)do q:destroy()end m.destroyed=true end x.InvokeServer=x.invokeServer x.InvokeClient=x.invokeClient x.Destroy=x.destroy return x
local TrueSignal = require(script.Parent.Parent.TrueSignal)

local prepArgs = require(script.Parent.prepArgs)

--[=[
    MockRemoteFunction class

    @class MockRemoteFunction
]=]
local MockRemoteFunction = {}

MockRemoteFunction.__index = function(self, key)
    return rawget(MockRemoteFunction, key) or rawget(self, key) or self._internal[key]
end

MockRemoteFunction.__newindex = function(self, key, fn)
    if key == "OnClientInvoke" then
        self._internal.OnClientInvoke = fn
        
        for _, signal in pairs(self._clientSignals) do
            signal:fire(fn(table.unpack(signal.args)))
            signal:destroy()
        end

        table.clear(self._clientSignals)
    elseif key == "OnServerInvoke" then
        self._internal.OnServerInvoke = fn

        for _, signal in pairs(self._serverSignals) do
            signal:fire(fn(self._client, table.unpack(signal.args)))
            signal:destroy()
        end

        table.clear(self._serverSignals)
    end
end

--[=[
    Constructs a new MockRemoteFunction object.

    @param client string
    @return MockRemoteEvent
]=]
function MockRemoteFunction.new(client)
    local self = {}

    --[=[
        Callback property to handle requests on client

        @prop OnClientInvoke function
        @within MockRemoteFunction
    ]=]

    --[=[
        Callback property to handle requests on server

        @prop OnServerInvoke function
        @within MockRemoteFunction
    ]=]
    self.destroyed = false
    self._client = client

    self._internal = {}
    self._clientSignals = {}
    self._serverSignals = {}

    setmetatable(self, MockRemoteFunction)

    return self
end

--[=[
    Sends a request to the server and yields until a response is received

    @param ... any
    @return any

    @yields
]=]
function MockRemoteFunction:invokeServer(...)
    if self._internal.OnServerInvoke then
        return self._internal.OnServerInvoke(self._client, prepArgs(...))
    end

    local signal = TrueSignal.new()
    signal.args = table.pack(prepArgs(...))

    table.insert(self._serverSignals, signal)

    return signal:wait()
end

--[=[
    Sends a request to the client and yields until a response is received

    @param client string
    @param ... any
    @return any

    @yields
]=]
function MockRemoteFunction:invokeClient(client, ...)
    assert(client == self._client, "Invalid client passed")

    if self._internal.OnClientInvoke then
        return self._internal.OnClientInvoke(prepArgs(...))
    end

    local signal = TrueSignal.new()
    signal.args = table.pack(prepArgs(...))

    table.insert(self._clientSignals, signal)

    return signal:wait()
end

--[=[
    Gets the passed client argument in the constructor

    @return any
]=]
function MockRemoteFunction:getClient()
    return self._client
end

--[=[
    Prepares the MockRemoteFunction for garbage collection
]=]
function MockRemoteFunction:destroy()
    for _, signal in pairs(self._clientSignals) do
        signal:destroy()
    end

    for _, signal in pairs(self._serverSignals) do
        signal:destroy()
    end

    self.destroyed = true
end

--[=[
    PascalCase alias for invokeServer

    @param ... any
    @return any

    @yields

    @method InvokeServer
    @within MockRemoteFunction
]=]
MockRemoteFunction.InvokeServer = MockRemoteFunction.invokeServer

--[=[
    PascalCase alias for invokeClient

    @param client string
    @param ... any
    @return any

    @yields

    @method InvokeClient
    @within MockRemoteFunction
]=]
MockRemoteFunction.InvokeClient = MockRemoteFunction.invokeClient

--[=[
    PascalCase alias for destroy

    @method Destroy
    @within MockRemoteFunction
]=]
MockRemoteFunction.Destroy = MockRemoteFunction.destroy

return MockRemoteFunction
