package group_mic_s

import (
	"context"
	"encoding/json"
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/mycontext"
	"git.hilo.cn/hilo-common/resource/redisCli"
	uuid "github.com/satori/go.uuid"
	"hilo-group/_const/enum/group_e"
	"hilo-group/_const/redis_key"
	"hilo-group/domain/event/group_ev"
	"hilo-group/domain/model/groupPower_m"
	"hilo-group/domain/model/group_m"
	"hilo-group/domain/service/signal_s"
	"hilo-group/myerr"
	"hilo-group/myerr/bizerr"
	"time"
)

type GroupMicService struct {
	svc *domain.Service
}

func NewGroupPowerService(myContext *mycontext.MyContext) *GroupMicService {
	svc := domain.CreateService(myContext)
	return &GroupMicService{svc}
}

//修改群组中麦的数量
func (s *GroupMicService) GroupMicNumChange(groupId string, userId uint64, micNumType group_e.GroupMicNumType, micOn bool) error {
	model := domain.CreateModelContext(s.svc.MyContext)
	//数据库修改群组麦的数量
	//检查权限
	if err := group_m.CheckPermission(model, groupId, userId); err != nil {
		return err
	}
	//删除麦位数量类型缓存
	group_m.InitMicNumType(model, groupId, micNumType).ClearCache()

	//
	groupInfo, _ := group_m.GetGroupInfo(model, groupId)
	if groupInfo == nil {
		return bizerr.GroupNotFound
	}

	//判断数据是否发生了变化
	//关闭麦位
	if micOn == false {
		if groupInfo.MicOn == micOn {
			return nil
		}
	} else {
		if groupInfo.MicOn == micOn && groupInfo.MicNumType == micNumType {
			return nil
		}
	}
	//修改数据,然后数据持久化,
	g := group_m.GroupInfo{
		MicOn: micOn,
	}
	fields := []string{"mic_on"}
	//开启麦位才修改micNumType
	returnMicNumType := g.MicNumType
	if micOn == true {
		g.MicNumType = micNumType
		fields = append(fields, "mic_num_type")
		returnMicNumType = micNumType
	}
	db := g.Update(model, groupId, fields)
	if db.Error != nil {
		return myerr.WrapErr(db.Error)
	}

	//增加麦位数量类型缓存
	group_m.InitMicNumType(model, groupId, micNumType).AddCache()

	//麦位上的信息,清理
	group_m.ClearMic(groupId)

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

	r := Content{
		MicOn:      micOn,
		MicNumType: returnMicNumType,
		Timestamp:  time.Now().Unix(),
	}
	buf, err := json.Marshal(r)
	if err != nil {
		model.Log.Errorf("GroupMicNumChange Content json.Marshal err:%v", err)
	}
	// 发信令,让前端重新拉取,接受容错,
	signal_s.SendSignalMsg(model, groupId, group_m.GroupSystemMsg{
		MsgId:   group_e.GroupMicChangeSignal,
		Content: string(buf),
	}, false)

	group_m.MicNumChangeRPush(model, groupId, returnMicNumType, micOn)

	return nil
}

//加锁, sign作为密钥存在(预防被别人删除,比如:先者删除了后者的锁),
func redisLock(key string, sign string, expiration time.Duration, callBack func() error) error {
	flag, err := redisCli.GetRedis().SetNX(context.Background(), key, sign, expiration).Result()
	if err != nil {
		return myerr.WrapErr(err)
	}
	if flag {
		err = callBack()
		redisSign, _ := redisCli.GetRedis().Get(context.Background(), key).Result()
		if redisSign == sign {
			redisCli.GetRedis().Del(context.Background(), key)
		}
		return err
	} else {
		return bizerr.GroupConcurrencyLock
	}
}

//加入麦位,锁两秒
func (s *GroupMicService) GroupMicIn(groupUuid string, i int, userId uint64, externalId string) error {
	return redisLock(redis_key.GetPrefixGroupMicUserInLock(userId), uuid.NewV4().String(), time.Second*2, func() error {
		model := domain.CreateModel(s.svc.CtxAndDb)
		mic, err := group_m.GetMic(model, groupUuid, i)
		if err != nil {
			return err
		}
		return mic.In(userId, externalId)
	})
}

//离开麦位
func (s *GroupMicService) GroupMicLeave(groupUuid string, i int, userId uint64, externalId string) error {
	return redisLock(redis_key.GetPrefixGroupMicUserDelLock(groupUuid, i), uuid.NewV4().String(), time.Second*2, func() error {
		model := domain.CreateModel(s.svc.CtxAndDb)
		micUser, err := group_m.GetMicUser(model, groupUuid, i)
		if err != nil {
			return err
		}
		if micUser != nil {
			return micUser.LeaveByUser(userId, externalId)
		}
		return nil
	})
}

//邀请上麦,锁两秒
func (s *GroupMicService) GroupMicInvite(groupUuid string, operateUserId uint64, beInvitedExternalId string) error {
	model := domain.CreateModelContext(s.svc.MyContext)
	if err := group_m.InviteMicIn(model, groupUuid, operateUserId, beInvitedExternalId); err != nil {
		return err
	}
	return nil
}

//麦位加锁,
func (s *GroupMicService) GroupMicLock(userId uint64, externalId string, groupUuid string, i int) error {
	//后果等级不高,不需要加锁
	model := domain.CreateModelContext(s.svc.MyContext)
	mic, err := group_m.GetMic(model, groupUuid, i)
	if err != nil {
		return err
	}
	return mic.MgrLock(userId, externalId)
}

//麦位解锁
func (s *GroupMicService) GroupMicUnLock(userId uint64, externalId string, groupUuid string, i int) error {
	//后果等级不高,不需要加锁
	model := domain.CreateModelContext(s.svc.MyContext)
	mic, err := group_m.GetMic(model, groupUuid, i)
	if err != nil {
		return err
	}
	return mic.MgrUnLock(userId, externalId)
}

// 麦位静音
func (s *GroupMicService) GroupMicMute(userId uint64, externalId string, groupUuid string, i int) error {
	//后果等级不高,不需要加锁
	model := domain.CreateModelContext(s.svc.MyContext)
	mic, err := group_m.GetMic(model, groupUuid, i)
	if err != nil {
		return err
	}
	return mic.MgrMute(userId, externalId)
}

// 麦位解除静音
func (s *GroupMicService) GroupMicUnMute(userId uint64, externalId string, groupUuid string, i int) error {
	//后果等级不高,不需要加锁
	model := domain.CreateModelContext(s.svc.MyContext)
	mic, err := group_m.GetMic(model, groupUuid, i)
	if err != nil {
		return err
	}
	return mic.MgrUnMute(userId, externalId)
}

//开启麦
func (s *GroupMicService) GroupMicSpeechOpen(userId uint64, externalId string, groupUuid string, i int) error {
	//自己/管理人开启禁麦,并发率不高,后果等级不高
	model := domain.CreateModelContext(s.svc.MyContext)
	micUser, err := group_m.GetMicUser(model, groupUuid, i)
	if err != nil {
		return err
	}
	return micUser.SpeechOpen(userId, externalId)
}

//关闭麦
func (s *GroupMicService) GroupMicSpeechClose(userId uint64, externalId string, groupUuid, lang string, i int) error {
	model := domain.CreateModelContext(s.svc.MyContext)
	micUser, err := group_m.GetMicUser(model, groupUuid, i)
	if err != nil {
		return err
	}
	return micUser.SpeechClose(userId, externalId, lang)
}

//麦上的人群发消息
func (s *GroupMicService) GroupIMMassByInMic(groupId string, userId uint64, externalId string, content string) error {
	return s.svc.Transactional(func() error {
		model := domain.CreateModel(s.svc.CtxAndDb)
		micUser, err := group_m.GetMicUserByExternalId(model, externalId)
		if err != nil {
			return err
		}
		if err := micUser.ImMass(externalId); err != nil {
			return err
		}
		//校验群组ID
		if micUser.GroupUuid != groupId {
			return myerr.NewSysError("groupId 不一致, http:groupId <> micUser.groupId")
		}

		//获取群成员
		gm, err := group_m.GetMembers(model.Db, groupId)
		if err != nil {
			return err
		}
		uids := make([]uint64, 0)
		for _, i := range gm {
			//排除自己
			if userId != i.UserId {
				uids = append(uids, i.UserId)
			}
		}
		return group_ev.PublishGroupImMass(model, &group_ev.GroupImMassEvent{
			GroupId: groupId,
			UserId:  userId,
			Members: uids,
			Content: content,
		})
	})
}

// 群管理人群发消息
func (s *GroupMicService) GroupIMMassByMgr(groupId string, userId uint64, externalId string, content string) error {
	return s.svc.Transactional(func() error {
		model := domain.CreateModel(s.svc.CtxAndDb)
		//检查权限
		if err := group_m.CheckPermission(model, groupId, userId); err != nil {
			return err
		}
		//获取群成员
		gm, err := group_m.GetMembers(model.Db, groupId)
		if err != nil {
			return err
		}
		uids := make([]uint64, 0)
		for _, i := range gm {
			//排除自己
			if userId != i.UserId {
				uids = append(uids, i.UserId)
			}
		}
		return group_ev.PublishGroupImMass(model, &group_ev.GroupImMassEvent{
			GroupId: groupId,
			UserId:  userId,
			Members: uids,
			Content: content,
		})
	})
}

// 增加势力上麦经验/时长
func (s *GroupMicService) IncrGroupPowerOnMicExpAndTime(groupId string, userId uint64, joinMicTimestamp int64) error {
	var model = domain.CreateModelContext(s.svc.MyContext)
	exists, groupPowerId, err := groupPower_m.CheckGroupPowerUser(model, userId)
	if err != nil {
		return err
	}
	if !exists {
		return nil
	}
	// 获取势力下所有群组
	groups, err := groupPower_m.GetGroupPowerGroups(model, groupPowerId)
	if err != nil {
		return err
	}
	inGroup := false
	for _, group := range groups {
		if group.ImGroupId == groupId {
			inGroup = true
			break
		}
	}
	if !inGroup {
		return nil
	}
	// 增加势力上麦经验
	if err := groupPower_m.IncrGroupPowerExpOnMic(model, groupPowerId, userId, joinMicTimestamp); err != nil {
		model.Log.Errorf("IncrGroupPowerExpOnMic fail:%v", err)
	}
	// 增加势力上麦时长-月
	if err := groupPower_m.IncrGroupPowerStarOnMicMonth(model, groupPowerId, userId, joinMicTimestamp); err != nil {
		model.Log.Errorf("IncrGroupPowerStarOnMicMonth fail:%v", err)
	}
	// 增加势力上麦时长-天
	if err := groupPower_m.IncrGroupPowerStarOnMicDay(model, groupPowerId, userId, joinMicTimestamp); err != nil {
		model.Log.Errorf("IncrGroupPowerStarOnMicDay fail:%v", err)
	}
	return nil
}