local skynet = require "skynet"
local cluster = require "skynet.cluster"

local skynet_env = require("skynet.env")
local cur_nodeid = skynet_env.get("nodeid")

local zenv = require("zenv.init")

local function _xpret(_, ...)
    return ...
end
---------------------------------------------------

local Rpc = class("Rpc")

function Rpc:initialize(name, nodeid)
    self._name = name
    self._nodeid = nodeid
end

function Rpc:_get_local_nodeid()
    local nodeid = self._nodeid
    if not nodeid or nodeid == cur_nodeid then
        return true
    end
    return false, nodeid
end

function Rpc:call(...)
    local is_local, nodeid = self:_get_local_nodeid()
    if is_local then
        return skynet.call(self._name, "lua", ...)
    end

    local nodename = zenv.get_node_conf(nodeid).name
    return cluster.call(nodename, self._name, ...)
end

function Rpc:send(...)
    local is_local, nodeid = self:_get_local_nodeid()
    if is_local then
        skynet.send(self._name, "lua", ...)
    else
        local node = zenv.get_node_conf(nodeid).name
        cluster.send(node, self._name, ...)
    end
end

function Rpc:xpcall(...)
    return xpcall(self.call, skynet.error, self, ...)
end

function Rpc:xpcallret(...)
    return _xpret(self:xpcall(...))
end

function Rpc:psend(...)
    pcall(self.send, self, ...)
end

function Rpc:timeout_call(time, cb, ...)
    local timeout = false
    local ok = false
    local co = coroutine.running()

    skynet.fork(function(...)
        local function f(suc, ...)
            if suc then
                if not timeout then
                    ok = true
                    skynet.wakeup(co)
                end
            else
                skynet.wakeup(co)
            end

            if cb then
                cb(ok, ...)
            end
        end

        f(self:xpcall(...))
    end, ...)

    skynet.sleep(time * 100)
    timeout = true

    return ok
end

return Rpc
