local skynet = require "skynet"
require "tracing.init"
local cluster = require "skynet.cluster"

local CMD = {}
local SOCKET = {}
local master_gate
local agent = {}
local protocol
local fd2gate = {}

function SOCKET.open(tracer, fd, addr, gate)
    skynet.error("New client from : " .. addr)
    fd2gate[fd] = gate
    local agent_addr = skynet.newservice("ws_agent")
    agent[fd] = agent_addr
    skynet.tracing_call(
        agent_addr,
        "start",
        tracer,
        {
            gate = gate,
            client = fd,
            watchdog = skynet.self(),
            protocol = protocol,
            addr = addr
        }
    )
end

local function close_agent(tracer, fd)
    local a = agent[fd]
    agent[fd] = nil
    if a then
        local gate = fd2gate[fd]
        if gate then
            skynet.tracing_call(gate, "kick", tracer, fd)
            fd2gate[fd] = nil
        end
        -- disconnect never return
        tracer.cmd = "disconnect"
        skynet.tracing_send(a, tracer)
    end
end

function SOCKET.close(tracer, fd)
    close_agent(tracer, fd)
end

function SOCKET.error(tracer, fd)
    close_agent(tracer, fd)
end

function SOCKET.warning(_, fd, size)
    -- size K bytes havn't send out in fd
    skynet.error("socket warning", fd, size)
end

function SOCKET.data(_, fd, msg)
    skynet.error("socket data", fd, msg)
end

function CMD.start(tracer, conf)
    protocol = conf.protocol
    skynet.tracing_call(master_gate, "open", tracer, conf)
    cluster.tracing_call("proxy_1", ".test_proxy", "test_proxy", tracer, 100)
end

function CMD.close(_, fd)
    close_agent(fd)
end

skynet.start(
    function()
        skynet.dispatch(
            "lua",
            function(_, _, cmd, tracer, subcmd, ...)
                skynet.trace(tracer)

                if cmd == "socket" then
                    -- socket api don't need return
                    local f = SOCKET[subcmd]
                    f(tracer, ...)
                else
                    local f = assert(CMD[cmd])
                    skynet.ret(skynet.pack(f(tracer, subcmd, ...)))
                end
            end
        )

        master_gate = skynet.newservice("ws_gate")
    end
)
