package im

import (
	"encoding/json"
	"github.com/go-netty/go-netty"
	redis2 "github.com/go-redis/redis"
	"github.com/qit-team/snow-core/redis"
	"go.mongodb.org/mongo-driver/bson"
	"snow-im/app/constants/common"
	"snow-im/app/constants/errorcode"
	"snow-im/app/constants/msgid"
	"snow-im/app/http/controllers"
	"snow-im/app/http/entities"
	"snow-im/app/models"
	"snow-im/app/utils"
	common2 "snow-im/app/utils/common"
	"snow-im/app/utils/mq"
	"snow-im/app/utils/netool"
	"snow-im/app/utils/serialize"
	"snow-im/config"
	"strconv"
	"strings"
	"time"
)

var ImRouter netool.Router

func init() {
	ImRouter = netool.Router{}
	ImRouter.AddRouter(msgid.SINGLE_MSG, SendMsgtoUser)
	ImRouter.AddRouter(msgid.GROUP_MSG, SendMsgtoGroup)
	ImRouter.AddRouter(msgid.MULT_MSG, SendMsgtoMultUser)
	ImRouter.AddRouter(msgid.HEART_BEAT, HeartBeat)
	ImRouter.AddRouter(msgid.AUTH, Auth)
	ImRouter.AddRouter(msgid.ACK_MSG, Ack)
}

func getRsp(err error) entities.ImRsp {
	var rsp entities.ImRsp
	if err == nil {
		rsp = entities.ImRsp{
			Code: errorcode.Success,
			Msg:  errorcode.GetMsg(errorcode.Success, ""),
		}
	} else {
		rsp = entities.ImRsp{
			Code: errorcode.SystemError,
			Msg:  errorcode.GetMsg(errorcode.SystemError, ""),
		}
		utils.Log(nil, "err", err)
	}
	return rsp
}

//验证
func Auth(msg []byte, connect netty.InboundContext) error {
	var authReq entities.AuthReq
	err := serialize.SerializeTool.UnSerialize(config.GetConf().Serialize,msg,&authReq)
	if err == nil {
		err = controllers.Validate(authReq)
		if err == nil {
			uid, _ := redis.GetRedis().Get(utils.GetRealKey(common.TOKEN_PRE) + authReq.AppId + ":" + authReq.Token)
			if uid != "" {
				netool.GetConnManagger().SaveConnection(uid, connect.Channel())
			}
		}
	}
	return err
}

//单聊
func SendMsgtoUser(msg []byte, connect netty.InboundContext) error {
	var singReq entities.SingTalkReq
	utils.Log(nil, string(msg))
	err := serialize.SerializeTool.UnSerialize(config.GetConf().Serialize,msg,&singReq)
	if err == nil {
		err = controllers.Validate(singReq)
		if err == nil {
			singReq.Id = utils.GenUniqId(singReq.SenderId)
			singReq.Timestamp = time.Now().Unix()
			var uid, _ = strconv.Atoi(singReq.To)
			var msgFrom = common2.CacheHelper.GetCache(utils.GetRealKey(common.USER)+singReq.SenderId,false).(map[string]interface{})
			singReq.Avatar = msgFrom["avatar"].(string)
			singReq.SenderName = msgFrom["nick_name"].(string)
			utils.Log(nil, "err", utils.GetUnderLineKey(common.SINGLE_TALK)+strconv.Itoa(uid%config.GetConf().Im.ImworkNum))
			err = rabbitmq.MqManager.GetMqByName(common.MQ_KFK).Produce(utils.GetUnderLineKey(common.SINGLE_TALK)+strconv.Itoa(uid%config.GetConf().Im.ImworkNum), singReq, 0)
			//生成会话
			var msgData,_ = json.Marshal(singReq)
			if err == nil {
				var msg = models.Msg{}
				msg.ParseFromParam(singReq.Msg)
				msg.Conversion = utils.SortKeys([]string{singReq.SenderId,singReq.To})
				msg.SaveMsg()
				if singReq.RoomId == ""{
					//优化管道操作
					var pipline = common2.PikaTool.GetPipe()
					var to = redis2.Z{
						Score:  float64(singReq.Timestamp),
						Member: singReq.SenderId,
					}
					var from = redis2.Z{
						Score:  float64(singReq.Timestamp),
						Member: singReq.SenderId,
					}
					pipline.ZAdd(utils.GetRealKey(common.CONVERSION)+singReq.To, to,from)
					var msgFrom = common2.CacheHelper.GetCache(utils.GetRealKey(common.USER)+singReq.To,false).(map[string]interface{})
					singReq.Avatar = msgFrom["avatar"].(string)
					singReq.SenderName = msgFrom["nick_name"].(string)
					msgDataFrom,_ := json.Marshal(singReq)
					pipline.MSet(utils.GetRealKey(common.CONVERSION)+singReq.To+":"+singReq.SenderId, msgData,utils.GetRealKey(common.CONVERSION)+singReq.SenderId+":"+singReq.To, msgDataFrom)
					pipline.Incr(utils.GetRealKey(common.CONVERSION)+singReq.To+":"+singReq.SenderId+":num")
					pipline.Incr(utils.GetRealKey(common.CONVERSION)+singReq.SenderId+":"+singReq.To+":num")
					pipline.Exec()

				}

			}
		}
	}
	return err
}

//群聊
func SendMsgtoGroup(msg []byte, connect netty.InboundContext) error {
	var singReq entities.SingTalkReq
	err := serialize.SerializeTool.UnSerialize(config.GetConf().Serialize,msg,&singReq)
	if err == nil {
		err = controllers.Validate(singReq)
		if err == nil {
			singReq.Id = utils.GenUniqId(singReq.SenderId)
			singReq.Timestamp = time.Now().Unix()
			var userInfo map[string]interface{}
			var rs = common2.CacheHelper.GetCache(utils.GetRealKey(common.USER)+singReq.SenderId,false)
			userInfo = rs.(map[string]interface{})
			var room = models.Room{}
			room = room.GetRoom(bson.M{"_id":singReq.RoomId})
			singReq.SenderName = userInfo["nick_name"].(string)
			singReq.Avatar = userInfo["avatar"].(string)
			singReq.RoomAvatar = room.Avatar
			singReq.RoomName = room.Name
			var uid, _ = strconv.Atoi(singReq.RoomId)
			err = rabbitmq.MqManager.GetMqByName(common.MQ_KFK).Produce(utils.GetUnderLineKey(common.GROUP_TALK)+strconv.Itoa(uid%config.GetConf().Im.ImGroupNum), singReq, 0)
			if err == nil {
				var msg = models.Msg{}
				msg.ParseFromParam(singReq.Msg)
				msg.Conversion = singReq.RoomId
				msg.SaveMsg()
				var pipie = common2.PikaTool.GetPipe()
				var roomMembers = common2.PikaTool.SetGet(utils.GetRealKey(common.ROOM) + singReq.RoomId)
				for _,v := range roomMembers{
					var msgData,_ = json.Marshal(singReq)
					var member =redis2.Z{
						Member:singReq.RoomId,
						Score:float64(singReq.Timestamp),
					}
					pipie.ZAdd(utils.GetRealKey(common.CONVERSION)+v, member)
					pipie.Set(utils.GetRealKey(common.CONVERSION)+v+":"+singReq.RoomId,msgData, 0)
				}
				_,err = pipie.Exec()
			}
		}
	}
	return err
}

//组聊
func SendMsgtoMultUser(msg []byte, connect netty.InboundContext) error {
	var singReq entities.SingTalkReq
	err := serialize.SerializeTool.UnSerialize(config.GetConf().Serialize,msg,&singReq)
	if err == nil {
		err = controllers.Validate(singReq)
		if err == nil {
			singReq.Id = utils.GenUniqId(singReq.SenderId)
			var userInfo map[string]string
			json.Unmarshal([]byte(common2.PikaTool.HashGet(utils.GetRealKey("user_info"), singReq.SenderId)), &userInfo)
			singReq.SenderName = userInfo["nick_name"]
			singReq.Avatar = userInfo["avatar"]
			var uids = strings.Split(singReq.To, ",")
			var pipie = common2.PikaTool.GetPipe()
			for _, v := range uids {
				var uid, _ = strconv.Atoi(v)
				singReq.To = v
				err = rabbitmq.MqManager.GetMqByName(common.MQ_KFK).Produce(utils.GetUnderLineKey(common.SINGLE_TALK)+strconv.Itoa(uid%config.GetConf().Im.ImworkNum), singReq, 0)
				//生成会话
				if err == nil {
					var member =redis2.Z{
						Member:singReq.RoomId,
						Score:float64(singReq.Timestamp),
					}
					pipie.ZAdd(utils.GetRealKey(common.CONVERSION)+v, member)
					pipie.Set(utils.GetRealKey(common.CONVERSION)+singReq.To+":"+singReq.RoomId, msg,0)
				}
				_,err = pipie.Exec()
			}
		}
	}
	return err
}

//消息ack
func Ack(msg []byte, connect netty.InboundContext) error {
	var req entities.MsgId
	err := json.Unmarshal(msg, &req)
	if err == nil {

	}
	return err
}

//心跳
func HeartBeat(msg []byte, connect netty.InboundContext) error {
	if connect.Channel().IsActive() {
		netool.GetConnManagger().SetBeat(connect.Channel().ID())
		connect.Write(utils.PackMsg([]byte("Ping"), msgid.HEART_BEAT))
	}

	return nil
}