package main

import (
	"mongo.games.com/goserver/core/basic"
	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/netlib"
	"mongo.games.com/goserver/core/task"

	"mongo.games.com/game/common"
	"mongo.games.com/game/model"
	rankproto "mongo.games.com/game/protocol/rank"
	"mongo.games.com/game/ranksrv/com"
	"mongo.games.com/game/ranksrv/rank"
)

func init() {
	// 排位赛排行榜
	com.Register(int(rankproto.Rank_PACKET_RANK_CSRankMatch), rankproto.CSRankMatch{}, CSRankMatch)
	// 金币榜
	com.Register(int(rankproto.Rank_PACKET_RANK_CSCoin), rankproto.CSCoin{}, CSCoin)
	// 邀请积分排行榜
	com.Register(int(rankproto.Rank_PACKET_RANK_CSInvite), rankproto.CSInvite{}, CSInvite)
	// 邀请记录
	com.Register(int(rankproto.Rank_PACKET_CSInviteLog), rankproto.CSInviteLog{}, CSInviteLog)
	// 收入榜
	com.Register(int(rankproto.Rank_PACKET_RANK_CSWinCoin), rankproto.CSWinCoin{}, CSWinCoin)
}

func CSRankMatch(s *netlib.Session, d *rankproto.GateTransmit, packetId int, data interface{}, sid int64) error {
	logger.Logger.Trace("CSRankMatch data:", data)
	msg, ok := data.(*rankproto.CSRankMatch)
	if !ok {
		return nil
	}

	rank.RankLevelMgrInstance.Take(d.Platform, msg.GetId(), func(list []*model.PlayerRankScore, err error) {
		if err != nil {
			logger.Logger.Errorf("CSRankMatch error: %v", err)
			return
		}

		page := msg.GetPage()
		if page < 0 {
			page = 0
		}
		pageSize := msg.GetPageSize()
		if pageSize < 1 {
			pageSize = 10
		}

		start := page * pageSize
		end := start + pageSize
		if end >= int32(len(list)) {
			end = int32(len(list))
		}

		var i int32
		var ranks []*rankproto.SeasonRank
		if end > start && int(start) < len(list) {
			for _, v := range list[start:end] {
				r := &rankproto.SeasonRank{
					Snid:    v.SnId,
					Name:    v.Name,
					Lv:      v.Lv,
					Rank:    start + i,
					Sex:     v.Sex,
					HeadUrl: v.HeadUrl,
					Coin:    v.Coin,
					Score:   v.Score,
					ModId:   v.ModId,
				}
				ranks = append(ranks, r)
				i++
			}
		}

		var me *rankproto.SeasonRank
		for k, v := range list {
			if v.SnId == d.Snid {
				me = &rankproto.SeasonRank{
					Snid:    v.SnId,
					Name:    v.Name,
					Lv:      v.Lv,
					Rank:    int32(k),
					Sex:     v.Sex,
					HeadUrl: v.HeadUrl,
					Coin:    v.Coin,
					Score:   v.Score,
					ModId:   v.ModId,
				}
				break
			}
		}

		pack := &rankproto.SCRankMatch{
			Ranks:    ranks,
			Me:       me,
			Page:     page,
			PageSize: pageSize,
			Total:    int32(len(list)),
		}

		common.SendToGate(sid, int(rankproto.Rank_PACKET_RANK_SCRankMatch), pack, s)
		logger.Logger.Tracef("SCRankMatch: %v", pack)
	})
	return nil
}

func CSCoin(s *netlib.Session, d *rankproto.GateTransmit, packetId int, data interface{}, sid int64) error {
	logger.Logger.Trace("CSCoin data:", data)
	msg, ok := data.(*rankproto.CSCoin)
	if !ok {
		return nil
	}

	rank.PlayerCoinMgrInstance.Take(d.Platform, 0, func(list []*model.RankPlayerCoin, err error) {
		if err != nil {
			logger.Logger.Errorf("CSCoin error: %v", err)
			return
		}

		page := msg.GetPage()
		if page < 0 {
			page = 0
		}
		pageSize := msg.GetPageSize()
		if pageSize < 1 {
			pageSize = 10
		}

		start := page * pageSize
		end := start + pageSize
		if end >= int32(len(list)) {
			end = int32(len(list))
		}

		var i int32
		var ranks []*rankproto.PlayerCoin
		if end > start && int(start) < len(list) {
			for _, v := range list[start:end] {
				r := &rankproto.PlayerCoin{
					Snid:    v.SnId,
					Name:    v.Name,
					Sex:     v.Sex,
					HeadUrl: v.HeadUrl,
					Coin:    v.Coin,
					Rank:    start + i,
					ModId:   v.ModId,
				}
				ranks = append(ranks, r)
				i++
			}
		}

		var me *rankproto.PlayerCoin
		for k, v := range list {
			if v.SnId == d.Snid {
				me = &rankproto.PlayerCoin{
					Snid:    v.SnId,
					Name:    v.Name,
					Sex:     v.Sex,
					HeadUrl: v.HeadUrl,
					Coin:    v.Coin,
					Rank:    int32(k),
					ModId:   v.ModId,
				}
				break
			}
		}

		pack := &rankproto.SCCoin{
			Ranks:    ranks,
			Me:       me,
			Page:     page,
			PageSize: pageSize,
			Total:    int32(len(list)),
		}

		common.SendToGate(sid, int(rankproto.Rank_PACKET_RANK_SCCoin), pack, s)
		logger.Logger.Tracef("SCCoin: %v", pack)
	})
	return nil
}

func CSInvite(s *netlib.Session, d *rankproto.GateTransmit, packetId int, data interface{}, sid int64) error {
	logger.Logger.Trace("CSInvite data:", data)
	msg, ok := data.(*rankproto.CSInvite)
	if !ok {
		return nil
	}

	rank.RankInviteMgrInstance.Take(d.Platform, msg.GetId(), func(list []*model.PlayerRankInvite, err error) {
		if err != nil {
			logger.Logger.Errorf("CSInvite error: %v", err)
			return
		}

		start, end := com.SkipLimitToStartEnd(msg.GetSkip(), msg.GetLimit(), len(list))

		IsEndNum := false
		if end == int32(len(list)) {
			IsEndNum = true
		}

		var i int32
		var ranks []*rankproto.InviteRank
		if end > start && int(start) < len(list) {
			for _, v := range list[start:end] {
				r := &rankproto.InviteRank{
					Snid:      v.SnId,
					Name:      v.Name,
					Rank:      start + i,
					Score:     v.Score,
					InviteNum: v.InviteNum,
					ModId:     v.ModId,
				}
				ranks = append(ranks, r)
				i++
			}
		}

		var me *rankproto.InviteRank
		for k, v := range list {
			if v.SnId == d.Snid {
				me = &rankproto.InviteRank{
					Snid:      v.SnId,
					Name:      v.Name,
					Score:     v.Score,
					Rank:      int32(k),
					InviteNum: v.InviteNum,
					ModId:     v.ModId,
				}
				break
			}
		}

		pack := &rankproto.SCInvite{
			Id:         msg.GetId(),
			Ranks:      ranks,
			Me:         me,
			Skip:       msg.GetSkip(),
			IsEndNum:   IsEndNum,
			RankMaxNum: model.GameParamData.RankInviteMaxNum,
		}

		common.SendToGate(sid, int(rankproto.Rank_PACKET_RANK_SCInvite), pack, s)
		logger.Logger.Tracef("SCInvite: %v", pack)
	})
	return nil
}

func CSInviteLog(s *netlib.Session, d *rankproto.GateTransmit, packetId int, data interface{}, sid int64) error {
	logger.Logger.Trace("CSInviteLog data:", data)
	msg, ok := data.(*rankproto.CSInviteLog)
	if !ok {
		return nil
	}

	rank.InviteLogMgrInstance.Take(d.Platform, d.Snid, func(list []*model.InviteInfo, err error) {
		if err != nil {
			logger.Logger.Errorf("CSInviteLog error: %v", err)
			return
		}

		start, end := com.SkipLimitToStartEnd(msg.GetSkip(), msg.GetLimit(), len(list))

		var ranks []*rankproto.InviteInfo
		for _, v := range list[start:end] {
			r := &rankproto.InviteInfo{
				Name:     v.Name,
				SnId:     v.SnId,
				CreateTs: v.CreateTs,
				Score:    v.Score,
				ModId:    v.ModId,
			}
			ranks = append(ranks, r)
		}

		pack := &rankproto.SCInviteLog{
			Skip:  start,
			Limit: msg.GetLimit(),
			List:  ranks,
		}

		common.SendToGate(sid, int(rankproto.Rank_PACKET_SCInviteLog), pack, s)
		logger.Logger.Tracef("SCInviteLog: %v", pack)
	})

	return nil
}

func CSWinCoin(s *netlib.Session, d *rankproto.GateTransmit, packetId int, data interface{}, sid int64) error {
	logger.Logger.Trace("CSWinCoin data:", data)
	msg, ok := data.(*rankproto.CSWinCoin)
	if !ok {
		return nil
	}

	ret := &rankproto.SCWinCoin{}
	var ranks []*rankproto.WinCoinInfo
	var me *rankproto.WinCoinInfo

	send := func() {
		ret.Ranks = ranks
		ret.Me = me
		common.SendToGate(sid, int(rankproto.Rank_PACKET_RANK_SCWinCoin), ret, s)
		logger.Logger.Tracef("SCWinCoin: %v", ret)
	}

	rank.WinCoinMgrInstance.Get(d.Platform, 0, func(list []*model.WinCoinInfo, err error) {
		if err != nil {
			logger.Logger.Errorf("CSWinCoin error: %v", err)
			return
		}

		start, end := com.SkipLimitToStartEnd(msg.GetSkip(), msg.GetLimit(), len(list))
		ret.Skip = start
		ret.Limit = msg.GetLimit()

		var i int32
		for _, v := range list[start:end] {
			r := &rankproto.WinCoinInfo{
				SnId:  v.SnId,
				Name:  v.Name,
				Rank:  start + i,
				Coin:  v.Coin,
				ModId: v.ModId,
			}
			ranks = append(ranks, r)
			i++
			if v.SnId == d.Snid {
				me = r
			}
		}

		if len(list) > 0 && me == nil {
			for k, v := range list {
				if v.SnId == d.Snid {
					me = &rankproto.WinCoinInfo{
						SnId:  v.SnId,
						Name:  v.Name,
						Rank:  int32(k),
						Coin:  v.Coin,
						ModId: v.ModId,
					}
					break
				}
			}
		}

		if me == nil {
			var err error
			var ret *model.FindWinCoinReply
			task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
				startTs, endTs := rank.StartEndTs()
				ret, err = model.FindWinCoinTienlen(&model.FindWinCoinArgs{
					Platform: d.Platform,
					StartTs:  startTs,
					EndTs:    endTs,
					SnId:     d.Snid,
				})
				if err != nil {
					logger.Logger.Errorf("FindWinCoinTienlen error: %v", err)
				}
				return nil
			}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
				if err == nil && ret.List != nil {
					me = &rankproto.WinCoinInfo{
						SnId:  ret.List.SnId,
						Name:  ret.List.Name,
						Rank:  -1,
						Coin:  ret.List.Coin,
						ModId: ret.List.ModId,
					}
				}
				send()
			})).Start()
		} else {
			send()
		}
	})
	return nil
}
