package authmiddleware

import (
	"context"
	"fmt"
	"net/http"
	"time"

	redisaccessor "legalgo-BE-go/internal/accessor/redis"
	"legalgo-BE-go/internal/utilities/response"
	"legalgo-BE-go/internal/utilities/utils"

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

const SessionHeader = "Authorization"

func Authorize() func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			ctx := r.Context()

			tokenString, err := utils.GetToken(r)
			if err != nil {
				response.RespondWithError(w, r, err, "Invalid auth header")
				return
			}

			spec, err := utils.GetTokenDetail(r)

			token, err := ValidateToken(ctx, spec.Email)
			if err != nil {
				response.RespondWithError(w, r, err, err.Error())
				return
			}

			isValid := token == tokenString

			if !isValid {
				response.RespondWithError(w, r, err, "invalid token")
				return
			}

			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

func ValidateToken(ctx context.Context, id string) (string, error) {
	redisClient := redisaccessor.Get()
	redisToken, err := utils.GetTokenRedis(ctx, redisClient, id)

	if err != nil {
		return "", err
	}

	token, err := utils.ParseToken(redisToken)

	if err != nil {
		return "", fmt.Errorf("invalid token: %w", err)
	}

	// Check if the token is valid
	if !token.Valid {
		return "", fmt.Errorf("invalid token: token is not valid")
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		expirationTime := claims["exp"].(float64) // Expiration time in Unix timestamp format
		if time.Unix(int64(expirationTime), 0).Before(time.Now()) {
			return "", fmt.Errorf("token has expired")
		}
	}

	return redisToken, nil
}
