// monorepo/cloud/maplefile-backend/internal/maplefile/interface/http/middleware/jwt.go
package middleware

import (
	"context"
	"net/http"
	"strings"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config/constants"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
)

func (mid *middleware) JWTProcessorMiddleware(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()

		// Extract the Authorization header
		reqToken := r.Header.Get("Authorization")

		// Validate that Authorization header is present
		if reqToken == "" {
			problem := httperror.NewUnauthorizedError("Authorization not set")
			problem.WithInstance(r.URL.Path).
				WithTraceID(httperror.ExtractRequestID(r))
			httperror.RespondWithProblem(w, problem)
			return
		}

		// Extract the token from the Authorization header
		// Support both "Bearer" (RFC 6750 standard) and "JWT" schemes for compatibility
		var token string
		if strings.HasPrefix(reqToken, "Bearer ") {
			token = strings.TrimPrefix(reqToken, "Bearer ")
		} else if strings.HasPrefix(reqToken, "JWT ") {
			token = strings.TrimPrefix(reqToken, "JWT ")
		} else {
			problem := httperror.NewBadRequestError("Not properly formatted authorization header")
			problem.WithInstance(r.URL.Path).
				WithTraceID(httperror.ExtractRequestID(r))
			httperror.RespondWithProblem(w, problem)
			return
		}

		// Validate the token is not empty after prefix removal
		if token == "" {
			problem := httperror.NewBadRequestError("Not properly formatted authorization header")
			problem.WithInstance(r.URL.Path).
				WithTraceID(httperror.ExtractRequestID(r))
			httperror.RespondWithProblem(w, problem)
			return
		}

		// Process the JWT token
		sessionID, err := mid.jwt.ProcessJWTToken(token)
		if err != nil {
			// Log the actual error for debugging but return generic message to client
			mid.logger.Error("JWT processing failed", zap.Error(err))
			problem := httperror.NewUnauthorizedError("Invalid or expired token")
			problem.WithInstance(r.URL.Path).
				WithTraceID(httperror.ExtractRequestID(r))
			httperror.RespondWithProblem(w, problem)
			return
		}

		// Update our context to save our JWT token content information
		ctx = context.WithValue(ctx, constants.SessionIsAuthorized, true)
		ctx = context.WithValue(ctx, constants.SessionID, sessionID)

		// Flow to the next middleware with our JWT token saved
		fn(w, r.WithContext(ctx))
	}
}
