package main

import (
	"mongo.games.com/game/model"
	"mongo.games.com/game/proto"
	"mongo.games.com/game/protocol/friend"
	"mongo.games.com/goserver/core/basic"
	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/module"
	"mongo.games.com/goserver/core/task"
	"time"
)

var FriendUnreadMgrSington = &FriendUnreadMgr{
	FriendUnreadList:  make(map[string]map[int32]map[int32]int),
	FriendUnreadDirty: make(map[string]map[int32]bool),
}

type FriendUnreadMgr struct {
	FriendUnreadList  map[string]map[int32]map[int32]int
	FriendUnreadDirty map[string]map[int32]bool
}

func (this *FriendUnreadMgr) AddFriendUnread(platform string, snid, chatsnid int32) {
	if this.FriendUnreadList[platform] != nil {
		if ful, exist := this.FriendUnreadList[platform][snid]; !exist {
			ful = make(map[int32]int)
			ful[chatsnid] = 1
			this.FriendUnreadList[platform][snid] = ful
		} else {
			had := false
			for cSnid, unreadNum := range ful {
				if cSnid == chatsnid {
					unreadNum++
					had = true
					break
				}
			}
			if !had {
				ful[chatsnid] = 1
			}
		}
		if this.FriendUnreadDirty[platform] == nil {
			this.FriendUnreadDirty[platform] = make(map[int32]bool)
		}
		this.FriendUnreadDirty[platform][snid] = true
	}
}

func (this *FriendUnreadMgr) DelFriendUnread(platform string, snid, chatsnid int32) {
	if this.FriendUnreadList[platform] == nil {
		return
	}
	if ful, exist := this.FriendUnreadList[platform][snid]; exist {
		delete(ful, chatsnid)
		if this.FriendUnreadDirty[platform] == nil {
			this.FriendUnreadDirty[platform] = make(map[int32]bool)
		}
		this.FriendUnreadDirty[platform][snid] = true
	}
}

func (this *FriendUnreadMgr) LoadFriendUnreadData(platform string, snid int32) {
	if this.FriendUnreadList[platform] == nil {
		this.FriendUnreadList[platform] = make(map[int32]map[int32]int)
	}
	if _, exist := this.FriendUnreadList[platform][snid]; exist {
		return
	}
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		ret, err := model.QueryFriendUnreadBySnid(platform, snid)
		if err != nil {
			return nil
		}
		return ret
	}), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
		if ret, ok := data.(*model.FriendUnread); ok && ret != nil {
			if ret.UnreadSnids != nil && len(ret.UnreadSnids) > 0 {
				this.FriendUnreadList[platform][ret.Snid] = make(map[int32]int)
				for _, us := range ret.UnreadSnids {
					this.FriendUnreadList[platform][ret.Snid][us.SnId] = int(us.UnreadNum)
				}
				if this.FriendUnreadDirty[platform] == nil {
					this.FriendUnreadDirty[platform] = make(map[int32]bool)
				}
				this.FriendUnreadDirty[platform][ret.Snid] = false
				this.CheckSendFriendUnreadData(platform, ret.Snid)
			}
		}
	})).StartByFixExecutor("QueryFriendUnreadBySnid")
}

func (this *FriendUnreadMgr) CheckSendFriendUnreadData(platform string, snid int32) {
	if this.FriendUnreadList[platform] == nil {
		return
	}
	if ful, exist := this.FriendUnreadList[platform][snid]; exist {
		if ful == nil || len(ful) == 0 {
			return
		}
		pack := &friend.SCFriendUnreadData{}
		for cSnid, unreadNum := range ful {
			isFriend := FriendMgrSington.IsFriend(platform, snid, cSnid)
			if isFriend {
				fu := &friend.FriendUnread{
					Snid:      proto.Int32(cSnid),
					UnreadNum: proto.Int(unreadNum),
				}
				pack.FriendUnreads = append(pack.FriendUnreads, fu)
			} else {
				delete(ful, cSnid)
				if this.FriendUnreadDirty[platform] == nil {
					this.FriendUnreadDirty[platform] = make(map[int32]bool)
				}
				this.FriendUnreadDirty[platform][snid] = true
			}
		}
		if len(pack.FriendUnreads) > 0 {
			proto.SetDefaults(pack)
			p := PlayerMgrSington.GetPlayerBySnId(snid)
			if p != nil {
				p.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendUnreadData), pack)
				logger.Logger.Trace("SCFriendUnreadData: 未读消息列表 pack: ", pack)
			}
		}
	}
}

func (this *FriendUnreadMgr) SaveFriendUnreadData(platform string, snid int32) {
	if this.FriendUnreadDirty[platform] == nil || this.FriendUnreadList[platform] == nil {
		return
	}
	if dirty, exist := this.FriendUnreadDirty[platform][snid]; exist {
		if dirty {
			if ful, ok := this.FriendUnreadList[platform][snid]; ok {
				fu := model.NewFriendUnread(snid)
				for cSnid, unreadNum := range ful {
					if unreadNum > 0 && FriendMgrSington.IsFriend(platform, snid, cSnid) {
						us := &model.FriendUnreadSnid{
							SnId:      cSnid,
							UnreadNum: int32(unreadNum),
						}
						fu.UnreadSnids = append(fu.UnreadSnids, us)
					}
				}
				task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
					model.UpdateFriendUnread(platform, snid, fu)
					return nil
				}), nil).StartByFixExecutor("UpdateFriendUnread")
			}
		}
	}
}

func (this *FriendUnreadMgr) ModuleName() string {
	return "FriendUnreadMgr"
}

func (this *FriendUnreadMgr) Init() {
}

func (this *FriendUnreadMgr) Update() {
}

func (this *FriendUnreadMgr) Shutdown() {
	for platform, friendUnreadDirty := range this.FriendUnreadDirty {
		for snid, dirty := range friendUnreadDirty {
			if dirty {
				this.SaveFriendUnreadData(platform, snid)
			}
		}
	}
	module.UnregisteModule(this)
}

func init() {
	module.RegisteModule(FriendUnreadMgrSington, time.Hour, 0)
}
