package testtoken

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

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

	"github.com/tidbcloud/metrics-server/central/db/tenant"
	"go.uber.org/zap"
)

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

func NewModel(log *zap.Logger, aesCrypt *encrypt.AESCrypt) Model {
	return Model{log, aesCrypt}
}

type Token struct {
	Token      string
	ExpireTime int64
}

const tokenPreFix = "CLOUD"

type Claims struct {
	Email      string
	ExpireTime int64
}

func (m Model) TryGetTestUserFromToken(rawToken string) *tenant.User {
	email := m.TryGetEmailFromTestToken(rawToken)
	if email == "" {
		return nil
	}
	user, found := tenant.GetUser(email)
	if found {
		return user
	}
	m.log.Info("find user failed", zap.String("email", email))
	return nil
}

func (m Model) 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 ""
}
