package main

import (
	"errors"
	"time"

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

type JwtType string

const (
	Access  JwtType = "access"
	Refresh JwtType = "refresh"
)

type JwtClaims struct {
	UserID string
	Type   JwtType
	Expire time.Time
}

// obviously this is very not secure. TODO: extract to env
var JWT_SECRET = []byte("very secret")

func createToken(claims JwtClaims) *jwt.Token {
	return jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"UserID": claims.UserID,
		"Type":   claims.Type,
		"Expire": claims.Expire,
	})
}

func CreateRefreshToken(userId uuid.UUID) string {
	token := createToken(JwtClaims{
		UserID: userId.String(),
		Type:   Refresh,
		Expire: time.Now().Add(time.Hour * 24 * 7),
	})

	// TODO: bruh what is this
	tokenString, err := token.SignedString(JWT_SECRET)
	if err != nil {
		panic(err)
	}

	return tokenString
}

func CreateAccessToken(userId uuid.UUID) string {
	token := createToken(JwtClaims{
		UserID: userId.String(),
		Type:   Access,
		Expire: time.Now().Add(time.Hour),
	})

	// TODO: bruh what is this
	tokenString, err := token.SignedString(JWT_SECRET)
	if err != nil {
		panic(err)
	}

	return tokenString
}

var NotValidToken = errors.New("Not a valid token")

func GetUserIdFromAccess(accessToken string) (uuid.UUID, error) {
	token, err := jwt.Parse(accessToken, func(token *jwt.Token) (any, error) {
		return JWT_SECRET, nil
	}, jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}))

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

	// Blah blah, check expiry and stuff

	// this function is stupid
	if claims, ok := token.Claims.(jwt.MapClaims); ok {
		tokenType, ok := claims["Type"]
		if !ok || tokenType.(string) != "access" {
			return uuid.Nil, NotValidToken
		}

		userId, err := uuid.Parse(claims["UserID"].(string))
		if err != nil {
			return uuid.Nil, NotValidToken
		}

		return userId, nil
	} else {
		return uuid.Nil, NotValidToken
	}
}
