package service import ( "context" "time" "gorm.io/gorm" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/repository" ) // NotificationService provides business logic for notifications and notification preferences. // Reference: Chatwoot app/services/notification_service.rb type NotificationService struct { db *gorm.DB notifRepo *repository.NotificationRepo prefRepo *repository.NotificationPreferenceRepo } // NewNotificationService creates a new Notification service with required dependencies. func NewNotificationService( db *gorm.DB, notifRepo *repository.NotificationRepo, prefRepo *repository.NotificationPreferenceRepo, ) *NotificationService { return &NotificationService{ db: db, notifRepo: notifRepo, prefRepo: prefRepo, } } // --- Notification CRUD operations --- // GetNotification retrieves a single notification by ID. func (s *NotificationService) GetNotification(ctx context.Context, id uint) (*model.Notification, error) { return s.notifRepo.FindByID(ctx, id) } // ListNotifications retrieves all notifications for a user with pagination. func (s *NotificationService) ListNotifications(ctx context.Context, userID uint, page, perPage int) ([]model.Notification, int64, error) { offset := (page - 1) * perPage return s.notifRepo.ListByUser(ctx, userID, offset, perPage) } // ListNotificationsByAccount retrieves notifications for a user within an account. func (s *NotificationService) ListNotificationsByAccount(ctx context.Context, userID uint, accountID uint, page, perPage int) ([]model.Notification, int64, error) { offset := (page - 1) * perPage return s.notifRepo.ListByUserAndAccount(ctx, userID, accountID, offset, perPage) } // CreateNotification creates a new notification. func (s *NotificationService) CreateNotification(ctx context.Context, notification *model.Notification) error { return s.notifRepo.Create(ctx, notification) } // MarkRead marks a single notification as read. func (s *NotificationService) MarkRead(ctx context.Context, id uint) error { return s.notifRepo.MarkRead(ctx, id) } // MarkAllRead marks all unread notifications for a user as read. func (s *NotificationService) MarkAllRead(ctx context.Context, userID uint) error { return s.notifRepo.MarkAllReadByUser(ctx, userID) } // MarkAllReadByAccount marks all unread notifications for a user within an account as read. func (s *NotificationService) MarkAllReadByAccount(ctx context.Context, userID uint, accountID uint) error { return s.notifRepo.MarkAllReadByUserAndAccount(ctx, userID, accountID) } // DeleteNotification soft-deletes a notification. func (s *NotificationService) DeleteNotification(ctx context.Context, id uint) error { return s.notifRepo.Delete(ctx, id) } // GetUnreadCount returns the number of unread notifications for a user. func (s *NotificationService) GetUnreadCount(ctx context.Context, userID uint) (int64, error) { return s.notifRepo.CountUnreadByUser(ctx, userID) } // --- Notification Preference operations --- // GetPreferences retrieves all notification preferences for a user within an account. func (s *NotificationService) GetPreferences(ctx context.Context, userID uint, accountID uint) ([]model.NotificationPreference, error) { return s.prefRepo.ListByUserAndAccount(ctx, userID, accountID) } // UpdatePreferences upserts notification preferences for a user within an account. func (s *NotificationService) UpdatePreferences(ctx context.Context, userID uint, accountID uint, prefs []model.NotificationPreference) error { // Enforce userID and accountID on each preference for i := range prefs { prefs[i].UserID = userID prefs[i].AccountID = &accountID } return s.prefRepo.BatchUpsert(ctx, prefs) } // --- Notification extension operations (G8) --- // Reference: Chatwoot notifications_controller.rb#snooze, #unread, #destroy_all // SnoozeNotification sets a snooze timestamp on a notification and clears its read_at. func (s *NotificationService) SnoozeNotification(ctx context.Context, id, userID, accountID uint, snoozedUntil time.Time) (*model.Notification, error) { return s.notifRepo.Snooze(ctx, id, userID, accountID, snoozedUntil) } // MarkNotificationUnread clears read_at on a notification, marking it as unread. func (s *NotificationService) MarkNotificationUnread(ctx context.Context, id, userID, accountID uint) (*model.Notification, error) { return s.notifRepo.MarkUnread(ctx, id, userID, accountID) } // DeleteAllNotifications deletes all notifications for a user within an account. func (s *NotificationService) DeleteAllNotifications(ctx context.Context, userID, accountID uint) error { return s.notifRepo.DeleteAllByUser(ctx, userID, accountID) }