local h=require(script.Parent.Parent.TrueSignal)local z=require(script.Parent.prepArgs)local r={}r.__index=function(h,z)return rawget(r,z)or rawget(h,z)or h._internal[z]end r.__newindex=function(h,z,r)if z=="\079\110\083\101\114\118\101\114\073\110\118\111\107\101"then h._internal.OnServerInvoke=r for h,z in pairs(h._signals)do z:fire(r(table.unpack(z.args)))z:destroy()end table.clear(h._signals)end end function r._new(h,z)local k={}k.name=h k.destroyed=false k._server=z k._internal={}k._signals={}k._server._remoteFunctions[h]=k return setmetatable(k,r)end function r._invokeServer(k,r,...)if k._internal.OnServerInvoke then return k._internal.OnServerInvoke(r,...)end local P=h.new()P.args=table.pack(r,z(...))table.insert(k._signals,P)return P:wait()end function r.destroy(h)h._server._remoteFunctions[h.name]=nil for z,r in pairs(h._server._clients)do(r:getRemoteFunction(h.name)):_destroy()end for h,z in pairs(h._signals)do z:destroy()end h.destroyed=true end function r.invokeClient(r,h,...)local k={z(...)}if h._remoteFunctions[r.name]then return(h:getRemoteFunction(r.name)):_invokeClient(table.unpack(k))end end r.InvokeClient=r.invokeClient r.Destroy=r.destroy return r
local TrueSignal = require(script.Parent.Parent.TrueSignal)

local prepArgs = require(script.Parent.prepArgs)

--[=[
    RemoteFunctionServer class

    @class RemoteFunctionServer
]=]
local RemoteFunctionServer = {}

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

RemoteFunctionServer.__newindex = function(self, key, fn)
    if key == "OnServerInvoke" then
        self._internal.OnServerInvoke = fn

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

--[=[
    Constructs a new RemoteFunctionServer object

    @param name string
    @param server Server
    @return RemoteFunctionServer

    @private
]=]
function RemoteFunctionServer._new(name, server)
    local self = {}

    self.name = name
    self.destroyed = false
    
    self._server = server
    
    self._internal = {}
    self._signals = {}

    self._server._remoteFunctions[name] = self

    return setmetatable(self, RemoteFunctionServer)
end

--[=[
    Called by RemoteFunctionClient to invoke the server

    @param client Client
    @param ... any
    @return any
    
    @private
]=]
function RemoteFunctionServer:_invokeServer(client, ...)
    if self._internal.OnServerInvoke then
        return self._internal.OnServerInvoke(client, ...)
    end
    
    local signal = TrueSignal.new()
    signal.args = table.pack(client, prepArgs(...))

    table.insert(self._signals, signal)
    
    return signal:wait()
end

--[=[
    Called by Server to clean up
]=]
function RemoteFunctionServer:destroy()
    self._server._remoteFunctions[self.name] = nil

    for _, client in pairs(self._server._clients) do
        client:getRemoteFunction(self.name):_destroy()
    end

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

    self.destroyed = true
end

--[=[
    Sends a request to the client and yields until it responds

    @param client Client
    @param ... any
    @return any

    @yields
]=]
function RemoteFunctionServer:invokeClient(client, ...)
    local args = {prepArgs(...)}

    if client._remoteFunctions[self.name] then
        return client:getRemoteFunction(self.name):_invokeClient(table.unpack(args))
    end
end

--[=[
    PascalCase alias for invokeClient

    @param client Client
    @param ... any
    @return any

    @yields

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

--[=[
    PascalCase alias for destroy

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

return RemoteFunctionServer