package service import ( "context" "errors" "time" "git.threesix.ai/jordan/slate-v3-1770514618/pkg/logging" "git.threesix.ai/jordan/slate-v3-1770514618/services/preferences-api/internal/domain" "git.threesix.ai/jordan/slate-v3-1770514618/services/preferences-api/internal/port" ) // PreferencesService handles preferences-related business logic. type PreferencesService struct { repo port.PreferencesRepository logger *logging.Logger } // NewPreferencesService creates a new preferences service. func NewPreferencesService(repo port.PreferencesRepository, logger *logging.Logger) *PreferencesService { return &PreferencesService{ repo: repo, logger: logger.WithService("PreferencesService"), } } // Get returns preferences for a user. // Returns domain.ErrPreferencesNotFound if not found. func (s *PreferencesService) Get(ctx context.Context, userID domain.UserID) (*domain.Preferences, error) { return s.repo.Get(ctx, userID) } // Upsert creates or updates preferences for a user with merge semantics. // If no preferences exist, creates defaults and merges the update. // Validates the merged result before persisting. func (s *PreferencesService) Upsert(ctx context.Context, userID domain.UserID, update *domain.PreferencesUpdate) (*domain.Preferences, error) { prefs, err := s.repo.Get(ctx, userID) if err != nil { if !errors.Is(err, domain.ErrPreferencesNotFound) { return nil, err } prefs = domain.NewDefaultPreferences(userID) } prefs.MergeFrom(update) if err := prefs.Validate(); err != nil { return nil, err } prefs.UpdatedAt = time.Now().UTC() if err := s.repo.Upsert(ctx, userID, prefs); err != nil { return nil, err } s.logger.Info("preferences upserted", "user_id", userID.String()) return prefs, nil }