package controller

import (
	"context"
	"fmt"
	mhayaGin "github.com/mhaya/components/gin"
	mhayaTime "github.com/mhaya/extend/time"
	cfacade "github.com/mhaya/facade"
	"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/param"
	"github.com/mhaya/game/game_cluster/internal/third/tg_sign"
	"github.com/mhaya/game/game_cluster/internal/token"
	"github.com/mhaya/game/game_cluster/nodes/web/sdk"
	mhayaLogger "github.com/mhaya/logger"
	mhayaActor "github.com/mhaya/net/actor"
	"github.com/mhaya/net/parser/pomelo"
	"time"
)

type Controller struct {
	mhayaGin.BaseController
	Users
}

type (
	Users struct {
		pomelo.ActorBase
	}
	User struct {
		pomelo.ActorBase
		childExitTime time.Duration
	}
)

func (p *Users) GetChildActor(userName string) (cfacade.IActor, bool) {
	childActor, ok := p.Child().Get(userName)
	if !ok {
		var err error
		childActor, err = p.Child().Create(userName, &User{})
		if err != nil {
			return nil, false
		}
	}
	return childActor, true
}

func (cu *User) OnInit() {
	cu.childExitTime = time.Minute * 5
	cu.Timer().Add(30*time.Second, cu.sessionClose)
}

func (cu *User) sessionClose() {
	deadline := time.Now().Add(-cu.childExitTime).Unix()
	if cu.LastAt() < deadline {
		cu.Exit()
	}
}

func (p *Controller) Init() {
	group := p.Group("/")
	group.POST("/auth", p.auth)
	group.POST("/login", p.login)
	group.POST("/start", p.start)
	group.POST("/guide", p.guide)
	group.POST("/roll", p.roll)
	group.POST("/lottery", p.lottery)
	group.POST("/getLotteryConfig", p.getLotteryConfig)

	group.POST("/signIn", p.signIn)
	group.POST("/signInList", p.signInList)

	group.POST("/rank", p.rank)
	group.POST("/countryRank", p.countryRank)
	group.POST("/invite", p.invite)
	group.POST("/inviteRewardRatio", p.inviteRewardRatio)
	group.POST("/inviteClaimRatio", p.inviteClaimRatio)
	group.POST("/inviteNodeReward", p.inviteNodeReward)
	group.POST("/itemWeekRecord", p.itemWeekRecord)
	group.POST("/inviteRewardRatioHistory", p.inviteRewardRatioHistory)

	group.POST("/share", p.share)
	group.POST("/claim", p.claim)

	group.POST("/weeklyRankConfig", p.weeklyRankConfig)

	group.POST("/jump", p.jump)
	group.POST("/savex", p.savex)
	group.POST("/savetonwall", p.savetonwall)
	group.POST("/getLevel", p.getLevel)

	group.POST("/cashOut", p.cashOut)
	group.POST("/setPwd", p.setPwd)
	group.POST("/cashOutList", p.cashOutList)
	group.POST("/getLotteryHistory", p.getLotteryHistory)

	system := mhayaActor.NewSystem()
	system.SetApp(p.App)
	parentActor := &Users{}
	system.CreateActor(p.App.NodeId(), parentActor)
	p.Users = *parentActor

}

func (p *Controller) Auth(c *mhayaGin.Context) (*token.Token, int32) {
	tokenString := c.GetHeader(constant.Token)
	if tokenString == "" {
		return nil, code.AccountTokenValidateFail
	}

	userToken, ok := token.DecodeToken(tokenString)
	if ok == false {
		return nil, code.AccountTokenValidateFail
	}

	platformRow := data.SdkConfig.Get(userToken.PID)
	if platformRow == nil {
		return nil, code.AccountTokenValidateFail
	}

	_, ok = token.Validate(userToken, platformRow.Salt)
	if ok == false {
		return nil, code.AccountTokenValidateFail
	}
	oldToken := mdb.RDB.Get(context.Background(), fmt.Sprintf("%v:%v", constant.Token, userToken.OpenID)).Val()
	if oldToken != tokenString {
		return nil, code.AccountTokenValidateFail
	}
	/*
		sdkInvoke, err := sdk.GetInvoke(userToken.PID)
		if err != nil {
			mhayaLogger.Warnf("[Auth] [pid = %d] get invoke error. params=%v", userToken.PID, userToken)
			return nil, code.AccountTokenValidateFail
		}

		s, newToken := sdkInvoke.Reconnect(userToken)
		if code.IsFail(s) {
			mhayaLogger.Warnf("[Auth]  Reconnect err , errCode = %v", s)
			return nil, code.AccountTokenValidateFail
		}
		//如果重新刷新路由
		if newToken.TargetPath != userToken.TargetPath {
			config := data.SdkConfig.Get(newToken.PID)
			if config == nil {
				mhayaLogger.Warnf("[Auth] if config err.  params=%v", newToken)
				return nil, code.AccountTokenValidateFail
			}
			base64Token := token.New(userToken.PID, userToken.OpenID, userToken.PlayerID, newToken.TargetPath, "", config.Salt).ToBase64()
			err = mdb.RDB.Set(context.Background(), fmt.Sprintf("%v:%v", constant.Token, userToken.OpenID), base64Token, mhayaTime.SecondsPerWeek*time.Second).Err()
			if err != nil {
				mhayaLogger.Warnf("[Auth] result set token err. result = %s", newToken)
				return nil, code.AccountTokenValidateFail
			}

			ctl, ok := p.GetChildActor(newToken.PlayerID)
			if !ok {
				mhayaLogger.Warnf("[Auth] result set token err. result = %s", newToken)
				return nil, code.AccountTokenValidateFail
			}
			ctl.Call(userToken.TargetPath, "sessionClose", nil)

			errCode := ctl.Call(newToken.TargetPath, "login", newToken)
			if code.IsFail(errCode) {
				mhayaLogger.Warnf("[Auth] result set token err. result = %s", newToken)
				return nil, code.AccountTokenValidateFail
			}
		}
	*/

	return userToken, code.OK
}

// login 根据pid获取sdkConfig，与第三方进行帐号登陆效验
func (p *Controller) auth(c *mhayaGin.Context) {
	var pa param.LoginReq
	//body := c.GetBody()
	if err := c.BindJSON(&pa); err != nil {
		mhayaLogger.Warnf("[auth] if auth err. params=%v", pa)
		code.RenderResult(c, code.LoginError)
		return
	}

	config := data.SdkConfig.Get(pa.Pid)
	if config == nil {
		mhayaLogger.Warnf("[auth] if config err.  params=%v", pa)
		code.RenderResult(c, code.LoginError)
		return
	}

	//sdkConfig := data.SdkConfig.Get(2).Params

	//pa.Sign = "query_id=AAHdF6IQAAAAAN0XohDhrOrc&user=%7B%22id%22%3A279058397%2C%22first_name%22%3A%22Vladislav%22%2C%22last_name%22%3A%22Kibenko%22%2C%22username%22%3A%22vdkfrost%22%2C%22language_code%22%3A%22ru%22%2C%22is_premium%22%3Atrue%7D&auth_date=1662771648&hash=c501b71e775f74ce10e377dea85a7ea24ecd640b223ea86dfe453e0eaed2e2b2"
	//sdkConfig.BotToken = "5768337691:AAH5YkoiEuPk8-FZa32hStHTqXiLPtAEhx8"
	sg := p.App.Settings().GetBool("is_not_sign")
	if !sg {
		err := initdata.Validate(pa.Sign, config.Params.BotToken, 0)
		if err != nil {
			mhayaLogger.Warnf("[auth] if sign err.  params=%v", pa)
			code.RenderResult(c, code.LoginError)
			return
		}
	}

	sdkInvoke, err := sdk.GetInvoke(config.ID)
	if err != nil {
		mhayaLogger.Warnf("[auth] [pid = %d] get invoke error. params=%v", pa.Pid, pa)
		code.RenderResult(c, code.PIDError)
		return
	}

	params := c.GetParams(true)
	params["openid"] = pa.OpenID
	params["platform"] = pa.Platform
	params["channel"] = pa.Channel
	params["sign"] = pa.Sign
	params["ip"] = c.ClientIP()

	// 输出客户端 IP 地址
	//mhayaLogger.Debugf("[auth] [c.ClientIP() => ip = %s]", c.ClientIP())
	// invoke login
	sdkInvoke.Login(config, params, func(statusCode int32, result sdk.Result, error ...error) {
		if code.IsFail(statusCode) {
			mhayaLogger.Warnf("login validate fail. code = %d, params = %v", statusCode, c.GetParams())
			if len(error) > 0 {
				mhayaLogger.Warnf("code = %d, error = %s", statusCode, error[0])
			}

			code.RenderResult(c, statusCode)
			return
		}

		if result == nil {
			mhayaLogger.Warnf("callback result map is nil. params= %v", c.GetParams())
			code.RenderResult(c, code.LoginError)
			return
		}

		openId, found := result["open_id"].(string)
		if found == false {
			mhayaLogger.Warnf("callback result map not found `open_id`. result = %v", result)
			code.RenderResult(c, code.LoginError)
			return
		}

		playerId, found := result["player_id"].(string)
		if found == false {
			mhayaLogger.Warnf("callback result map not found `open_id`. result = %s", result)
			code.RenderResult(c, code.LoginError)
			return
		}
		targetPath, found := result["target_path"].(string)
		if found == false {
			mhayaLogger.Warnf("callback result map not found `targetPath`. result = %s", result)
			code.RenderResult(c, code.LoginError)
			return
		}

		/*		account, found := result["account"].(*models.Account)
				if found == false {
					mhayaLogger.Warnf("callback result map not found `account`. result = %s", result)
					code.RenderResult(c, code.LoginError)
					return
				}
				ctl, ok := p.GetChildActor(playerId)
				if !ok {
					mhayaLogger.Warnf("callback result GetChildActor err. result = %s", result)
					code.RenderResult(c, code.LoginError)
					return
				}
				dbPath := cfacade.NewChildPath("m-database", "dbs", playerId)
				ctl.Call(dbPath, "setAccountDb", account)
		*/
		//重新获取认证 需要断天原来服务器
		oldToken := mdb.RDB.Get(context.Background(), fmt.Sprintf("%v:%v", constant.Token, openId)).Val()
		if len(oldToken) > 0 {
			userToken, ok := token.DecodeToken(oldToken)
			if ok == false {
				mhayaLogger.Warnf("callback result set token err. result = %s", result)
				code.RenderResult(c, code.LoginError)
				return
			}
			//如果分配在不同节点需要断开原来服务器
			if userToken.TargetPath != targetPath {
				ctl, ok := p.GetChildActor(playerId)
				if !ok {
					mhayaLogger.Warnf("callback result GetChildActor err. result = %s", result)
					code.RenderResult(c, code.LoginError)
					return
				}
				ctl.Call(userToken.TargetPath, "sessionClose", nil)
			}
		}

		base64Token := token.New(pa.Pid, openId, playerId, targetPath, "", config.Salt).ToBase64()
		err = mdb.RDB.Set(context.Background(), fmt.Sprintf("%v:%v", constant.Token, openId), base64Token, mhayaTime.SecondsPerWeek*time.Second).Err()
		if err != nil {
			mhayaLogger.Warnf("callback result set token err. result = %s", result)
			code.RenderResult(c, code.LoginError)
			return
		}
		code.RenderResult(c, code.OK, base64Token)
	})
}
