package auth

import (
	"crypto/rand"
	"encoding/hex"
	"errors"
	"net/http"
	"strings"
	"time"

	"github.com/alexedwards/argon2id"
	"github.com/golang-jwt/jwt/v5"
	"github.com/google/uuid"
)

func HashPassword(password string) (string, error) {
	return argon2id.CreateHash(password, argon2id.DefaultParams)
}

func CheckPasswordHash(password string, hash string) (bool, error) {
	return argon2id.ComparePasswordAndHash(password, hash)
}

func MakeJWT(userID uuid.UUID, tokenSecret []byte, expiresIn time.Duration) (string, error) {
	token := jwt.New(jwt.GetSigningMethod(jwt.SigningMethodHS256.Name))

	token.Claims = &jwt.RegisteredClaims{
		Issuer:    "chirpy-access",
		IssuedAt:  jwt.NewNumericDate(time.Now()),
		ExpiresAt: jwt.NewNumericDate(time.Now().Add(expiresIn)),
		Subject:   userID.String(),
	}

	return token.SignedString(tokenSecret)
}

func ValidateJWT(tokenString string, tokenSecret []byte) (uuid.UUID, error) {
	token, err := jwt.ParseWithClaims(tokenString, &jwt.RegisteredClaims{}, func(t *jwt.Token) (any, error) {
		return tokenSecret, nil
	})

	if err != nil {
		return uuid.Nil, err
	}

	userId, err := token.Claims.GetSubject()

	if err != nil {
		return uuid.Nil, err
	}

	validUserId, err := uuid.Parse(userId)

	if err != nil {
		return uuid.Nil, err
	}

	return validUserId, nil
}

func GetBearerToken(headers http.Header) (string, error) {
	authorizationHeader := headers.Get("Authorization")

	if strings.TrimSpace(authorizationHeader) == "" {
		return "", errors.New("Missing Authorization header")
	}

	token := strings.TrimPrefix(authorizationHeader, "Bearer ")

	return token, nil
}

func GetAPIKey(headers http.Header) (string, error) {
	authorizationHeader := headers.Get("Authorization")

	if strings.TrimSpace(authorizationHeader) == "" {
		return "", errors.New("Missing Authorization header")
	}

	apiKey := strings.TrimPrefix(authorizationHeader, "ApiKey ")

	return apiKey, nil
}

func MakeRefreshToken() string {
	bytes := make([]byte, 32)
	rand.Read(bytes)
	return hex.EncodeToString(bytes)
}
