package api

import(
	"errors"
	"net/http"
	"strings"

	"party.at/party/cmd/party/common"
	"party.at/party/internal/data"
	"party.at/party/internal/validator"
)

type Api struct {
	App *common.Application
}

func (api *Api) Authenticate(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Vary", "Authorization")

		authorizationHeader := r.Header.Get("Authorization")
		if authorizationHeader == "" {
			r = common.SetUser(r, data.AnonymousUser)
			next.ServeHTTP(w, r)
			return
		}

		headerParts := strings.Split(authorizationHeader, " ")
		if len(headerParts) != 2 || headerParts[0] != "Bearer" {
			api.errorResponse(w, r, data.ErrInvalidAuthToken)
			return
		}

		token := headerParts[1]
		v := validator.New()
		if data.ValidateTokenPlaintext(v, token); !v.Valid() {
			api.errorResponse(w, r, data.ErrInvalidAuthToken)
			return
		}

		userIdentity, err := api.App.Models.UserIdentities.GetForToken(data.ScopeAuthentication, token)
		if err != nil {
			switch {
			case errors.Is(err, data.ErrRecordNotFound):
				api.errorResponse(w, r, data.ErrInvalidAuthToken)
			default:
				api.ServerErrorResponse(w, r, err)
			}
			return
		}

		user, err := api.App.Models.Users.Get(userIdentity.UserID)
		if err != nil {
			switch {
			case errors.Is(err, data.ErrRecordNotFound):
				api.errorResponse(w, r, data.ErrInvalidCredentials)
			default:
				api.ServerErrorResponse(w, r, err)
			}
			return
		}

		r = common.SetUser(r, user)
		next.ServeHTTP(w, r)
	})
}
