package notification import ( "context" "errors" "fmt" "tm/pkg/logger" "tm/pkg/response" ) // NotificationService defines the interface for notification business logic type NotificationService interface { Create(ctx context.Context, req *NotificationRequest) (*NotificationResponse, error) Update(ctx context.Context, id string, req *NotificationRequest) (*NotificationResponse, error) Get(ctx context.Context, id string) (*NotificationResponse, error) Search(ctx context.Context, req *SearchForm, pagination *response.Pagination) (*NotificationsResponse, error) Delete(ctx context.Context, id string) error } // notificationService implements NotificationService interface type notificationService struct { repository NotificationRepository logger logger.Logger } // NewNotificationService creates a new notification service func NewNotificationService( repository NotificationRepository, logger logger.Logger, ) NotificationService { return ¬ificationService{ repository: repository, logger: logger, } } // Create creates a single notification func (s *notificationService) Create(ctx context.Context, req *NotificationRequest) (*NotificationResponse, error) { s.logger.Info("Creating notification", map[string]interface{}{ "recipient": req.Recipient, "type": req.Type, "priority": req.Priority, }) // Create notification entity notification := &Notification{ Recipient: req.Recipient, Tender: req.Tender, Channels: req.Channels, Type: req.Type, Priority: req.Priority, Title: req.Title, Description: req.Description, Link: req.Link, Status: DeliveryStatusPending, Schedule: Schedule{ Time: req.Schedule.Time, }, } // Create notification in repository if err := s.repository.Create(ctx, notification); err != nil { s.logger.Error("Failed to create notification", map[string]interface{}{ "recipient": req.Recipient, "error": err.Error(), }) return nil, fmt.Errorf("failed to create notification") } s.logger.Info("Notification created", map[string]interface{}{ "notification_id": notification.ID, "recipient": req.Recipient, "channels": req.Channels, }) return notification.ToResponse(), nil } // Update updates a notification func (s *notificationService) Update(ctx context.Context, id string, req *NotificationRequest) (*NotificationResponse, error) { s.logger.Info("Updating notification", map[string]interface{}{ "notification_id": id, }) notification, err := s.repository.Get(ctx, id) if err != nil { s.logger.Error("Failed to get notification", map[string]interface{}{ "notification_id": id, "error": err.Error(), }) return nil, fmt.Errorf("failed to get notification") } if notification.Status == DeliveryStatusSent { return nil, fmt.Errorf("notification already sent") } // update notification fields notification.Recipient = req.Recipient notification.Tender = req.Tender notification.Channels = req.Channels notification.Type = req.Type notification.Priority = req.Priority notification.Title = req.Title notification.Description = req.Description notification.Link = req.Link notification.Schedule = Schedule{ Time: req.Schedule.Time, } notification.Status = DeliveryStatusPending // update notification in repository if err := s.repository.Update(ctx, notification); err != nil { s.logger.Error("Failed to update notification", map[string]interface{}{ "notification_id": id, "error": err.Error(), }) return nil, fmt.Errorf("failed to update notification") } s.logger.Info("Notification updated", map[string]interface{}{ "notification_id": id, "recipient": req.Recipient, "channels": req.Channels, }) return notification.ToResponse(), nil } // Get gets a notification func (s *notificationService) Get(ctx context.Context, id string) (*NotificationResponse, error) { s.logger.Info("Getting notification", map[string]interface{}{ "notification_id": id, }) notification, err := s.repository.Get(ctx, id) if err != nil { s.logger.Error("Failed to get notification", map[string]interface{}{ "notification_id": id, "error": err.Error(), }) return nil, fmt.Errorf("failed to get notification") } return notification.ToResponse(), nil } // Search searches for notifications func (s *notificationService) Search(ctx context.Context, req *SearchForm, pagination *response.Pagination) (*NotificationsResponse, error) { notifications, total, err := s.repository.Search(ctx, req, pagination) if err != nil { s.logger.Error("Failed to search notifications", map[string]interface{}{ "error": err.Error(), }) return nil, errors.New("failed to search notifications") } var notificationResponses []*NotificationResponse for _, notification := range notifications { notificationResponses = append(notificationResponses, notification.ToResponse()) } return &NotificationsResponse{ Notifications: notificationResponses, Meta: pagination.Response(total), }, nil } // Delete deletes a notification func (s *notificationService) Delete(ctx context.Context, id string) error { s.logger.Info("Deleting notification", map[string]interface{}{ "notification_id": id, }) notification, err := s.repository.Get(ctx, id) if err != nil { s.logger.Error("Failed to get notification", map[string]interface{}{ "notification_id": id, "error": err.Error(), }) return fmt.Errorf("failed to get notification") } if notification.Status == DeliveryStatusSent { return fmt.Errorf("notification already sent") } err = s.repository.Delete(ctx, id) if err != nil { s.logger.Error("Failed to delete notification", map[string]interface{}{ "notification_id": id, "error": err.Error(), }) return err } return nil }