package account

import (
	"context"
	mhayaTime "github.com/mhaya/extend/time"
	cutils "github.com/mhaya/extend/utils"
	"github.com/mhaya/game/game_cluster/internal/code"
	"github.com/mhaya/game/game_cluster/internal/constant"
	"github.com/mhaya/game/game_cluster/internal/data"
	"github.com/mhaya/game/game_cluster/internal/mdb"
	"github.com/mhaya/game/game_cluster/internal/mdb/models"
	"github.com/mhaya/game/game_cluster/internal/param"
	"github.com/mhaya/game/game_cluster/internal/third"
	cactor "github.com/mhaya/net/actor"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
	"strings"
	"time"
)

type (
	ActorAccount struct {
		cactor.Base
		time       int64
		serverLoad map[string]string
		account    models.Account
	}
)

func (p *ActorAccount) AliasID() string {
	return "account"
}

// OnInit center为后端节点，不直接与客户端通信，所以注册了一些remote函数，供RPC调用
func (p *ActorAccount) OnInit() {
	p.Remote().Register("registerAccount", p.registerOrLoinAccount)
	p.Timer().Add(5*time.Second, p.load)
	p.Timer().Add(time.Minute, p.Stat)
	p.Timer().Add(1*time.Minute, p.PlayerIpStat)
	p.Timer().Add(time.Minute, p.playerLevelStat)
	p.Timer().AddFixedHour(23, 59, 59, p.Stat)
	//p.Timer().AddOnce(30*time.Second, RunToMongoDB)
	// p.Timer().AddOnce(30*time.Second, RunToMongoDB)
}

func (p *ActorAccount) Stat() {
	daily := mhayaTime.Now().DailyTOTimeStamp()

	var dailyRecord models.DailyRecord
	dailyRecord.Daily = daily
	platformConfig := data.PlatformConfig.GatMap()
	channelConfig := data.ChannelConfig.GatMap()
	for _, v := range platformConfig {
		for _, v2 := range channelConfig {
			p.dailyStat(v.Name, v2.Name, daily)
		}
	}
}

func (p *ActorAccount) playerLevelStat() {
	platformConfig := data.PlatformConfig.GatMap()
	channelConfig := data.ChannelConfig.GatMap()
	for _, v := range platformConfig {
		for _, v2 := range channelConfig {
			p.levelStat(v.Name, v2.Name)
		}
	}
}

func (p *ActorAccount) PlayerIpStat() {
	daily := mhayaTime.Now().DailyTOTimeStamp()
	platformConfig := data.PlatformConfig.GatMap()
	channelConfig := data.ChannelConfig.GatMap()
	for _, v := range platformConfig {
		for _, v2 := range channelConfig {
			p.ipStat(v.Name, v2.Name, daily)
		}
	}
}

func (p *ActorAccount) load() {
	m, err := mdb.RDB.HGetAll(context.Background(), constant.ServerLoadHKey).Result()
	if err != nil {
		return
	}
	var stat models.PlayerServerLoadStat
	stat.Name = "load"
	stat.Load = m
	stat.TotalUser = p.userStat()
	stat.UpdateTime = mhayaTime.Now().Unix()
	mdb.MDB.Collection(constant.CNameServerLoadStat).UpdateOne(context.Background(), bson.M{"name": "load"}, bson.M{"$set": &stat}, options.Update().SetUpsert(true))
}

func (p *ActorAccount) userStat() int64 {
	var num int64

	platformConfig := data.PlatformConfig.GatMap()
	channelConfig := data.ChannelConfig.GatMap()

	for _, v := range platformConfig {
		for _, v2 := range channelConfig {
			num += models.GetTotalPlayerRecordLen(v.Name, v2.Name)
		}
	}
	return num
}

func (p *ActorAccount) ipStat(platform, channel string, daily int64) {
	var ipMap = make(map[string]int)
	ret, err := models.GetAllDailyRecordNewUserRegister(platform, channel, models.DailyRecordNewRegistered)
	if err != nil {
		return
	}

	for _, v := range ret {
		c, _ := third.GetCountryByIP(v)
		ipMap[c] += 1
	}
	var stat models.PlayerCountryStat
	stat.Daily = daily
	stat.Platform = platform
	stat.Channel = channel
	stat.PlayerRegisterCountry = ipMap
	stat.UpdateTime = mhayaTime.Now().Unix()
	mdb.MDB.Collection(constant.CNamePlayerCountryByIPStat).UpdateOne(context.Background(), bson.M{"platform": platform, "channel": channel, "daily": daily}, bson.M{"$set": &stat}, options.Update().SetUpsert(true))
}

func (p *ActorAccount) levelStat(platform, channel string) {
	level := make(map[string]int)
	ret, err := models.GetAllTotalPlayerRecord(platform, channel)
	if err != nil {
		return
	}
	for _, v := range ret {
		level[v] += 1
	}
	var stat models.PlayerLevelStat
	stat.Platform = platform
	stat.Channel = channel
	stat.ServerLevel = level
	stat.UpdateTime = mhayaTime.Now().Unix()
	mdb.MDB.Collection(constant.CNamePlayerLevelStat).UpdateOne(context.Background(), bson.M{"platform": platform, "channel": channel}, bson.M{"$set": &stat}, options.Update().SetUpsert(true))
}

func (p *ActorAccount) dailyStat(platform, channel string, daily int64) *models.DailyRecord {

	var dailyRecord models.DailyRecord
	dailyRecord.Daily = daily
	dailyRecord.Platform = platform
	dailyRecord.Channel = channel
	dailyRecord.Registered = models.GetAppointDailyRecordLen(platform, channel, daily, models.DailyRecordNewRegistered)
	dailyRecord.NewLogin = models.GetAppointDailyRecordLen(platform, channel, daily, models.DailyRecordNewLogin)
	dailyRecord.OldLogin = models.GetAppointDailyRecordLen(platform, channel, daily, models.DailyRecordOldLogin)
	dailyRecord.LoggedIn = dailyRecord.NewLogin + dailyRecord.OldLogin
	dailyRecord.NewActive = models.GetAppointDailyRecordLen(platform, channel, daily, models.DailyRecordNewActive)
	dailyRecord.OldActive = models.GetAppointDailyRecordLen(platform, channel, daily, models.DailyRecordOldActive)
	dailyRecord.ActiveUsers = dailyRecord.NewActive + dailyRecord.NewActive

	point, err := models.GetAppointDailyRecord(platform, channel, daily, models.DailyRecordTotalPoints)
	if err == nil {
		dailyRecord.TotalPoints = point
	}

	u, err := models.GetAppointDailyRecord(platform, channel, daily, models.DailyRecordUProduced)
	if err == nil {
		dailyRecord.UProduced = cutils.QuoInt64ByRatioToFloat64(u, constant.MoneyRatio)
	}

	uCashOut, err := models.GetAppointDailyRecord(platform, channel, daily, models.DailyRecordUCashout)
	if err == nil {
		dailyRecord.UCashout = cutils.QuoInt64ByRatioToFloat64(uCashOut, constant.MoneyRatio)
	}

	dailyRecord.CreatedAt = mhayaTime.Now().Unix()
	dailyRecord.UpdatedAt = mhayaTime.Now().Unix()

	mdb.MDB.Collection(constant.CNamePlayerDailyRecord).UpdateOne(context.Background(), bson.M{"platform": platform, "channel": channel, "daily": daily}, bson.M{"$set": &dailyRecord}, options.Update().SetUpsert(true))
	return &dailyRecord
}

// registerDevAccount 注册开发者帐号
func (p *ActorAccount) registerOrLoinAccount(req *param.LoginReq) (*param.LoginResp, int32) {

	if strings.TrimSpace(req.OpenID) == "" || strings.TrimSpace(req.IP) == "" || strings.TrimSpace(req.Platform) == "" || strings.TrimSpace(req.Channel) == "" {
		return nil, code.Error
	}
	account, err := p.account.AccountRegisterOrLogin(req)
	if err > 0 {
		return nil, code.Error
	}

	return &param.LoginResp{
		UserName: account.UserName,
		OpenId:   account.OpenId,
	}, code.OK
}
