package auth

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

	"com.sismedika.com.absensi/graph/model"
	"com.sismedika.com.absensi/pkg/jwt"
)

var userCtxKey = &contextKey{"user"}

type contextKey struct {
	name string
}

type AuthRequest struct {
	isAuthenticated bool
	staff           model.Staff
}

func Middleware() func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			header := r.Header.Get("Authorization")
			AuthStatus := AuthRequest{isAuthenticated: false}
			// Allow unauthenticated users in
			if header == "" {
				ctx := context.WithValue(r.Context(), userCtxKey, &AuthStatus)
				r = r.WithContext(ctx)
				next.ServeHTTP(w, r)
				return
			}

			// validate jwt token
			tokenParts := strings.Split(header, " ")
			var tokenStr string
			if len(tokenParts) == 2 && tokenParts[0] == "Bearer" {
				tokenStr = tokenParts[1]
			}
			email, idGoogleSignIn, err := jwt.ParseToken(tokenStr)
			if err != nil {
				log.Printf("ParseToken: %v\n", err)
				ctx := context.WithValue(r.Context(), userCtxKey, &AuthStatus)
				r = r.WithContext(ctx)
				next.ServeHTTP(w, r)
				// boom.Unathorized(w, fmt.Errorf("AUTHORIZATION_HEADER_INVALID"))
				return
			}
			AuthStatus.staff = model.Staff{
				Email:          email,
				IDGoogleSignIn: idGoogleSignIn,
			}
			// put it in context
			ctx := context.WithValue(r.Context(), userCtxKey, &AuthStatus)

			// and call the next with our new context
			r = r.WithContext(ctx)
			next.ServeHTTP(w, r)
		})
	}
}

// ForContext finds the user from the context. REQUIRES Middleware to have run.
func ForContext(ctx context.Context) *model.Staff {
	raw, _ := ctx.Value(userCtxKey).(*model.Staff)
	return raw
}
