package group_r

import (
	"encoding/json"
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/mycontext"
	"git.hilo.cn/hilo-common/resource/config"
	"git.hilo.cn/hilo-common/resource/mysql"
	"git.hilo.cn/hilo-common/rpc"
	"git.hilo.cn/hilo-common/sdk/aws"
	"git.hilo.cn/hilo-common/sdk/tencentyun"
	"git.hilo.cn/hilo-common/utils"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"hilo-group/_const/enum/diamond_e"
	"hilo-group/_const/enum/group_e"
	"hilo-group/_const/enum/mgr_e"
	"hilo-group/_const/enum/msg_e"
	"hilo-group/cv/diamond_cv"
	"hilo-group/cv/user_cv"
	"hilo-group/domain/cache/group_c"
	"hilo-group/domain/model/diamond_m"
	"hilo-group/domain/model/game_m"
	"hilo-group/domain/model/group_m"
	"hilo-group/domain/model/mgr_m"
	"hilo-group/domain/model/noble_m"
	"hilo-group/domain/model/res_m"
	"hilo-group/domain/model/user_m"
	"hilo-group/domain/service/group_s"
	"hilo-group/domain/service/signal_s"
	"hilo-group/myerr"
	"hilo-group/myerr/bizerr"
	"hilo-group/req"
	"hilo-group/resp"
	"strconv"
	"time"
)

// @Tags 群组
// @Summary 查询群是否有密码
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} bool
// @Router /v1/imGroup/password/{groupId} [get]
func GetGroupPassword(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	userId, err := req.GetUserId(c)
	if err != nil {
		return myContext, err
	}

	groupId := c.Param("groupId")
	if len(groupId) <= 0 {
		return myContext, myerr.NewSysError("groupId 为必填项")
	}

	model := domain.CreateModelContext(myContext)

	gi, err := group_m.GetInfoByTxGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}
	if gi == nil {
		return myContext, bizerr.GroupNotFound
	}
	groupId = gi.ImGroupId

	result := false
	if gi != nil && len(gi.Password) > 0 && userId != gi.Owner {
		result = true
	}

	resp.ResponseOk(c, result)
	return myContext, nil
}

type SimpleRoleInfo struct {
	ExternalId string                `json:"externalId"`
	Role       group_e.GroupRoleType `json:"role"`
}

// @Tags 群组
// @Summary 查询群角色
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param role query int false "指定的角色,不填的话代表全选"
// @Success 200 {object} []SimpleRoleInfo
// @Router /v1/imGroup/role/{groupId} [get]
func GetGroupRole(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	groupId := c.Param("groupId")
	if len(groupId) <= 0 {
		return myContext, myerr.NewSysError("groupId 为必填项")
	}
	var role group_e.GroupRoleType = 0
	r, err := strconv.Atoi(c.Query("role"))
	if err == nil {
		role = group_e.GroupRoleType(r)
	}

	userId, err := req.GetUserId(c)
	if err != nil {
		return myContext, err
	}

	model := domain.CreateModelContext(myContext)

	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}

	roles, orderList, err := group_m.GetRolesInGroup(model, groupId)
	if err != nil {
		return myContext, err
	}
	result := make([]SimpleRoleInfo, 0)

	userBases, err := user_cv.GetUserBaseMap(orderList, userId)
	if err != nil {
		return myContext, err
	}

	for _, i := range orderList {
		if role == 0 || role == roles[i] {
			result = append(result, SimpleRoleInfo{
				ExternalId: *userBases[i].ExternalId,
				Role:       roles[i],
			})
		}
	}

	resp.ResponseOk(c, result)
	return myContext, nil
}

// @Tags 群组
// @Summary 设置群角色/邀请游客成为群成员,邀请后需要对方同意
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param role formData int true "要赋予的角色"
// @Param externalId formData string true "用户的externalId"
// @Success 200
// @Router /v1/imGroup/role/{groupId} [put]
func SetGroupRole(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	groupId := c.Param("groupId")
	if len(groupId) <= 0 {
		return myContext, myerr.NewSysError("groupId 为必填项")
	}

	r, err := strconv.Atoi(c.PostForm("role"))
	if err != nil {
		return myContext, err
	}
	role := group_e.GroupRoleType(r)
	if role != group_e.GROUP_MANAGER && role != group_e.GROUP_ADMIN && role != group_e.GROUP_MEMBER && role != group_e.GROUP_VISITOR {
		return myContext, myerr.NewSysError("Invalid role")
	}

	model := domain.CreateModelContext(myContext)

	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}

	// 删除角色时没必要检查上限
	if role > group_e.GROUP_MEMBER {
		// 检查有没有超过上限 TODO: 如何防止并发?
		count, err := group_m.GetRoleCountInGroup(model, groupId, role)
		if err != nil {
			return myContext, err
		}

		if role == group_e.GROUP_MANAGER && count >= group_e.GROUP_MANAGER_LIMIT {
			return myContext, bizerr.RoleLimitReached
		}
		if role == group_e.GROUP_ADMIN && count >= group_e.GROUP_ADMIN_LIMIT {
			return myContext, bizerr.RoleLimitReached
		}
	}

	userId, myExtId, nick, avatar, _, err := req.GetUserEx(c, myContext)
	if err != nil {
		return myContext, err
	}

	// 检查用户是否有权限做操作
	myRole, err := group_m.GetRoleInGroup(model, userId, groupId)
	if err != nil {
		return myContext, err
	}

	// 管理员以下不能改变任何角色
	if myRole <= group_e.GROUP_ADMIN {
		return myContext, bizerr.NoPrivileges
	}
	if role == group_e.GROUP_MANAGER && myRole != group_e.GROUP_OWNER {
		return myContext, bizerr.NoPrivileges
	}
	if role == group_e.GROUP_ADMIN && myRole != group_e.GROUP_OWNER && myRole != group_e.GROUP_MANAGER {
		return myContext, bizerr.NoPrivileges
	}
	if (role == group_e.GROUP_VISITOR || role == group_e.GROUP_MEMBER) && myRole != group_e.GROUP_OWNER && myRole != group_e.GROUP_MANAGER {
		return myContext, bizerr.NoPrivileges
	}

	externalId := c.PostForm("externalId")
	model.Log.Info("externalId: ", externalId)

	//
	targetUser, err := user_m.GetUserByExtId(model, externalId)
	if err != nil {
		return myContext, err
	}

	isGroupMember, err := group_m.IsGroupMember(model.Db, groupId, targetUser.ID)
	if err != nil && err != gorm.ErrRecordNotFound {
		return myContext, err
	}

	// 邀请用户加入群组会员、把用户设置成游客
	if role == group_e.GROUP_VISITOR || (role == group_e.GROUP_MEMBER && !isGroupMember) {
		err = SetGroupMemberTourist(model, role, isGroupMember, targetUser.ID, userId, externalId, myExtId, groupId)
		if err != nil {
			return myContext, err
		}
		resp.ResponseOk(c, nil)
		return myContext, nil
	}

	if !isGroupMember {
		return myContext, bizerr.NotGroupMember
	}

	// 先读取旧角色
	oldRole, err := group_m.GetRoleInGroup(model, targetUser.ID, groupId)
	if err != nil {
		return myContext, err
	}

	if oldRole >= myRole {
		// 不能调整更高级者的角色!
		return myContext, bizerr.NoPrivileges
	}

	if role <= group_e.GROUP_MEMBER {
		// 如果已经没有角色,则不需要取消
		if oldRole != role {
			err = RemoveGroupRole(model, groupId, myExtId, externalId, nick, avatar, targetUser.Nick, targetUser.Avatar, targetUser.ID, oldRole)
			if err != nil {
				return myContext, err
			}
		}
	} else if err = group_m.CreateGroupRole(model, groupId, targetUser.ID, role); err == nil {
		// 发送信令
		systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupRoleChangeSignal, Source: myExtId, Target: externalId, Content: "add"}
		signal_s.SendSignalMsg(model, groupId, systemMsg, false)

		nobleLevel, err := noble_m.GetNobleLevel(model.Db, targetUser.ID)
		if err != nil {
			return myContext, err
		}

		// 发公屏消息
		msg := group_m.CommonPublicMsg{Type: group_e.RoleAssignedPublicScreenMsg,
			OperatorExternalId: myExtId, OperatorNick: nick, OperatorAvatar: avatar,
			ExternalId: targetUser.ExternalId, Nick: targetUser.Nick, Avatar: targetUser.Avatar, NobleLevel: nobleLevel,
			Role: role}
		buf, err := json.Marshal(msg)
		if err == nil {
			signal_s.SendCustomMsg(model, groupId, nil, string(buf))
		}
	} else {
		return myContext, err
	}
	// 发送腾讯云信令
	con := &GroupRoleChangeMsg{Role: int(role)}
	msgContent, _ := json.Marshal(con)
	signal_s.SendSignalMsg(model, groupId, group_m.GroupSystemMsg{
		MsgId:   group_e.GroupRoleChange,
		Source:  myExtId,
		Target:  externalId,
		Content: string(msgContent),
	}, false)

	// 新角色不是经理角度时,将其(可能)设置的欢迎语清除
	if role < group_e.GROUP_MANAGER {
		gwt := group_m.GroupWelcomeText{}
		if err = gwt.Remove(model.Db, groupId, targetUser.ID); err != nil {
			model.Log.Warnf("Can't remove group %s user %d's welcome text.", groupId, userId)
		}
	}

	resp.ResponseOk(c, nil)
	return myContext, nil
}

func RemoveGroupRole(model *domain.Model, groupId, myExtId, externalId, nick, avatar, targetNick, targetAvatar string,
	targetUserId uint64, oldRole group_e.GroupRoleType) error {
	if err := group_m.RemoveGroupRole(model, groupId, targetUserId); err == nil {
		// 发送信令
		systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupRoleChangeSignal, Source: myExtId, Target: externalId, Content: "remove"}
		signal_s.SendSignalMsg(model, groupId, systemMsg, false)

		nobleLevel, err := noble_m.GetNobleLevel(model.Db, targetUserId)
		if err != nil {
			return err
		}

		// 发公屏消息
		msg := group_m.CommonPublicMsg{Type: group_e.RoleRemovedPublicScreenMsg,
			OperatorExternalId: myExtId, OperatorNick: nick, OperatorAvatar: avatar,
			ExternalId: externalId, Nick: targetNick, Avatar: targetAvatar, NobleLevel: nobleLevel,
			Role: oldRole}
		buf, err := json.Marshal(msg)
		if err != nil {
			return err
		}
		signal_s.SendCustomMsg(model, groupId, nil, string(buf))
	}
	return nil
}

func SetGroupMemberTourist(model *domain.Model, role group_e.GroupRoleType, isGroupMember bool, userId, inviteUserId uint64,
	externalId, myExtId, imGroupId string) (err error) {
	var msgId group_e.TypeSignalMsg
	var msgContent string
	switch role {
	case group_e.GROUP_MEMBER:
		if isGroupMember { // 已经是成员,直接返回
			return nil
		}
		// 邀请对方成为成员
		// 插入邀请表
		err = group_m.InsertGroupInviteJoin(model, userId, inviteUserId, imGroupId)
		if err != nil {
			return err
		}
		msgId = group_e.GroupMemberInvite
	case group_e.GROUP_VISITOR:
		if !isGroupMember { // 不是成员,直接返回
			return nil
		}
		// 移除成员
		if err = group_s.NewGroupService(nil).LeaveGroupMember(model, imGroupId, userId, externalId); err != nil {
			return err
		}
		msgId = group_e.GroupRoleChange
		con := &GroupRoleChangeMsg{Role: int(group_e.GROUP_VISITOR)}
		jData, _ := json.Marshal(con)
		msgContent = string(jData)
	}
	if msgId > 0 {
		// 发送腾讯云信令
		signal_s.SendSignalMsg(model, imGroupId, group_m.GroupSystemMsg{
			MsgId:   msgId,
			Source:  myExtId,
			Target:  externalId,
			Content: msgContent,
		}, false)
	}
	return nil
}

type GroupRoleChangeMsg struct {
	Role int `json:"role"`
}

// @Tags 群组
// @Summary 接受邀请-成为永久成员
// @Param groupId formData string true "群ID"
// @Success 200
// @Router /v1/imGroup/role/accept [post]
func AcceptMemberInvite(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	groupId := c.Param("groupId")
	if len(groupId) <= 0 {
		return myContext, myerr.NewSysError("groupId 为必填项")
	}

	resp.ResponseOk(c, group_e.ADD_GROUP_DONE)
	return myContext, nil
}

// @Tags 群组
// @Summary 添加群黑名单(封禁)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param externalId formData string true "用户的externalId"
// @Param removeHistory formData bool true "是否删除聊天记录"
// @Param blackImei formData bool false "SVIP是否封禁设备和ip"
// @Success 200
// @Router /v1/imGroup/blacklist/{groupId} [put]
func AddGroupBlacklist(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	groupId := c.Param("groupId")
	if len(groupId) <= 0 {
		return myContext, myerr.NewSysError("groupId 为必填项")
	}

	removeHistory, err := strconv.ParseBool(c.PostForm("removeHistory"))
	if err != nil {
		return myContext, myerr.NewSysError("removeHistory 为必填项")
	}

	blackImei, err := strconv.ParseBool(c.PostForm("blackImei"))
	if err != nil {
		blackImei = false
	}

	userId, myExtId, nick, avatar, _, err := req.GetUserEx(c, myContext)
	if err != nil {
		return myContext, err
	}

	_, lang, err := req.GetUserIdLang(c, myContext)
	if err != nil {
		return myContext, err
	}

	model := domain.CreateModelContext(myContext)

	txGroupId := groupId
	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}

	myRole, err := group_m.GetRoleInGroup(model, userId, groupId)
	if err != nil {
		return myContext, err
	}

	if myRole < group_e.GROUP_ADMIN {
		return myContext, bizerr.NoPrivileges
	}

	externalId := c.PostForm("externalId")
	user, err := user_m.GetUserByExtId(model, externalId)
	if err != nil {
		return myContext, err
	}

	//超级管理人
	if flag, err := user_m.IsSuperManager(domain.CreateModelContext(myContext), user.ID); err != nil {
		return myContext, err
	} else if flag {
		return myContext, bizerr.OfficialStaffLimit
	}

	role, err := group_m.GetRoleInGroup(model, user.ID, groupId)
	if err != nil {
		return myContext, err
	}
	isGaming, err := game_m.IsGaming(model, user.ID, txGroupId)
	if err != nil {
		return myContext, err
	}
	if isGaming {
		return myContext, bizerr.GamingCannotKick
	}

	if err = CheckOptToSvip6(model, userId, user.ID, lang, 10); err != nil {
		return myContext, err
	}

	// svip
	svipMap, err := rpc.MGetUserSvip(model, []mysql.ID{userId, user.ID})
	if err != nil {
		return myContext, err
	}

	if myRole > role {
		// 是否svip封禁设备
		var userImei, userIp string
		if blackImei && role != group_e.GROUP_OWNER && role != group_e.GROUP_MANAGER {
			if v, ok := svipMap[userId]; ok && v.SvipLevel > 0 {
				userImei, err = user_m.GetUserImeiStr(model, user.ID)
				if err != nil {
					return myContext, err
				}
				userIpInfo, err := user_m.GetUserIpOrInit(model, user.ID)
				if err != nil {
					return myContext, err
				}
				userIp = userIpInfo.Ip
			}
		}
		// TODO: 先发信令和公屏消息,避免被封之人收不到
		// 发送信令
		type removeHistoryParam struct {
			RemoveHistory bool `json:"removeHistory"`
		}
		r := removeHistoryParam{RemoveHistory: removeHistory}
		buf, err := json.Marshal(r)
		if err == nil {
			systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupMemberRemoveSignal,
				Source: myExtId, Target: externalId, Content: string(buf)}
			signal_s.SendSignalMsg(model, groupId, systemMsg, false)
		}

		// 发公屏消息
		msg := group_m.CommonPublicMsg{Type: group_e.UserBannedPublicScreenMsg,
			OperatorExternalId: myExtId, OperatorNick: nick, OperatorAvatar: avatar,
			ExternalId: user.ExternalId, Nick: user.Nick, Avatar: user.Avatar}
		buf, err = json.Marshal(msg)
		if err == nil {
			signal_s.SendCustomMsg(model, groupId, nil, string(buf))
		}

		if err = group_s.NewGroupService(myContext).LeaveGroup(model, groupId, user.ID, externalId); err != nil {
			return myContext, err
		}

		gb := group_m.GroupBlacklist{ImGroupId: groupId, UserId: user.ID, Imei: userImei, Ip: userIp}
		err = group_m.AddBlacklist(model, &gb)
		if err != nil {
			model.Log.Errorf("AddBlacklist failed for %s, user %d", groupId, user.ID)
		}
	} else {
		return myContext, bizerr.NoPrivileges
	}

	resp.ResponseOk(c, nil)
	return myContext, nil
}

// 检查是否可以对svip6进行操作 optUserId:被操作的用户id
func CheckOptToSvip6(model *domain.Model, userId, optUserId uint64, lang string, privilegeId int) error {
	// 是否超管
	isM, err := user_m.IsSuperManagerV2(model, userId, optUserId)
	if err != nil {
		return err
	}
	// svip
	svipMap, err := rpc.MGetUserSvip(model, []mysql.ID{userId, optUserId})
	if err != nil {
		return err
	}
	if !isM {
		if svip, ok := svipMap[userId]; !ok || svip.SvipLevel < 6 { // 非svip6(svip6可以对svip6进行操作)
			// 是否禁止被封禁
			if svip, ok := svipMap[optUserId]; ok {
				for _, v := range svip.Privileges {
					if v.Type == privilegeId {
						return myerr.WrapErr(res_m.GetErrByLanguage(model.Db, msg_e.MSG_ID_NO_POWER_TO_SVIP6, lang, bizerr.GroupNoPowerToSvip6))
					}
				}
			}
		}
	}
	return nil
}

// @Tags 群组
// @Summary 移除群黑名单
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param externalId query string true "用户的externalId"
// @Success 200
// @Router /v1/imGroup/blacklist/{groupId} [delete]
func RemoveGroupBlacklist(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	groupId := c.Param("groupId")
	if len(groupId) <= 0 {
		return myContext, myerr.NewSysError("groupId 为必填项")
	}
	userId, err := req.GetUserId(c)
	if err != nil {
		return myContext, err
	}

	model := domain.CreateModelContext(myContext)

	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}

	myRole, err := group_m.GetRoleInGroup(model, userId, groupId)
	if err != nil {
		return myContext, err
	}

	if myRole < group_e.GROUP_ADMIN {
		return myContext, bizerr.NoPrivileges
	}

	externalId := c.Query("externalId")
	if len(externalId) <= 0 {
		return myContext, myerr.NewSysError("externalId 为必填项")
	}

	user, err := user_m.GetUserByExtId(model, externalId)
	if err != nil {
		return myContext, err
	}
	err = group_m.RemoveBlacklist(model, &group_m.GroupBlacklist{ImGroupId: groupId, UserId: user.ID})
	if err != nil {
		return myContext, err
	}

	resp.ResponseOk(c, nil)
	return myContext, nil
}

//拉黑列表视图
type GroupBlackList struct {
	//拉黑时间
	BlockTime int64 `json:"blockTime"`
	//用户基本信息
	UserBase user_cv.CvUserBase `json:"userBase"`
}

// @Tags 群组
// @Summary 查询群黑名单
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} GroupBlackList
// @Router /v1/imGroup/blacklist/{groupId} [get]
func GetGroupBlacklist(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	groupId := c.Param("groupId")
	if len(groupId) <= 0 {
		return myContext, myerr.NewSysError("groupId 为必填项")
	}

	userId, err := req.GetUserId(c)
	if err != nil {
		return myContext, err
	}

	model := domain.CreateModelContext(myContext)

	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}

	// TODO: 非群成员不能看
	rows, err := group_m.FindGroupBlackList(model, groupId)
	if err != nil {
		return myContext, err
	}

	userIds := make([]uint64, 0)
	for _, i := range rows {
		userIds = append(userIds, i.UserId)
	}
	users, err := user_cv.GetUserBaseMap(userIds, userId)
	if err != nil {
		return myContext, err
	}

	result := make([]GroupBlackList, 0)
	for _, i := range rows {
		result = append(result, GroupBlackList{
			BlockTime: i.CreatedTime.Unix(),
			UserBase:  *users[i.UserId],
		})
	}

	resp.ResponsePageOk(c, result, uint(len(result)), 1)
	return myContext, nil
}

// @Tags 群组
// @Summary 踢人出群(运营操作,慎用)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param externalId formData string true "用户的externalId"
// @Param removeHistory formData bool true "是否删除聊天记录"
// @Success 200
// @Router /v1/imGroup/kick/{groupId} [put]
func KickGroupMembers(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	groupId := c.Param("groupId")
	if len(groupId) <= 0 {
		return myContext, myerr.NewSysError("groupId 为必填项")
	}

	removeHistory, err := strconv.ParseBool(c.PostForm("removeHistory"))
	if err != nil {
		return myContext, myerr.NewSysError("removeHistory 为必填项")
	}

	userId, myExtId, _, _, _, err := req.GetUserEx(c, myContext)
	if err != nil {
		return myContext, err
	}

	if !user_m.IsSuperUser(userId) {
		return myContext, bizerr.NoPrivileges
	}

	model := domain.CreateModelContext(myContext)

	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}
	externalId := c.PostForm("externalId")
	user, err := user_m.GetUserByExtId(model, externalId)
	if err != nil {
		return myContext, err
	}

	role, err := group_m.GetRoleInGroup(model, user.ID, groupId)
	if err != nil {
		return myContext, err
	}

	if role > group_e.GROUP_MEMBER {
		// 不能踢有角色的人出去
		return myContext, bizerr.NoPrivileges
	}

	// 发送信令?
	type removeHistoryParam struct {
		RemoveHistory bool `json:"removeHistory"`
	}
	r := removeHistoryParam{RemoveHistory: removeHistory}
	buf, err := json.Marshal(r)
	if err == nil {
		systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupMemberRemoveSignal,
			Source: myExtId, Target: externalId, Content: string(buf)}
		signal_s.SendSignalMsg(model, groupId, systemMsg, false)
	}

	if err = group_s.NewGroupService(myContext).LeaveGroup(model, groupId, user.ID, externalId); err != nil {
		return myContext, err
	}

	resp.ResponseOk(c, nil)
	return myContext, nil
}

// @Tags 群组
// @Summary 设置入群欢迎语
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param text formData string true "欢迎语"
// @Success 200
// @Router /v1/imGroup/welcomeText/{groupId} [put]
func SetWelcomeText(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	groupId := c.Param("groupId")
	if len(groupId) <= 0 {
		return myContext, myerr.NewSysError("groupId 为必填项")
	}

	text := c.PostForm("text")
	if len(text) <= 0 {
		return myContext, bizerr.EmptyContent
	}
	if len([]rune(text)) > group_e.GROUP_INTRODUCTION_LENGTH_LIMIT {
		return myContext, bizerr.ContentTooLong
	}

	userId, _, err := req.GetUserIdAndExtId(c, myContext)
	if err != nil {
		return myContext, err
	}

	model := domain.CreateModelContext(myContext)
	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}
	if group_c.IsEditGroupCd(model, groupId) {
		return myContext, bizerr.EditCd
	}

	myRole, err := group_m.GetRoleInGroup(model, userId, groupId)
	if err != nil {
		return myContext, err
	}
	if myRole != group_e.GROUP_OWNER && myRole != group_e.GROUP_MANAGER {
		return myContext, bizerr.NoPrivileges
	}

	gwt := group_m.GroupWelcomeText{GroupId: groupId, UserId: userId, Text: text}
	if err = gwt.Save(model.Db); err != nil {
		return myContext, err
	}

	resp.ResponseOk(c, nil)
	return myContext, nil
}

// @Tags 群组
// @Summary 设置群成员上限(obsolete)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群组ID"
// @Param limit formData int true "成员上限"
// @Success 200
// @Router /v1/imGroup/memberLimit [put]
func SetGroupMemberLimit(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	groupId := c.PostForm("groupId")
	if len(groupId) <= 0 {
		return myContext, bizerr.ParaMissing
	}

	slimit := c.PostForm("limit")
	limit, err := strconv.Atoi(slimit)
	if err != nil || limit <= 0 {
		return myContext, bizerr.InvalidParameter
	}

	model := domain.CreateModelContext(myContext)

	groupInfo, err := group_m.GetInfoByTxGroupId(model, groupId)
	if err == nil && groupInfo != nil {
		err = tencentyun.SetGroupMaxMemberNum(groupInfo.ImGroupId, uint(limit))
		if err != nil {
			model.Log.Warn("SetGroupMemberLimit failed for ", groupId)
		}
	} else {
		model.Log.Warn("Skip group ", groupId)
	}

	resp.ResponseOk(c, nil)
	return myContext, nil
}

// @Tags 群组
// @Summary 社区管理员重置群信息
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param externalId formData string true "externalId"
// @Success 200
// @Router /v1/imGroup/info/reset [put]
func ResetGroupInfo(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)

	userId, err := req.GetUserId(c)
	if err != nil {
		return myContext, err
	}

	externalId := c.PostForm("externalId")
	if len(externalId) <= 0 {
		return myContext, bizerr.ParaMissing
	}

	model := domain.CreateModelContext(myContext)

	//isMgr, err := user_m.IsCommunityManager(model.Db, userId)
	//if err != nil {
	//	return myContext, err
	//}
	//if !isMgr {
	//	return myContext, bizerr.UserGlobalBroadcastManagerNo
	//}
	globalManager, countryManager, err := group_s.NewGroupService(myContext).CheckAppManager(userId)
	if err != nil {
		return myContext, err
	}
	if !globalManager && !countryManager {
		return myContext, bizerr.UserGlobalBroadcastManagerNo
	}

	user, err := user_m.GetUserByExtId(model, externalId)
	if err != nil {
		return myContext, err
	}

	if user == nil || user.ID <= 0 {
		return myContext, bizerr.ExternalIdNoExist
	}

	gi, err := group_m.FindGroupByOwner(model, user.ID)
	if err != nil {
		return myContext, err
	}

	if len(gi) <= 0 {
		return myContext, bizerr.GroupNotFound
	}
	// 额外判断国家管理员权限
	if !globalManager && countryManager {
		if isManager, _ := group_s.NewGroupService(myContext).CheckCountryManagerPermission(userId, user.ID); !isManager {
			return myContext, bizerr.UserGlobalBroadcastManagerNo
		}
	}

	if err = group_m.ResetGroupInfo(model, gi[0].ImGroupId, gi[0].Code); err != nil {
		return myContext, err
	}

	c.Set(mgr_e.OperationLogKey, mgr_m.MgrOperationLog{
		Content:   "管理员重置群信息",
		TargetUid: user.ID,
		OperUid:   userId,
	})
	resp.ResponseOk(c, nil)
	return myContext, nil
}

// @Tags 群组
// @Summary 清理公屏
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Success 200
// @Router /v1/imGroup/mgr/clearScreen [post]
func GroupMgrClearScreen(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)
	userId, err := req.GetUserId(c)
	if err != nil {
		return myContext, err
	}
	groupId := c.PostForm("groupId")
	if len(groupId) <= 0 {
		return myContext, bizerr.InvalidParameter
	}

	model := domain.CreateModelContext(myContext)
	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}

	if err := group_s.NewGroupService(myContext).GroupClearScreenByMgr(groupId, userId); err != nil {
		return myContext, err
	}
	resp.ResponseOk(c, "")
	return myContext, nil
}

type ReturnGroupThemeConfig struct {
	Days       int `json:"days"`
	NumLimit   int `json:"numLimit"`
	DiamondNum int `json:"diamondNum"`
}

// @Tags 群组
// @Summary 查询自定义主题
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Success 200 {object} ReturnGroupThemeConfig
// @Router /v1/imGroup/theme/custom/config [get]
func GroupThemeConfig(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)
	diamondOperateSet := diamond_m.DiamondOperateSet{}
	if err := mysql.Db.Model(&diamond_m.DiamondOperateSet{}).Where(&diamond_m.DiamondOperateSet{
		Type: diamond_e.GroupCustomTheme,
	}).First(&diamondOperateSet).Error; err != nil {
		return myContext, err
	}
	resp.ResponseOk(c, ReturnGroupThemeConfig{
		Days:       config.GetGroupCustomThemeConfig().DAY,
		NumLimit:   config.GetGroupCustomThemeConfig().PIC_LIMIT,
		DiamondNum: diamondOperateSet.DiamondNum,
	})
	return myContext, nil
}

type ReturnGroupThemeAdd struct {
	DiamondNum uint32 `json:"diamondNum"`
	ThemeId    uint64 `json:"themeId"`
	ThemeUrl   string `json:"themeUrl"`
}

// @Tags 群组
// @Summary 上传自定义主题
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param picUrl formData string true "主题URL"
// @Param groupId formData string true "群ID"
// @Success 200 {object} ReturnGroupThemeAdd
// @Router /v1/imGroup/theme/custom [post]
func GroupThemeAdd(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)
	userId, err := req.GetUserId(c)
	if err != nil {
		return myContext, err
	}
	picUrl := c.PostForm("picUrl")
	if picUrl == "" {
		return myContext, myerr.NewSysError("参数 picUrl 不能为空")
	}
	groupId := c.PostForm("groupId")
	if len(groupId) <= 0 {
		return myContext, bizerr.InvalidParameter
	}

	model := domain.CreateModelContext(myContext)
	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}

	switch config.GetConfigApp().MODERATE {
	case "AWS":
		passed, err := aws.ModerateLabels(model.Log, userId, picUrl)
		if err == nil {
			if !passed {
				return myContext, bizerr.ImagePolicyViolation
			}
		} else {
			model.Log.Warnf("ModerateLabels err:%v", err)
		}
	case "TENCENT":
		label, err := tencentyun.ModerateImage(model, userId, "", utils.StripAwsPrefix(picUrl), picUrl)
		if err == nil && label != "Pass" {
			return myContext, bizerr.ImagePolicyViolation
		}
	}

	themeId, themeUrl, err := group_s.NewGroupService(myContext).AddGroupCustomTheme(userId, groupId, picUrl)
	if err != nil {
		return myContext, err
	}
	diamond, err := diamond_cv.GetDiamond(userId)
	if err != nil {
		return nil, myerr.WrapErr(err)
	}
	resp.ResponseOk(c, ReturnGroupThemeAdd{
		DiamondNum: *diamond.DiamondNum,
		ThemeId:    themeId,
		ThemeUrl:   themeUrl,
	})
	return myContext, nil
}

// @Tags 群组
// @Summary 使用自定义主题
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupCustomThemeId formData int true "自定义主题ID"
// @Param groupId formData string true "群ID"
// @Success 200
// @Router /v1/imGroup/theme/custom/using [put]
func GroupThemeUsing(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)
	userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
	if err != nil {
		return myContext, err
	}
	groupId := c.PostForm("groupId")
	if len(groupId) <= 0 {
		return myContext, bizerr.InvalidParameter
	}

	model := domain.CreateModelContext(myContext)
	groupId, err = group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}

	id, err := strconv.ParseUint(c.PostForm("groupCustomThemeId"), 10, 64)
	if err != nil {
		return myContext, err
	}
	if err := group_s.NewGroupService(myContext).GroupCustomThemeUsing(userId, externalId, groupId, id); err != nil {
		return myContext, err
	}
	resp.ResponseOk(c, nil)
	return myContext, nil
}

type ResultGroupTheme struct {
	Id           uint64 `json:"id"`
	PicUrl       string `json:"picUrl"`
	RemainSecond int64  `json:"remainSecond"`
}

// @Tags 群组
// @Summary 查询有效的全部自定义主题
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId query string true "群ID"
// @Success 200 {object} ResultGroupTheme
// @Router /v1/imGroup/theme/custom/all [get]
func GroupThemeValidAll(c *gin.Context) (*mycontext.MyContext, error) {
	myContext := mycontext.CreateMyContext(c.Keys)
	groupId := c.Query("groupId")
	if len(groupId) <= 0 {
		return myContext, bizerr.InvalidParameter
	}

	model := domain.CreateModelContext(myContext)
	groupId, err := group_m.ToImGroupId(model, groupId)
	if err != nil {
		return myContext, err
	}

	var groupCustomThemes []group_m.GroupCustomTheme
	if err := mysql.Db.Where(&group_m.GroupCustomTheme{ImGroupId: groupId}).Where("expire_time > ?", time.Now()).Order("expire_time asc").Find(&groupCustomThemes).Error; err != nil {
		return myContext, err
	}
	//
	resultGroupThemes := make([]ResultGroupTheme, 0, len(groupCustomThemes))
	now := time.Now().Unix()
	for _, r := range groupCustomThemes {
		resultGroupThemes = append(resultGroupThemes, ResultGroupTheme{
			Id:           r.ID,
			PicUrl:       r.PicUrl,
			RemainSecond: r.ExpireTime.Unix() - now,
		})
	}
	resp.ResponseOk(c, resultGroupThemes)
	return myContext, nil
}