package middleware

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

	"gitea.local/admin/hspguard/internal/config"
	"gitea.local/admin/hspguard/internal/types"
	"gitea.local/admin/hspguard/internal/util"
	"gitea.local/admin/hspguard/internal/web"
)

type AuthMiddleware struct {
	cfg *config.AppConfig
}

func NewAuthMiddleware(cfg *config.AppConfig) *AuthMiddleware {
	return &AuthMiddleware{
		cfg,
	}
}

func (m *AuthMiddleware) Runner(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		authHeader := r.Header.Get("Authorization")
		if authHeader == "" {
			web.Error(w, "unauthorized", http.StatusUnauthorized)
			return
		}

		parts := strings.Split(authHeader, "Bearer ")
		if len(parts) != 2 {
			web.Error(w, "invalid auth header format", http.StatusUnauthorized)
			return
		}

		tokenStr := parts[1]
		var userClaims types.UserClaims

		token, err := util.VerifyToken(tokenStr, m.cfg.Jwt.PublicKey, &userClaims)
		if err != nil || !token.Valid {
			web.Error(w, fmt.Sprintf("invalid token: %v", err), http.StatusUnauthorized)
			return
		}

		ctx := context.WithValue(r.Context(), types.UserIdKey, userClaims.Subject)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func WithSkipper(mw func(http.Handler) http.Handler, excludedPaths ...string) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			for _, path := range excludedPaths {
				if strings.HasPrefix(r.URL.Path, path) {
					next.ServeHTTP(w, r)
					return
				}
			}
			mw(next).ServeHTTP(w, r)
		})
	}
}
