local Network = {}

local pb = require("pb")
local CSNetworker = CS.Thousandto.Plugins.Common.Networker

--存储所有的服务器响应事件【key:消息id(enum),value:事件】一个消息只能创建一个响应事件
local msgMap = {}
--根据枚举存储所有类型
local cmdMap = {}
--根据类型存储所有枚举
local msgIDMap = {}
--是否是重新注册消息
local isReRegisterMsg = false
--注册接收的消息
local resMsgIDs = nil
local resMsgIDDic = nil
local resExtendMsgIDs = nil
local resExtendMsgIDDic = nil

--创建服务器消息响应事件
function Network.CreatRespond(cmd, callback)
	if not cmd or not callback then
		Debug.LogError(string.format("注册消息错误 cmd = %s,callback = %s", cmd, callback))
		return
	end
	local _msgid = pb.enum(string.format("%s.MsgID", cmd), "eMsgID")

    if not _msgid then
		Debug.LogError(string.format("消息不存在,请手动删除 %s", cmd))
		return
    end

	if msgMap[_msgid] and not isReRegisterMsg then
		Debug.LogError(string.format("消息重复注册 cmd = %s", cmd))
		return
	end

	if _msgid <= 500000 then
		--50万以内并且不在注册列表的消息,不走lua协议处理
		if resMsgIDs == nil then
			Network.GetResLuaMsgIDs()
		end
		--注册lua扩展的消息
		if resExtendMsgIDs == nil then
			Network.GetResLuaExtendMsgIDs()
		end
		if resMsgIDDic[_msgid] == nil and resExtendMsgIDDic[_msgid] == nil then
			return
		end
	end

	msgMap[_msgid] = callback
	cmdMap[_msgid] = cmd
	msgIDMap[cmd] = _msgid
end

--发送消息【编码-->序列化-->发送】
function Network.Send(cmd, msg)
	msg = msg or {}
	if not cmd then
		Debug.LogError(string.format("注册消息错误 cmd = %s", cmd))
		return
	end

	if not msgIDMap[cmd] then
		msgIDMap[cmd] = pb.enum(string.format("%s.MsgID", cmd), "eMsgID")
		if not msgIDMap[cmd] then
			Debug.LogError(string.format("消息不存在: %s",cmd))
			return
		end
	end

	local _code = pb.encode(cmd, msg)	
	CSNetworker.Instance:Send(_code, msgIDMap[cmd])
end

--处理服务器发来的消息
function Network.DoResMessage(msgid, bytes)
	local _cmd = cmdMap[msgid]
	if not _cmd then
		Debug.LogError(string.format("msgid = %s 消息未注册", msgid))
		return
	end
	local _msg = pb.decode(_cmd, bytes)
	--存一个MsgID
	_msg.MsgID = msgid
	msgMap[msgid](_msg)
	-- local _ok, _err = xpcall(function() msgMap[cmd](_msg) end, debug.traceback)
	-- if not _ok then
	-- end
end

--本地模拟服务器
function Network.DoResTest(cmd, table)
	local msgid = msgIDMap[cmd]
	if not msgid then
		Debug.LogError(string.format("msgid = %s 消息未注册", msgid))
		return
	end
	table.MsgID = msgid
	msgMap[msgid](table)
end

--获取所有Lua端的消息ID
function Network.GetResLuaMsgIDs()
	if resMsgIDs == nil then
		local resMsgCMDs = require("Network.ResMsgCMD")
		resMsgIDs = {}
		resMsgIDDic = {}
		for i=1, #resMsgCMDs do
			local _msgID = pb.enum(string.format("%s.MsgID", resMsgCMDs[i]), "eMsgID")
			if _msgID ~= nil then
				table.insert(resMsgIDs,_msgID )
				resMsgIDDic[_msgID] = true
			end
		end
	end
	return resMsgIDs
end

--获取所有Lua端扩展的消息ID
function Network.GetResLuaExtendMsgIDs()
	if resExtendMsgIDs == nil then
		local resMsgCMDs = require("Network.ResMsgExtendCMD")
		resExtendMsgIDs = {}
		resExtendMsgIDDic = {}
		for i=1, #resMsgCMDs do
			local _msgID = pb.enum(string.format("%s.MsgID", resMsgCMDs[i]), "eMsgID")
			if _msgID ~= nil then
				table.insert(resExtendMsgIDs,_msgID )
				resExtendMsgIDDic[_msgID] = true
			end
		end
	end
	return resExtendMsgIDs
end

function Network.ReRegisterMsg(name)
	local _path = string.format("Network.Msg.%s", name)
	Utils.RemoveRequiredByName(_path)
	local _msgSystem = require(_path)
	if _msgSystem then
		isReRegisterMsg = true
		_msgSystem.RegisterMsg()
		isReRegisterMsg = false
	end
end

--注册所有消息
function Network.RegisterAllMsg()
	local _msgNames = require("Network.Msg.ResMsg.MsgNames")
	for i=1, #_msgNames do
		local _msgSystem = require(string.format("Network/Msg/ResMsg/%s", _msgNames[i]))
		if _msgSystem then
			_msgSystem.RegisterMsg()
		end
	end
end

--初始化
function Network.Init()
	--加载所有协议文件
	local protoPaths = CSNetworker.GetAllProtoPath()
	local _count = protoPaths.Count - 1
	-- 打印pb的类型
	print(pb.types())
	

	for i = 0, _count do
		local _path = protoPaths[i]
		local _isok = pb.load(_path)
	end

	Network.RegisterAllMsg()
end

function Network.GetMsgID(cmd)
	return pb.enum(string.format("%s.MsgID", cmd), "eMsgID")
end

--设置IP和端口
function Network.GetIPAndPort()
	return CSNetworker.Instance.IP,CSNetworker.Instance.Port;
end
--设置IP和端口
function Network.SetIPAndPort(ip,port)
	CSNetworker.Instance.IP = ip;
	CSNetworker.Instance.Port = port;
end

--连接
function Network.Connect(func)
	CSNetworker.Instance:Connect(func);
end

--断开连接
function Network.Disconnect()
	CSNetworker.Instance:Disconnect();
end

--开始线程
function Network.StartThread()
	CSNetworker.Instance:StartThread();
end

return Network