package token

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"strings"
	"sync"
	"time"

	"github.com/tidbcloud/account/commons/config"
	"github.com/tidbcloud/tiinf/monitor/tilog"

	"github.com/tidbcloud/pkgv2/secret/encrypt"

	"go.uber.org/zap"
)

// Model is created with NewModel
type TestTokenSvc struct {
	log      *zap.Logger
	aesCrypt *encrypt.AESCrypt
}

var (
	testTokenSvcInitOnce sync.Once
	testTokenSvcInstance TestTokenSvc
)

func GetTestTokenSvc() (TestTokenSvc, error) {
	testTokenSvcInitOnce.Do(func() {
		testTokenSvcInstance = NewTestTokenSvc()

	})
	return testTokenSvcInstance, nil
}

func NewTestTokenSvc() TestTokenSvc {
	log := tilog.WithContextL(context.Background())

	serverConfig := config.Global().ServerConfig
	aesCrypt, _ := encrypt.NewAESCrypt([]byte(serverConfig.SaltSecret))

	return TestTokenSvc{log, aesCrypt}
}

const tokenPreFix = "CLOUD"
const TokenTypeTest = "testtoken"

type Claims struct {
	Email      string
	ExpireTime int64
}

func (m TestTokenSvc) TryGetEmailFromTestToken(rawToken string) string {
	if strings.HasPrefix(rawToken, tokenPreFix) {
		newToken := strings.TrimPrefix(rawToken, tokenPreFix)
		claims := Claims{}
		newTokenData, err := base64.URLEncoding.DecodeString(newToken)
		if err != nil {
			m.log.Error("decode token failed", zap.String("token", rawToken), zap.Error(err))
			return ""
		}
		if err := json.Unmarshal(m.aesCrypt.Decrypt(newTokenData), &claims); err != nil {
			m.log.Error("parse token failed", zap.String("token", rawToken), zap.Error(err))
			return ""
		}
		if claims.ExpireTime < time.Now().Unix() {
			m.log.Info("token is expired", zap.Int64("time", claims.ExpireTime))
			return ""
		}
		return claims.Email
	}
	return ""
}
