package group_m

import (
	"context"
	"encoding/json"
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/resource/redisCli"
	"git.hilo.cn/hilo-common/rpc"
	"hilo-group/_const/enum/group_e"
	"hilo-group/_const/redis_key"
	"hilo-group/domain/model/noble_m"
	"hilo-group/domain/model/res_m"
	"hilo-group/domain/model/user_m"
	"time"
)

//麦位,要发送的麦位信息
type MicSystemMsg struct {
	GroupUid string //房间ID
	Source   string
	Target   string
	MsgId    group_e.TypeSignalMsg
	Content  string //要发送的内容
}

type MicContent struct {
	//GroupId
	GroupId string `json:"groupId"`
	//麦位
	I int `json:"i"`
	//锁,是否有锁 true:锁了, false:没锁
	Lock bool `json:"lock"`
	//个人静音 true:静音,false:没有静音
	Forbid bool `json:"forbid"`
	//麦位静音 true:静音,false:没有静音
	MicForbid bool `json:"micForbid"`
	//如果 空字符串 则代表这个位置上没有人
	ExternalId string `json:"externalId"`
	//声网agoraId 如果 0 则代表这个位置上没有人
	AgoraId uint32 `json:"agoraId"`
	//服务器记录的时间戳
	Timestamp int64 `json:"timestamp"`
	//用户
	User *MicUserData `json:"user"`
}

type MicUserData struct {
	Id                       uint64     `json:"id,omitempty"`
	ExternalId               string     `json:"externalId"`
	Avatar                   string     `json:"avatar"`
	Nick                     string     `json:"nick"`
	Sex                      uint8      `json:"sex"`
	Code                     string     `json:"code"`
	IsVip                    bool       `json:"isVip"`
	NobleLeave               uint16     `json:"noble"` // 当前的贵族等级
	HeadwearPicUrl           string     `json:"headwearPicUrl"`
	HeadwearEffectUrl        string     `json:"headwearEffectUrl"`
	HeadwearReverseEffectUrl string     `json:"headwearReverseEffectUrl"` // 反转svga效果
	SvipLevel                int        `json:"svipLevel"`
	Svip                     rpc.CvSvip `json:"svip"`
	MicEffect                string     `json:"micEffect"`    //mic位置特效svga
	HeadwearIcon             string     `json:"headwearIcon"` //头饰里面的小头像
}

type MicNumChangeContent struct {
	MicOn      bool                    `json:"micOn"`
	MicNumType group_e.GroupMicNumType `json:"micNumType"`
	Timestamp  int64                   `json:"timestamp"`
}

func MicGroupKickOutRPush(model *domain.Model, groupUid string, userExternalId string, beKickExternalId string, beKickuserId uint64) {
	model.Log.Infof("MicChangeRPush MicGroupKickOutRPush begin groupUuid:%v", groupUid)

	txGroupId, err := ToTxGroupId(model, groupUid)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicGroupKickOutRPush ToTxGroupId err:%+v, groupUid:%v", err, groupUid)
	}

	r := MicNumChangeContent{
		Timestamp: time.Now().Unix(),
	}
	buf, err := json.Marshal(r)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicGroupKickOutRPush Content json.Marshal err:%+v", err)
	}
	str, err := json.Marshal(MicSystemMsg{
		GroupUid: txGroupId,
		Source:   userExternalId,
		Target:   beKickExternalId,
		MsgId:    group_e.GroupKickOut,
		Content:  string(buf),
	})
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicGroupKickOutRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
		return
	}
	// socket通知被拉黑者退房
	rpc.SendQuitRoom(beKickuserId, 2, txGroupId)
	if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
		model.Log.Errorf("MicChangeRPush MicGroupKickOutRPush err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
		return
	} else {
		model.Log.Infof("MicChangeRPush MicGroupKickOutRPush success groupUuid:%v, micContent:%+v", groupUid, string(str))
	}
	model.Log.Infof("MicChangeRPush MicGroupKickOutRPush end groupUuid:%v, micContent:%v", groupUid, string(str))
}

func MicSocketMicOutRPush(model *domain.Model, groupUid string, userExternalId string) {
	model.Log.Infof("MicChangeRPush MicSocketMicOutRPush begin groupUuid:%v", groupUid)

	txGroupId, err := ToTxGroupId(model, groupUid)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicSocketMicOutRPush ToTxGroupId err:%+v, groupUid:%v", err, groupUid)
	}

	r := MicNumChangeContent{
		Timestamp: time.Now().Unix(),
	}
	buf, err := json.Marshal(r)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicSocketMicOutRPush Content json.Marshal err:%+v", err)
	}
	str, err := json.Marshal(MicSystemMsg{
		GroupUid: txGroupId,
		Source:   userExternalId,
		MsgId:    group_e.GroupSocketMicOutSignal,
		Content:  string(buf),
	})
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicSocketMicOutRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
		return
	}
	if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
		model.Log.Errorf("MicChangeRPush MicSocketMicOutRPush err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
		return
	} else {
		model.Log.Infof("MicChangeRPush MicSocketMicOutRPush success groupUuid:%v, micContent:%+v", groupUid, string(str))
	}
	model.Log.Infof("MicChangeRPush MicSocketMicOutRPush end groupUuid:%v, micContent:%v", groupUid, string(str))
}

func MicNumChangeRPush(model *domain.Model, groupUid string, micNumType group_e.GroupMicNumType, micOn bool) {
	model.Log.Infof("MicChangeRPush MicNumChangeRPush begin groupUuid:%v, micNumType:%v", groupUid, micNumType)

	txGroupId, err := ToTxGroupId(model, groupUid)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicNumChangeRPush ToTxGroupId err:%+v, groupUid:%v", err, txGroupId)
	}

	r := MicNumChangeContent{
		MicOn:      micOn,
		MicNumType: micNumType,
		Timestamp:  time.Now().Unix(),
	}
	buf, err := json.Marshal(r)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicNumChangeRPush Content json.Marshal err:%+v", err)
	}
	str, err := json.Marshal(MicSystemMsg{
		GroupUid: txGroupId,
		MsgId:    group_e.GroupMicChangeSignal,
		Content:  string(buf),
	})
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicNumChangeRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
		return
	}
	if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
		model.Log.Errorf("MicChangeRPush MicNumChangeRPush err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
		return
	} else {
		model.Log.Infof("MicChangeRPush MicNumChangeRPush success groupUuid:%v, micContent:%+v", groupUid, string(str))
	}
	model.Log.Infof("MicChangeRPush MicNumChangeRPush end groupUuid:%v, micContent:%v", groupUid, string(str))
}

func MicEmptyRPush(model *domain.Model, groupUid string, i int) {
	model.Log.Infof("MicChangeRPush MicEmptyRPush begin groupUuid:%v, i:%v", groupUid, i)

	txGroupId, err := ToTxGroupId(model, groupUid)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicEmptyRPush ToTxGroupId err:%+v, groupUid:%v", err, txGroupId)
	}

	micContent, err := json.Marshal(MicContent{
		GroupId:    txGroupId,
		I:          i,
		Lock:       false,
		Forbid:     false,
		ExternalId: "",
		AgoraId:    0,
		Timestamp:  time.Now().UnixNano(),
		User:       nil,
	})
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicEmptyRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContent))
		return
	}

	str, err := json.Marshal(MicSystemMsg{
		GroupUid: txGroupId,
		MsgId:    group_e.GroupMicChange,
		Content:  string(micContent),
	})
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicEmptyRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContent))
		return
	}
	if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
		model.Log.Errorf("MicChangeRPush MicEmptyRPush err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContent))
		return
	} else {
		model.Log.Infof("MicChangeRPush MicEmptyRPush success groupUuid:%v, i:%v, micContent:%+v", micContent, groupUid, i, string(micContent))
	}
	model.Log.Infof("MicChangeRPush MicEmptyRPush end groupUuid:%v, i:%v, micContent:%v", groupUid, i, string(micContent))
}

//将麦位信息推送到redis 队列中
func MicChangeRPush(model *domain.Model, groupUid string, i int) {
	model.Log.Infof("MicChangeRPush MicChangeRPush begin groupUuid:%v, i:%v", groupUid, i)

	txGroupId, err := ToTxGroupId(model, groupUid)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicChangeRPush ToTxGroupId err:%+v, groupUid:%v", err, txGroupId)
	}

	micContent, err := getMicIContent(model, groupUid, i)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicChangeRPush getMicIContent err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, micContent)
		return
	}
	micContentStr, err := json.Marshal(micContent)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicChangeRPush Marshal err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContentStr))
		return
	}
	str, err := json.Marshal(MicSystemMsg{
		GroupUid: txGroupId,
		Content:  string(micContentStr),
		MsgId:    group_e.GroupMicChange,
	})
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicChangeRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContentStr))
		return
	}
	if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
		model.Log.Errorf("MicChangeRPush MicChangeRPush err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContentStr))
		return
	} else {
		model.Log.Infof("MicChangeRPush MicChangeRPush success groupUuid:%v, i:%v, micContent:%+v", groupUid, i, string(micContentStr))
	}
	model.Log.Infof("MicChangeRPush MicChangeRPush end groupUuid:%v, i:%v, micContent:%+v", groupUid, i, micContent)
}

func MicAllRPush(model *domain.Model, groupUid string, externalId string) error {
	model.Log.Infof("MicChangeRPush MicAllRPush begin groupUuid:%v, externalId:%v", groupUid, externalId)

	txGroupId, err := ToTxGroupId(model, groupUid)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicChangeRPush ToTxGroupId err:%+v, groupUid:%v", err, txGroupId)
	}

	//
	micContents, err := GetMicAllContent(model, groupUid)
	if err != nil {
		model.Log.Errorf("MicChangeRPush MicAllRPush GetMicAllContent  err:%+v, micContents:%v groupUuid:%v, externalId:%v", err, micContents, groupUid, externalId)
		return err
	}
	for _, micContent := range micContents {
		//麦上是默认值,就不用推
		if micContent.Forbid == false && micContent.User == nil && micContent.AgoraId == 0 && micContent.Lock == false && micContent.ExternalId == "" && micContent.MicForbid == false {
			model.Log.Infof("MicChangeRPush MicAllRPush default micContent:%v, groupUuid:%v, externalId:%v, micContent:%+v", micContent, groupUid, externalId, micContent)
			continue
		}
		micContentStr, err := json.Marshal(micContent)
		if err != nil {
			model.Log.Errorf("MicChangeRPush MicAllRPush Marshal micContent err:%+v, groupUuid:%v, externalId:%v, micContent:%+v", err, groupUid, externalId, string(micContentStr))
			continue
		}
		str, err := json.Marshal(MicSystemMsg{
			GroupUid: txGroupId,
			Target:   externalId,
			Content:  string(micContentStr),
			MsgId:    group_e.GroupMicChange,
		})

		if err != nil {
			model.Log.Errorf("MicChangeRPush MicAllRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, externalId:%v, micContent:%+v", err, groupUid, externalId, string(micContentStr))
			continue
		}
		if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
			model.Log.Errorf("MicChangeRPush MicAllRPush err:%+v, groupUuid:%v, externalId:%v, micContent:%+v", err, groupUid, externalId, string(micContentStr))
			continue
		} else {
			model.Log.Infof("MicChangeRPush MicAllRPush success micContent:%v, groupUuid:%v, externalId:%v, micContent:%+v", micContent, groupUid, externalId, string(micContentStr))
		}
	}
	model.Log.Infof("MicChangeRPush MicAllRPush end groupUuid:%v, externalId:%v", groupUid, externalId)
	return nil
}

// 通用麦位信息推送
func MicRPush(model *domain.Model, txGroupId string, msg GroupSystemMsg) error {
	model.Log.Infof("MicRPush begin msg:%v", msg)
	str, err := json.Marshal(MicSystemMsg{
		GroupUid: txGroupId,
		Source:   msg.Source,
		MsgId:    msg.MsgId,
		Content:  msg.Content,
	})
	if err != nil {
		model.Log.Errorf("MicRPush Marshal MicSystemMsg err:%+v, txGroupId:%v, micContent:%+v", err, txGroupId, string(str))
		return err
	}
	if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
		model.Log.Errorf("MicRPush err:%+v, txGroupId:%v, micContent:%+v", err, txGroupId, string(str))
		return err
	}
	model.Log.Infof("MicRPush end txGroupId:%v, micContent:%v", txGroupId, string(str))
	return nil
}

//得使用旧的imGroupId
func GetMicAllContent(model *domain.Model, groupUid string) ([]MicContent, error) {

	txGroupId, err := ToTxGroupId(model, groupUid)
	if err != nil {
		return nil, err
	}

	micNumType, err := GetMicNumType(model, groupUid)
	if err != nil {
		return nil, err
	}
	mics, micUsers, err := GetAllMic(groupUid, micNumType)

	micUserMap := map[int]MicUser{}
	for i, r := range micUsers {
		micUserMap[r.I] = micUsers[i]
	}

	userIds := make([]uint64, 0, len(micUsers))
	for _, r := range micUsers {
		userIds = append(userIds, r.UserId)
		if r.CpUserId > 0 {
			userIds = append(userIds, r.CpUserId)
		}
	}

	model.Log.Infof("MicChangeRPush getMicAllContent groupUid:%v, userIds:%+v", groupUid, userIds)
	micUserDataMap, err := getMicUserDatas(model, userIds)
	if err != nil {
		return nil, err
	}

	micContents := make([]MicContent, 0, len(mics))
	for _, r := range mics {
		var micEffect string
		cpUserId := micUserMap[r.I].CpUserId
		micUserData := micUserDataMap[micUserMap[r.I].UserId]
		if cpUserId > 0 {
			micEffect = "https://image.whoisamy.shop/hilo/resource/svga/mic_effect_cp.svga"
			micUserData.MicEffect = micEffect
		}
		micContents = append(micContents, MicContent{
			GroupId:    txGroupId,
			I:          r.I,
			Lock:       r.Lock,
			MicForbid:  r.MicForbid,
			Forbid:     micUserMap[r.I].Forbid,
			ExternalId: micUserMap[r.I].ExternalId,
			AgoraId:    uint32(micUserMap[r.I].UserId),
			Timestamp:  time.Now().UnixNano(),
			User:       micUserData,
		})
	}
	return micContents, nil
}

//得使用旧的imGroupId
func getMicIContent(model *domain.Model, groupId string, i int) (MicContent, error) {
	txGroupId, err := ToTxGroupId(model, groupId)
	if err != nil {
		return MicContent{}, err
	}

	mic, err := GetMic(model, groupId, i)
	if err != nil {
		return MicContent{}, err
	}
	micUser, err := GetMicUser(model, groupId, i)
	if err != nil {
		return MicContent{}, err
	}
	if micUser == nil {
		return MicContent{
			GroupId:    txGroupId,
			I:          mic.I,
			Lock:       mic.Lock,
			Forbid:     false,
			MicForbid:  mic.MicForbid,
			ExternalId: "",
			AgoraId:    0,
			Timestamp:  time.Now().UnixNano(),
			User:       nil,
		}, nil
	} else {
		micUserData, err := getMicUserData(model, micUser.UserId)
		if err != nil {
			return MicContent{}, err
		}
		var micEffect string
		if micUser.CpUserId > 0 {
			micEffect = "https://image.whoisamy.shop/hilo/resource/svga/mic_effect_cp.svga"
			micUserData.MicEffect = micEffect
		}
		return MicContent{
			GroupId:    txGroupId,
			I:          mic.I,
			Lock:       mic.Lock,
			Forbid:     micUser.Forbid,
			MicForbid:  mic.MicForbid,
			ExternalId: micUser.ExternalId,
			AgoraId:    uint32(micUser.UserId),
			Timestamp:  time.Now().UnixNano(),
			User:       micUserData,
		}, nil
	}

}

func getMicUserDatas(model *domain.Model, userIds []uint64) (map[uint64]*MicUserData, error) {
	userMap, err := user_m.GetUserMapByIds(model, userIds)
	if err != nil {
		return nil, err
	}

	vipMap, err := user_m.BatchGetVips(userIds)
	if err != nil {
		return nil, err
	}

	nobleMap, err := noble_m.BatchGetNobleLevel(model.Db, userIds)
	if err != nil {
		return nil, err
	}

	headwearMap, err := user_m.BatchGetUserHeadwearUsing(model, userIds)
	if err != nil {
		return nil, err
	}
	//
	resHeadwearIds := make([]uint64, 0, len(headwearMap))
	for _, value := range headwearMap {
		resHeadwearIds = append(resHeadwearIds, value.HeadwearId)
	}
	//
	resHeadwearMap, err := res_m.BatchGetHeadwearByIds(model, resHeadwearIds)
	if err != nil {
		return nil, err
	}
	svips, _ := rpc.MGetUserSvip(model, userIds)
	cpRelations, _ := rpc.MGetUserCpRelations(model, userIds)

	micUserDataMap := map[uint64]*MicUserData{}
	for _, id := range userIds {
		user, flag := userMap[id]
		if !flag {
			model.Log.Errorf("MicChangeRPush getMicUserDatas id:%v noexit", id)
		}
		vipTime, vipFlag := vipMap[id]
		if vipTime == nil {
			vipFlag = false
		}
		var headwearPicUrl string
		var headwearEffectUrl string
		var headwearReverseEffectUrl string
		if headwearUser, flag := headwearMap[id]; flag {
			headwearPicUrl = resHeadwearMap[headwearUser.HeadwearId].PicUrl
			headwearEffectUrl = resHeadwearMap[headwearUser.HeadwearId].EffectUrl
			headwearReverseEffectUrl = resHeadwearMap[headwearUser.HeadwearId].ReverseEffectUrl
		}
		micUserDataMap[id] = &MicUserData{
			Id:                       user.ID,
			ExternalId:               user.ExternalId,
			Avatar:                   user.Avatar,
			Nick:                     user.Nick,
			Sex:                      user.Sex,
			Code:                     user.Code,
			IsVip:                    vipFlag,
			NobleLeave:               nobleMap[id],
			HeadwearPicUrl:           headwearPicUrl,
			HeadwearEffectUrl:        headwearEffectUrl,
			HeadwearReverseEffectUrl: headwearReverseEffectUrl,
			SvipLevel:                svips[id].SvipLevel,
			Svip:                     rpc.CopySimpleSvip(svips[id]),
			HeadwearIcon:             cpRelations[user.ID].CpUserAvatar,
		}
	}
	return micUserDataMap, nil

}

func getMicUserData(model *domain.Model, userId uint64) (*MicUserData, error) {
	user, err := user_m.GetUser(model, userId)
	if err != nil {
		return nil, err
	}

	flag, _, err := user_m.IsVip(userId)
	if err != nil {
		return nil, err
	}

	nobleLeave, err := noble_m.GetNobleLevel(model.Db, userId)
	if err != nil {
		return nil, err
	}
	svip, _ := rpc.GetUserSvip(model, userId)

	var headwearPicUrl string
	var headwearEffectUrl string
	var headwearReverseEffectUrl string

	headwear, err := user_m.GetUserHeadwearUsing(model, userId)
	if err != nil {
		return nil, err
	}
	if headwear != nil {
		resHeadwear, err := res_m.GetHeadwearById(model, headwear.HeadwearId)
		if err != nil {
			return nil, err
		}
		headwearPicUrl = resHeadwear.PicUrl
		headwearEffectUrl = resHeadwear.EffectUrl
		headwearReverseEffectUrl = resHeadwear.ReverseEffectUrl
	}
	var headwearIcon string
	if cpRelation, _ := rpc.GetUserCpRelation(model, userId); len(cpRelation.CpUserAvatar) > 0 {
		headwearIcon = cpRelation.CpUserAvatar
	}

	return &MicUserData{
		Id:                       user.ID,
		ExternalId:               user.ExternalId,
		Avatar:                   user.Avatar,
		Nick:                     user.Nick,
		Sex:                      user.Sex,
		Code:                     user.Code,
		IsVip:                    flag,
		NobleLeave:               nobleLeave,
		HeadwearPicUrl:           headwearPicUrl,
		HeadwearEffectUrl:        headwearEffectUrl,
		HeadwearReverseEffectUrl: headwearReverseEffectUrl,
		SvipLevel:                svip.SvipLevel,
		Svip:                     rpc.CopySimpleSvip(svip),
		HeadwearIcon:             headwearIcon,
	}, nil
}