package server

import (
	"game/common/proto/pb"
	"game/common/topicName"
	"github.com/fox/fox/ipb"
	"github.com/fox/fox/log"
	"github.com/fox/fox/processor"
	"github.com/fox/fox/ws"
	"reflect"
	"time"
)

/*
如果需要gate处理后，继续将消息转发给玩家，则最后需要调用SendClientData
*/
func (s *GateService) initProcessor() {
	s.Processor().RegisterMessages(processor.RegisterMetas{
		pb.MsgId_RspUserLoginId:  {pb.RspUserLogin{}, s.onUserLogin},
		pb.MsgId_RspUserLogoutId: {pb.RspUserLogout{}, s.onUserLogout},
		pb.MsgId_NtfUserOnlineId: {pb.NtfUserOnline{}, s.onUserOnline},
	})
}

// 收到登陆成功消息，判断是否顶号
func (s *GateService) onUserLogin(iMsg *ipb.InternalMsg, conn ws.IConn, msg *pb.RspUserLogin) {
	if conn == nil || reflect.ValueOf(conn).IsNil() {
		return
	}
	// 登陆失败，回传玩家
	if msg.Code != pb.ErrCode_OK {
		s.SendClientMsg(conn, iMsg.ServiceName, int32(pb.MsgId_RspUserLoginId), msg)
		return
	}
	log.Debug(s.Log("玩家id:%v登陆成功，连接:%v ", msg.UserId, conn.Id()))
	if oldConn, ok := s.wss.FindConnByUserId(msg.UserId); ok {
		log.Debug(s.Log("通知本网关下的旧玩家id:%v下线，连接:%v 当前连接:%v", oldConn.UserId(), oldConn.Id(), conn.Id()))
		s.SendClientMsg(oldConn, iMsg.ServiceName, int32(pb.MsgId_RspUserLogoutId), &pb.RspUserLogout{Code: pb.ErrCode_LoginDiffLoc})
		s.wss.SetUserId(oldConn.Id(), 0)
		// 登出的清理工作由WsOnDisconnect实现
		s.Timer.NewTimer(time.Second, func() {
			oldConn.Close()
		}, false)
	}
	//log.Debug(s.Log("连接:%v 设置玩家id:%v", conn.Id(), msg.UserId))
	s.wss.SetUserId(conn.Id(), msg.UserId)
	s.SendClientMsg(conn, iMsg.ServiceName, int32(pb.MsgId_RspUserLoginId), msg)
	//sName := s.BindService().LoadFromRedis(conn.UserId(), pb.ServiceTypeId_STI_Gate)
	//// 网关不同，说明玩家在其它网关上登陆，
	//if sName != "" && sName != s.Name() {
	//	log.Debug(s.Log("通知其它网关:%v下的旧玩家id:%v下线", sName, conn.UserId()))
	//	s.SendServiceMsg(service.TopicEx(sName), conn, int32(pb.MsgId_RspUserLogoutId), &pb.RspUserLogout{Code: pb.ErrCode_LoginDiffLoc})
	//}
	//log.Debug(s.Log("玩家:%v 绑定网关:%v", conn.UserId(), s.Name()))
	s.BindService().SaveUserService(msg.UserId, pb.ServiceTypeId_STI_Gate, s.Name())
	// 广播玩家上线
	s.SendServiceMsg(topicName.UserOnline, conn, int32(pb.MsgId_NtfUserOnlineId), &pb.NtfUserOnline{UserId: msg.UserId})
}

// 收到登出消息，网关不会主动发登出消息，异地登陆由online广播中检查自己
func (s *GateService) onUserLogout(iMsg *ipb.InternalMsg, conn ws.IConn, msg *pb.RspUserLogout) {
	if conn == nil || reflect.ValueOf(conn).IsNil() {
		return
	}
	s.SendClientMsg(conn, iMsg.ServiceName, int32(pb.MsgId_RspUserLogoutId), msg)

	// 登出的清理工作由WsOnDisconnect实现
	s.Timer.NewTimer(time.Second, func() {
		conn.Close()
	}, false)
}

// 收到玩家上线广播
func (s *GateService) onUserOnline(iMsg *ipb.InternalMsg, conn ws.IConn, msg *pb.NtfUserOnline) {
	//log.DebugF(s.Log("收到玩家:%v上线广播消息", msg.UserId))
	if conn == nil || reflect.ValueOf(conn).IsNil() {
		log.Error(s.Log("连接不存在,玩家:%v", msg.UserId))
		return
	}
	sName := s.BindService().LoadFromRedis(conn.UserId(), pb.ServiceTypeId_STI_Gate)
	//log.Debug(s.Log("玩家:%v 当前网关:%v", msg.UserId, sName))
	// 网关不同，说明玩家在其它网关上登陆，
	if sName != "" && sName != s.Name() {
		log.Debug(s.Log("通知本网关:%v下的旧玩家id:%v下线", s.Name(), conn.UserId()))
		s.SendClientMsg(conn, iMsg.ServiceName, int32(pb.MsgId_RspUserLogoutId), &pb.RspUserLogout{Code: pb.ErrCode_LoginDiffLoc})
		s.wss.SetUserId(conn.Id(), 0)
		// 登出的清理工作由WsOnDisconnect实现
		s.Timer.NewTimer(time.Second, func() {
			conn.Close()
		}, false)
	}
}
