package user import ( "context" "fmt" ) type Service struct { repo UserRepository } func NewService(repo UserRepository) *Service { return &Service{repo: repo} } func (s *Service) GetProfile(ctx context.Context, userID string) (*User, error) { return s.repo.GetByID(ctx, userID) } func (s *Service) UpdateProfile(ctx context.Context, userID string, req UpdateProfileRequest) (*User, error) { if err := validateProfileRequest(req); err != nil { return nil, err } if !req.HasBodyParams() { updated, err := s.repo.Update(ctx, userID, req) if err != nil { return nil, fmt.Errorf("update profile: %w", err) } return updated, nil } // Need to update profile + recalculate calories in a single transaction. // First, get current user to merge with incoming fields for calorie calculation. current, err := s.repo.GetByID(ctx, userID) if err != nil { return nil, fmt.Errorf("get user: %w", err) } // Merge current values with request to compute calories height := current.HeightCM if req.HeightCM != nil { height = req.HeightCM } weight := current.WeightKG if req.WeightKG != nil { weight = req.WeightKG } age := current.Age if req.Age != nil { age = req.Age } gender := current.Gender if req.Gender != nil { gender = req.Gender } activity := current.Activity if req.Activity != nil { activity = req.Activity } goal := current.Goal if req.Goal != nil { goal = req.Goal } calories := CalculateDailyCalories(height, weight, age, gender, activity, goal) var calReq *UpdateProfileRequest if calories != nil { calReq = &UpdateProfileRequest{DailyCalories: calories} } updated, err := s.repo.UpdateInTx(ctx, userID, req, calReq) if err != nil { return nil, fmt.Errorf("update profile: %w", err) } return updated, nil } func validateProfileRequest(req UpdateProfileRequest) error { if req.HeightCM != nil { if *req.HeightCM < 100 || *req.HeightCM > 250 { return fmt.Errorf("height_cm must be between 100 and 250") } } if req.WeightKG != nil { if *req.WeightKG < 30 || *req.WeightKG > 300 { return fmt.Errorf("weight_kg must be between 30 and 300") } } if req.Age != nil { if *req.Age < 10 || *req.Age > 120 { return fmt.Errorf("age must be between 10 and 120") } } if req.Gender != nil { if *req.Gender != "male" && *req.Gender != "female" { return fmt.Errorf("gender must be 'male' or 'female'") } } if req.Activity != nil { switch *req.Activity { case "low", "moderate", "high": default: return fmt.Errorf("activity must be 'low', 'moderate', or 'high'") } } if req.Goal != nil { switch *req.Goal { case "lose", "maintain", "gain": default: return fmt.Errorf("goal must be 'lose', 'maintain', or 'gain'") } } return nil }