package main

import (
	"github.com/globalsign/mgo/bson"
	"mongo.games.com/game/model"
	"mongo.games.com/game/proto"
	"mongo.games.com/game/protocol/tournament"
	"mongo.games.com/game/srvdata"
	"mongo.games.com/goserver/core/basic"
	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/module"
	"mongo.games.com/goserver/core/task"
	"sort"
	"strconv"
	"time"
)

var MatchSeasonMgrSington = &MatchSeasonMgr{
	MatchSeasonList: make(map[int32]*MatchSeason),
	MatchSeasonId:   make(map[string]*MatchSeasonId),
}

type MatchSeasonMgr struct {
	BaseClockSinker
	MatchSeasonList map[int32]*MatchSeason    // snid:玩家赛季信息
	MatchSeasonId   map[string]*MatchSeasonId // platform:平台赛季信息
}

// MatchSeason 玩家赛季信息
type MatchSeason struct {
	Id       bson.ObjectId `bson:"_id"`
	Platform string
	SnId     int32
	Name     string
	SeasonId int32 //赛季id
	Lv       int32 //段位
	LastLv   int32 //上赛季段位
	IsAward  bool  //上赛季是否领奖
	AwardTs  int64 //领奖时间
	UpdateTs int64
	dirty    bool
}

// MatchSeasonId 赛季信息
type MatchSeasonId struct {
	Id         bson.ObjectId `bson:"_id"`
	Platform   string
	SeasonId   int32 //赛季id
	StartStamp int64 //开始时间戳
	EndStamp   int64 //结束时间戳
	UpdateTs   int64 //更新时间戳
}

func (this *MatchSeasonMgr) exchangeModel2Cache(mms *model.MatchSeason) *MatchSeason {
	if mms == nil {
		return nil
	}
	ms := &MatchSeason{
		Id:       mms.Id,
		Platform: mms.Platform,
		SnId:     mms.SnId,
		Name:     mms.Name,
		Lv:       mms.Lv,
		LastLv:   mms.LastLv,
		IsAward:  mms.IsAward,
		AwardTs:  mms.AwardTs,
		SeasonId: mms.SeasonId,
		UpdateTs: mms.UpdateTs,
	}
	return ms
}

func (this *MatchSeasonMgr) GetMatchSeason(snid int32) *MatchSeason {
	return this.MatchSeasonList[snid]
}

// GetAllMatchSeason 获取所有玩家赛季信息
func (this *MatchSeasonMgr) GetAllMatchSeason() map[int32]*MatchSeason {
	return this.MatchSeasonList
}

func (this *MatchSeasonMgr) SetMatchSeason(ms *MatchSeason) {
	if ms == nil {
		return
	}
	this.MatchSeasonList[ms.SnId] = ms
}

func (this *MatchSeasonMgr) DelMatchSeasonCache(snid int32) {
	if this.MatchSeasonList[snid] == nil {
		return
	}
	delete(this.MatchSeasonList, snid)
}

// UpdateMatchSeasonLv 修改玩家段位
// 通知段位变更
// 更新排行榜
func (this *MatchSeasonMgr) UpdateMatchSeasonLv(p *Player, addlv int32, dirty bool) {
	logger.Logger.Trace("(this *MatchSeasonMgr) UpdateMatchSeasonLv: SnId: ", p.SnId, " addlv: ", addlv)
	if p == nil || p.IsRob {
		return
	}
	platform := p.Platform
	if platform == DefaultPlatform {
		return
	}
	ms := this.GetMatchSeason(p.SnId)
	if ms != nil {
		ms.Lv = ms.Lv + addlv
		ms.dirty = true
		ms.UpdateTs = time.Now().Unix()
		msid := this.GetMatchSeasonId(platform)
		if msid != nil {
			if addlv != 0 || dirty { //段位有变化或者需要继承
				//通知客户端段位更新
				pack := &tournament.SCTMSeasonInfo{
					Id:              msid.SeasonId,
					SeasonTimeStamp: []int64{msid.StartStamp, msid.EndStamp},
					Lv:              ms.Lv,
					LastLv:          ms.LastLv,
					IsAward:         ms.IsAward,
				}
				proto.SetDefaults(pack)
				ok := p.SendToClient(int(tournament.TOURNAMENTID_PACKET_TM_SCTMSeasonInfo), pack)
				logger.Logger.Trace("SCTMSeasonInfoHandler: ok: ", ok, pack)
			}
			//更新排行榜
			logger.Logger.Trace("更新排行榜！！！")
			msrs := MatchSeasonRankMgrSington.GetMatchSeasonRank(platform)
			if msrs == nil { //排行榜没有数据 去缓存中取
				ams := MatchSeasonMgrSington.GetAllMatchSeason()
				mss := []*model.MatchSeason{}
				if ams != nil {
					for _, season := range ams {
						if season.Platform == platform {
							mms := &model.MatchSeason{
								Id:       season.Id,
								Platform: season.Platform,
								SnId:     season.SnId,
								Name:     season.Name,
								SeasonId: season.SeasonId,
								Lv:       season.Lv,
								LastLv:   season.LastLv,
								IsAward:  season.IsAward,
								AwardTs:  season.AwardTs,
							}
							mss = append(mss, mms)
						}
					}
				}
				if mss != nil && len(mss) > 0 {
					cmsrs := []*MatchSeasonRank{}
					sort.Slice(mss, func(i, j int) bool {
						return mss[i].Lv > mss[j].Lv
					})
					if len(mss) > model.GameParamData.MatchSeasonRankMaxNum {
						mss = append(mss[:model.GameParamData.MatchSeasonRankMaxNum])
					}
					for i := 0; i < len(mss); i++ {
						season := mss[i]
						msr := &MatchSeasonRank{
							Id:       season.Id,
							Platform: season.Platform,
							SnId:     season.SnId,
							Name:     season.Name,
							Lv:       season.Lv,
							UpdateTs: season.UpdateTs,
						}
						cmsrs = append(cmsrs, msr)
					}
					MatchSeasonRankMgrSington.SetMatchSeasonRank(platform, cmsrs)
				}
			}
			MatchSeasonRankMgrSington.UpdateMatchSeasonRank(p, ms.Lv)
		}
	}
}

// MatchSeasonInherit 查询段位继承
func (this *MatchSeasonMgr) MatchSeasonInherit(lv int32) int32 {
	logger.Logger.Trace("(this *MatchSeasonMgr) MatchSeasonInherit: lv: ", lv)
	destLv := int32(1)
	for _, v := range srvdata.PBDB_GamMatchLVMgr.Datas.GetArr() {
		if v.Star != nil && len(v.Star) > 1 {
			startStar := v.Star[0]
			endStar := v.Star[1]
			if lv >= startStar && lv <= endStar { //匹配段位
				destLv = v.Star2 //继承后段位
			}
		}
	}
	return destLv
}

// UpdateMatchSeasonAward 更新领奖时间
func (this *MatchSeasonMgr) UpdateMatchSeasonAward(snid int32) {
	logger.Logger.Trace("(this *MatchSeasonMgr) UpdateMatchSeasonAward ", snid)
	ms := this.GetMatchSeason(snid)
	if ms != nil {
		ms.IsAward = true
		ms.AwardTs = time.Now().Unix()
		ms.UpdateTs = time.Now().Unix()
		ms.dirty = true
	}
}

// SaveMatchSeasonData 保存玩家段位信息
// logout 删除缓存
func (this *MatchSeasonMgr) SaveMatchSeasonData(snid int32, logout bool) {
	logger.Logger.Trace("(this *MatchSeasonMgr) SaveMatchSeasonData ", snid)
	ms := this.MatchSeasonList[snid]
	if ms != nil && ms.dirty {
		ms.dirty = false
		mms := &model.MatchSeason{
			Id:       ms.Id,
			Platform: ms.Platform,
			SnId:     ms.SnId,
			Name:     ms.Name,
			Lv:       ms.Lv,
			LastLv:   ms.LastLv,
			IsAward:  ms.IsAward,
			AwardTs:  ms.AwardTs,
			SeasonId: ms.SeasonId,
			UpdateTs: ms.UpdateTs,
		}
		task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
			return model.UpsertMatchSeason(mms)
		}), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
			logger.Logger.Info("SaveMatchSeasonData!!!")
			if logout {
				this.DelMatchSeasonCache(snid)
			}
		})).StartByFixExecutor("SnId:" + strconv.Itoa(int(snid)))
	}
}

// SaveAllMatchSeasonData 保存所有玩家段位信息
func (this *MatchSeasonMgr) SaveAllMatchSeasonData() {
	for _, msl := range this.MatchSeasonList {
		this.SaveMatchSeasonData(msl.SnId, false)
	}
}

// UpdateMatchSeasonId 更新比赛场赛季配置
// 更新赛季配置
// 更新在线玩家段位
// 更新排行榜
func (this *MatchSeasonMgr) UpdateMatchSeasonId(platform string) {
	logger.Logger.Info("(this *MatchSeasonMgr) UpdateMatchSeasonId")
	if platform == DefaultPlatform {
		return
	}
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		ret, err := model.QueryMatchSeasonId(platform)
		if err != nil {
			return nil
		}
		return ret
	}), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
		var ret *model.MatchSeasonId
		if data == nil || data.(*model.MatchSeasonId) == nil {
			sstamp, estamp := this.getNowMonthStartAndEnd()
			ret = model.NewMatchSeasonId(platform, int32(1), sstamp, estamp) //初始化赛季
			task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
				return model.UpsertMatchSeasonId(ret)
			}), nil).StartByFixExecutor("UpsertMatchSeasonId")
		} else {
			ret = data.(*model.MatchSeasonId)
		}
		logger.Logger.Info("UpdateMatchSeasonId!!!", ret)
		if ret != nil {
			nowStamp := time.Now().Unix()
			if nowStamp < ret.StartStamp {
				logger.Logger.Error("赛季开始时间错误!!!")
			}
			if nowStamp >= ret.EndStamp { //新赛季
				logger.Logger.Info("新赛季!!!", ret)
				sstamp, estamp := this.getNowMonthStartAndEnd()
				ret.SeasonId++
				ret.StartStamp = sstamp
				ret.EndStamp = estamp
				task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
					return model.UpsertMatchSeasonId(ret)
				}), nil).StartByFixExecutor("UpsertMatchSeasonId")
				//排行榜内的段位继承
				MatchSeasonRankMgrSington.MatchSeasonRankInherit(platform)
				//通知平台玩家继承后的段位数据
				players := PlayerMgrSington.playerOfPlatform[platform]
				for _, p := range players {
					if p != nil && p.IsOnLine() && !p.IsRob {
						ms := MatchSeasonMgrSington.GetMatchSeason(p.SnId)
						if ms != nil {
							if ms.SeasonId < ret.SeasonId { //不同赛季段位继承
								num := ret.SeasonId - ms.SeasonId
								finalLv := ms.Lv
								for i := 0; i < int(num); i++ { //继承几次
									if i == int(num)-1 { //上个赛季
										ms.LastLv = finalLv
									}
									finalLv = MatchSeasonMgrSington.MatchSeasonInherit(finalLv)
								}
								ms.Lv = finalLv
								ms.SeasonId = ret.SeasonId
								ms.IsAward = false
								ms.UpdateTs = time.Now().Unix()
								ms.dirty = true
								MatchSeasonMgrSington.SetMatchSeason(ms) //更新缓存
								pack := &tournament.SCTMSeasonInfo{
									Id:              ret.SeasonId,
									SeasonTimeStamp: []int64{ret.StartStamp, ret.EndStamp},
									Lv:              ms.Lv,
									LastLv:          ms.LastLv,
									IsAward:         ms.IsAward,
								}
								proto.SetDefaults(pack)
								logger.Logger.Trace("SCTMSeasonInfo:", p.SnId, " pack: ", pack)
								p.SendToClient(int(tournament.TOURNAMENTID_PACKET_TM_SCTMSeasonInfo), pack)
							}
						}
					}
				}
			}
			this.MatchSeasonId[platform] = &MatchSeasonId{
				Id:         ret.Id,
				Platform:   ret.Platform,
				SeasonId:   ret.SeasonId,
				StartStamp: ret.StartStamp,
				EndStamp:   ret.EndStamp,
				UpdateTs:   ret.UpdateTs,
			}
		}
	})).StartByFixExecutor("platform: " + platform)
}

// GetMatchSeasonId 获取比赛场赛季配置
func (this *MatchSeasonMgr) GetMatchSeasonId(platform string) *MatchSeasonId {
	logger.Logger.Info("(this *MatchSeasonMgr) GetMatchSeasonId", platform)
	return this.MatchSeasonId[platform]
}

// 获取当月初和月末时间戳
func (this *MatchSeasonMgr) getNowMonthStartAndEnd() (int64, int64) {
	now := time.Now()
	first := now.Format("2006-01") + "-01"
	start, _ := time.ParseInLocation("2006-01-02", first, time.Local)
	last := start.AddDate(0, 1, 0).Format("2006-01-02")
	end, _ := time.ParseInLocation("2006-01-02", last, time.Local)
	return start.Unix(), end.Unix() - 1
}

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

func (this *MatchSeasonMgr) Init() {
	for _, platform := range PlatformMgrSingleton.GetPlatforms() {
		if platform.IdStr == DefaultPlatform {
			continue
		}
		this.UpdateMatchSeasonId(platform.IdStr)
	}
}

func (this *MatchSeasonMgr) Update() {
	this.SaveAllMatchSeasonData()
}

func (this *MatchSeasonMgr) Shutdown() {
	this.SaveAllMatchSeasonData()
	module.UnregisteModule(this)
}

func (this *MatchSeasonMgr) InterestClockEvent() int {
	//TODO implement me
	//panic("implement me")
	return 1 << CLOCK_EVENT_MONTH
}

func (this *MatchSeasonMgr) OnMonthTimer() {
	logger.Logger.Info("(this *MatchSeasonMgr) OnMonthTimer")
	for _, platform := range PlatformMgrSingleton.GetPlatforms() {
		if platform.IdStr == DefaultPlatform {
			continue
		}
		this.UpdateMatchSeasonId(platform.IdStr)
	}
}

func init() {
	module.RegisteModule(MatchSeasonMgrSington, time.Minute*1, 0)
	ClockMgrSington.RegisteSinker(MatchSeasonMgrSington)
}
