package auth

import (
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/golang-jwt/jwt/v4"
	"golang.org/x/crypto/bcrypt"

	"git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/model"
)

const (
	ClaimNameKey = "name"
	claimUserKey = "user"
	claimExpKey  = "exp"
	defaultCost  = bcrypt.DefaultCost
)

type Config interface {
	JWTSecretKey() string
	JWTLifeTime() time.Duration
}

type Service struct {
	config Config
}

func Init(c Config) (*Service, error) {
	return &Service{config: c}, nil
}

func (a Service) GeneratePasswordHash(password string) (string, error) {
	res, err := bcrypt.GenerateFromPassword([]byte(password), defaultCost)
	if err != nil {
		return "", err
	}

	return string(res), nil
}

func (a Service) IsCorrectPassword(password string, hash string) bool {
	return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil
}

func (a Service) GetClaims(fctx *fiber.Ctx) jwt.MapClaims {
	jwtUser := fctx.Locals(claimUserKey).(*jwt.Token)
	claims := jwtUser.Claims.(jwt.MapClaims)

	return claims
}

func (a Service) GenerateToken(user model.User) (string, error) {
	claims := jwt.MapClaims{
		ClaimNameKey: user.Username,
		claimExpKey:  time.Now().Add(a.config.JWTLifeTime()).Unix(),
	}

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

	return token.SignedString([]byte(a.config.JWTSecretKey()))
}
