package jwt

import (
	"errors"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"maps"
)

type Jwt struct {
	options
}

func New(opts ...Option) *Jwt {
	res := new(Jwt)
	for _, o := range opts {
		o(&res.options)
	}

	return res
}

func (j *Jwt) GenToken(mp map[string]interface{}) (string, error) {
	claims := jwt.MapClaims{
		"exp": time.Now().Add(j.expire).Unix(),
	}

	maps.Copy(claims, mp)

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	return token.SignedString(j.salt)
}

func (j *Jwt) ParseToken(tokenStr string) (map[string]interface{}, error) {
	token, err := jwt.Parse(tokenStr, func(t *jwt.Token) (interface{}, error) {
		if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, jwt.ErrSignatureInvalid
		}

		return j.salt, nil
	})
	
	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid token")
}

func ErrorIsJwtExpired(err error) bool {
	return errors.Is(err, jwt.ErrTokenExpired)
}

func GetValueStringFromToken(jwt map[string]interface{}, key string) (string, bool) {
	if value, ok := jwt[key]; ok {
		if res, ok := value.(string); ok {
			return res, true
		}
	}

	return "", false
}

func GetValueInt64FromToken(jwt map[string]interface{}, key string) (int64, bool) {
	if value, ok := jwt[key]; ok {
		if res, ok := value.(int64); ok {
			return res, true
		}
	}

	return 0, false
}
