package handlers import ( "errors" "net/http" "time" "github.com/go-chi/chi/v5" "github.com/google/uuid" "git.threesix.ai/jordan/slack5-1770606136/pkg/app" "git.threesix.ai/jordan/slack5-1770606136/pkg/httperror" "git.threesix.ai/jordan/slack5-1770606136/pkg/httpresponse" "git.threesix.ai/jordan/slack5-1770606136/pkg/logging" "git.threesix.ai/jordan/slack5-1770606136/services/preferences-api/internal/domain" "git.threesix.ai/jordan/slack5-1770606136/services/preferences-api/internal/service" ) // Preference handles HTTP requests for user preference resources. type Preference struct { svc *service.PreferenceService logger *logging.Logger } // NewPreference creates a new Preference handler with injected dependencies. func NewPreference(svc *service.PreferenceService, logger *logging.Logger) *Preference { return &Preference{ svc: svc, logger: logger.WithComponent("PreferenceHandler"), } } // UpdatePreferencesRequest is the request body for updating preferences. type UpdatePreferencesRequest struct { Preferences map[string]any `json:"preferences"` } // PreferenceResponse is the response for a preference resource. type PreferenceResponse struct { UserID string `json:"user_id"` Preferences map[string]any `json:"preferences"` UpdatedAt string `json:"updated_at"` } // Get returns preferences for a user. func (h *Preference) Get(w http.ResponseWriter, r *http.Request) error { userID := chi.URLParam(r, "user_id") if _, err := uuid.Parse(userID); err != nil { return httperror.BadRequest("invalid user_id format") } prefs, err := h.svc.Get(r.Context(), userID) if err != nil { return err } if prefs == nil { httpresponse.OK(w, r, PreferenceResponse{ UserID: userID, Preferences: map[string]any{}, UpdatedAt: time.Now().UTC().Format(time.RFC3339), }) return nil } httpresponse.OK(w, r, toPreferenceResponse(prefs)) return nil } // Upsert creates or updates preferences for a user. func (h *Preference) Upsert(w http.ResponseWriter, r *http.Request) error { userID := chi.URLParam(r, "user_id") if _, err := uuid.Parse(userID); err != nil { return httperror.BadRequest("invalid user_id format") } var req UpdatePreferencesRequest if err := app.Bind(r, &req); err != nil { return err } if req.Preferences == nil { return httperror.BadRequest("preferences field is required") } result, err := h.svc.Upsert(r.Context(), service.UpsertInput{ UserID: userID, Preferences: req.Preferences, }) if err != nil { return mapPreferenceDomainError(err) } httpresponse.OK(w, r, toPreferenceResponse(result)) return nil } // toPreferenceResponse converts a domain UserPreferences to an API response. func toPreferenceResponse(p *domain.UserPreferences) PreferenceResponse { return PreferenceResponse{ UserID: p.UserID, Preferences: p.Preferences, UpdatedAt: p.UpdatedAt.Format(time.RFC3339), } } // mapPreferenceDomainError converts domain errors to HTTP errors. func mapPreferenceDomainError(err error) error { if errors.Is(err, domain.ErrInvalidPreferenceValue) { var valErr *service.ValidationError if errors.As(err, &valErr) { return httperror.WithDetails( httperror.Validation("Invalid preference values"), valErr.Details, ) } return httperror.BadRequest("invalid preference value") } return err }