package token

import (
	"encoding/json"
	"fmt"
	mhayaCrypto "github.com/mhaya/extend/crypto"
	mhayaTime "github.com/mhaya/extend/time"
	"github.com/mhaya/game/game_cluster/internal/code"
	mhayaLogger "github.com/mhaya/logger"
)

const (
	hashFormat      = "pid:%d,openid:%s,playerid:%s,targetPath:%s,timestamp:%d"
	tokenExpiredDay = 3
)

type Token struct {
	PID        int    `json:"pid"`
	OpenID     string `json:"open_id"`
	PlayerID   string `json:"player_id"`
	TargetPath string `json:"target_path"`
	Nickname   string `json:"nickname"`
	Timestamp  int64  `json:"tt"`
	Hash       string `json:"hash"`
}

func New(pid int, openId, playerId, targetPath, nickName string, appKey string) *Token {
	token := &Token{
		PID:        pid,
		OpenID:     openId,
		PlayerID:   playerId,
		TargetPath: targetPath,
		Nickname:   nickName,
		Timestamp:  mhayaTime.Now().ToMillisecond(),
	}

	token.Hash = BuildHash(token, appKey)
	return token
}

func (t *Token) ToBase64() string {
	bytes, _ := json.Marshal(t)
	return mhayaCrypto.Base64Encode(string(bytes))
}

func DecodeToken(base64Token string) (*Token, bool) {
	if len(base64Token) < 1 {
		return nil, false
	}

	token := &Token{}
	bytes, err := mhayaCrypto.Base64DecodeBytes(base64Token)
	if err != nil {
		mhayaLogger.Warnf("base64Token = %s, validate error = %v", base64Token, err)
		return nil, false
	}

	err = json.Unmarshal(bytes, token)
	if err != nil {
		mhayaLogger.Warnf("base64Token = %s, unmarshal error = %v", base64Token, err)
		return nil, false
	}

	return token, true
}

func Validate(token *Token, appKey string) (int32, bool) {
	now := mhayaTime.Now()
	now.AddDays(tokenExpiredDay)

	if token.Timestamp > now.ToMillisecond() {
		mhayaLogger.Warnf("token is expired, token = %s", token)
		return code.AccountTokenValidateFail, false
	}

	newHash := BuildHash(token, appKey)
	if newHash != token.Hash {
		mhayaLogger.Warnf("hash validate fail. newHash = %s, token = %s", token)
		return code.AccountTokenValidateFail, false
	}

	return code.OK, true
}

func BuildHash(t *Token, appKey string) string {
	value := fmt.Sprintf(hashFormat, t.PID, t.OpenID, t.PlayerID, t.TargetPath, t.Timestamp)
	return mhayaCrypto.MD5(value + appKey)
}
