package jwt

import (
	"mini_server/internal/config"
	"mini_server/internal/dao"
	"net/http"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

var jwtKey = []byte(config.JwtKey)

type Claims struct {
	Username string `json:"username"`
	ID       int32  `json:"id"`
	jwt.StandardClaims
}

func CreateToken(user *dao.User) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, &Claims{
		ID:       user.ID,
		Username: user.Username,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: jwt.TimeFunc().Add(time.Hour * 24).Unix(), // Token expires in 24 hours
			IssuedAt:  jwt.TimeFunc().Unix(),
		},
	})
	return token.SignedString(jwtKey)
}

func AuthenticateToken(tokenString string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtKey, nil
	})
	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	} else {
		return nil, err
	}
}

func AuthMiddleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		if !withinWhiteList(ctx.Request.URL, ctx.Request.Method) {
			tokenString := ctx.GetHeader("Authorization")
			if tokenString == "" {
				ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
				return
			}

			claims, err := AuthenticateToken(tokenString)
			if err != nil {
				ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
				return
			}
			ctx.Set("user", claims)
		}
		ctx.Next()
	}
}
