package main

import (
	"fmt"
	"strconv"
	"time"

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

const tokenSecret = "tmp" // TODO delete in production
const tokenExpiration = time.Hour

func TokenCreate(userId uint32) (string, error) {
	now := time.Now()
	signedToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{
		Subject:   strconv.FormatUint(uint64(userId), 10),
		IssuedAt:  jwt.NewNumericDate(now),
		ExpiresAt: jwt.NewNumericDate(now.Add(tokenExpiration)),
	}).SignedString([]byte(tokenSecret))
	return signedToken, err
}

func TokenValidateGetId(tokenString string) (uint32, error) {
	token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
		if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
		}
		return []byte(tokenSecret), nil
	})
	if err != nil {
		return 0, err
	}

	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok || !token.Valid {
		return 0, fmt.Errorf("invalid token")
	}

	exp, ok := claims["exp"].(float64)
	if !ok || time.Now().Unix() > int64(exp) {
		return 0, fmt.Errorf("token expired")
	}

	sub, ok := claims["sub"].(string)
	if !ok {
		return 0, fmt.Errorf("invalid subject claim")
	}

	id, err := strconv.ParseUint(sub, 10, 32)
	if err != nil {
		return 0, fmt.Errorf("invalid subject claim")
	}

	return uint32(id), nil
}
