package repository // import ( // "context" // "encoding/json" // "fmt" // dbgen "Yimaru-Backend/gen/db" // "Yimaru-Backend/internal/domain" // "Yimaru-Backend/internal/ports" // "github.com/jackc/pgx/v5/pgtype" // ) // func NewNotificationStore(s *Store) ports.NotificationStore { return s } // func (r *Store) CreateNotification(ctx context.Context, notification *domain.Notification) (*domain.Notification, error) { // var errorSeverity pgtype.Text // if notification.ErrorSeverity != "" { // errorSeverity.String = string(notification.ErrorSeverity) // errorSeverity.Valid = true // } // var deliveryChannel pgtype.Text // if notification.DeliveryChannel != "" { // deliveryChannel.String = string(notification.DeliveryChannel) // deliveryChannel.Valid = true // } // var priority pgtype.Int4 // if notification.Priority != 0 { // priority.Int32 = int32(notification.Priority) // priority.Valid = true // } // params := dbgen.CreateNotificationParams{ // ID: notification.ID, // RecipientID: notification.RecipientID, // Type: string(notification.Type), // Level: string(notification.Level), // ErrorSeverity: errorSeverity, // Reciever: string(notification.Reciever), // IsRead: notification.IsRead, // DeliveryStatus: string(notification.DeliveryStatus), // DeliveryChannel: deliveryChannel, // Payload: marshalPayload(notification.Payload), // Priority: priority, // Timestamp: pgtype.Timestamptz{Time: notification.Timestamp, Valid: true}, // Expires: pgtype.Timestamptz{Time: notification.Expires, Valid: true}, // Img: pgtype.Text{String: notification.Image, Valid: notification.Image != ""}, // Metadata: notification.Metadata, // } // dbNotification, err := r.queries.CreateNotification(ctx, params) // if err != nil { // return nil, err // } // return r.mapDBToDomain(&dbNotification), nil // } // func (r *Store) UpdateNotificationStatus(ctx context.Context, id, status string, isRead bool, metadata []byte) (*domain.Notification, error) { // params := dbgen.UpdateNotificationStatusParams{ // ID: id, // DeliveryStatus: status, // IsRead: isRead, // Metadata: metadata, // } // dbNotification, err := r.queries.UpdateNotificationStatus(ctx, params) // if err != nil { // return nil, err // } // return r.mapDBToDomain(&dbNotification), nil // } // func (r *Store) GetUserNotifications(ctx context.Context, recipientID int64, limit, offset int) ([]domain.Notification, int64, error) { // params := dbgen.GetUserNotificationsParams{ // RecipientID: recipientID, // Limit: int32(limit), // Offset: int32(offset), // } // dbNotifications, err := r.queries.GetUserNotifications(ctx, params) // if err != nil { // return nil, 0, err // } // total, err := r.queries.GetUserNotificationCount(ctx, recipientID) // if err != nil { // return nil, 0, err // } // var result []domain.Notification = make([]domain.Notification, 0, len(dbNotifications)) // for _, dbNotif := range dbNotifications { // domainNotif := r.mapDBToDomain(&dbNotif) // result = append(result, *domainNotif) // } // return result, total, nil // } // func (r *Store) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) { // dbNotifications, err := r.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{ // Limit: int32(limit), // Offset: int32(offset), // }) // if err != nil { // return nil, err // } // var result []domain.Notification = make([]domain.Notification, 0, len(dbNotifications)) // for _, dbNotif := range dbNotifications { // domainNotif := r.mapDBToDomain(&dbNotif) // result = append(result, *domainNotif) // } // return result, nil // } // func (r *Store) ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error) { // dbNotifications, err := r.queries.ListFailedNotifications(ctx, int32(limit)) // if err != nil { // return nil, err // } // var result []domain.Notification // for _, dbNotif := range dbNotifications { // domainNotif := r.mapDBToDomain(&dbNotif) // result = append(result, *domainNotif) // } // return result, nil // } // func (r *Store) ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) { // return r.queries.ListRecipientIDsByReceiver(ctx, string(receiver)) // } // func (s *Store) DeleteOldNotifications(ctx context.Context) error { // return s.queries.DeleteOldNotifications(ctx) // } // func (r *Store) mapDBToDomain(dbNotif *dbgen.Notification) *domain.Notification { // var errorSeverity domain.NotificationErrorSeverity // if dbNotif.ErrorSeverity.Valid { // errorSeverity = domain.NotificationErrorSeverity(dbNotif.ErrorSeverity.String) // } else { // errorSeverity = "" // } // var deliveryChannel domain.DeliveryChannel // if dbNotif.DeliveryChannel.Valid { // deliveryChannel = domain.DeliveryChannel(dbNotif.DeliveryChannel.String) // } else { // deliveryChannel = "" // } // var priority int // if dbNotif.Priority.Valid { // priority = int(dbNotif.Priority.Int32) // } // payload, err := unmarshalPayload(dbNotif.Payload) // if err != nil { // payload = domain.NotificationPayload{} // } // return &domain.Notification{ // ID: dbNotif.ID, // RecipientID: dbNotif.RecipientID, // Type: domain.NotificationType(dbNotif.Type), // Level: domain.NotificationLevel(dbNotif.Level), // ErrorSeverity: errorSeverity, // Reciever: domain.NotificationRecieverSide(dbNotif.Reciever), // IsRead: dbNotif.IsRead, // DeliveryStatus: domain.NotificationDeliveryStatus(dbNotif.DeliveryStatus), // DeliveryChannel: deliveryChannel, // Payload: payload, // Priority: priority, // Timestamp: dbNotif.Timestamp.Time, // Expires: dbNotif.Expires.Time, // Image: dbNotif.Img.String, // Metadata: dbNotif.Metadata, // } // } // func marshalPayload(payload domain.NotificationPayload) []byte { // data, _ := json.Marshal(payload) // return data // } // func unmarshalPayload(data []byte) (domain.NotificationPayload, error) { // var payload domain.NotificationPayload // if err := json.Unmarshal(data, &payload); err != nil { // return domain.NotificationPayload{}, err // } // return payload, nil // } // func (r *Store) CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error) { // return r.queries.CountUnreadNotifications(ctx, recipient_id) // } // func (r *Store) GetNotificationCounts(ctx context.Context, filter domain.ReportFilter) (total, read, unread int64, err error) { // rows, err := r.queries.GetNotificationCounts(ctx) // if err != nil { // return 0, 0, 0, fmt.Errorf("failed to get notification counts: %w", err) // } // // var total, read, unread int64 // for _, row := range rows { // total += row.Total // read += row.Read // unread += row.Unread // } // return total, read, unread, nil // } // func (s *Store) GetMostActiveNotificationRecipients(ctx context.Context, filter domain.ReportFilter, limit int) ([]domain.ActiveNotificationRecipient, error) { // query := `SELECT // n.recipient_id, // u.first_name || ' ' || u.last_name as recipient_name, // COUNT(*) as notification_count, // MAX(n.timestamp) as last_notification_time // FROM notifications n // JOIN users u ON n.recipient_id = u.id // WHERE n.timestamp BETWEEN $1 AND $2 // GROUP BY n.recipient_id, u.first_name, u.last_name // ORDER BY notification_count DESC // LIMIT $3` // var recipients []domain.ActiveNotificationRecipient // rows, err := s.conn.Query(ctx, query, filter.StartTime.Value, filter.EndTime.Value, limit) // if err != nil { // return nil, fmt.Errorf("failed to get active notification recipients: %w", err) // } // defer rows.Close() // for rows.Next() { // var r domain.ActiveNotificationRecipient // if err := rows.Scan(&r.RecipientID, &r.RecipientName, &r.NotificationCount, &r.LastNotificationTime); err != nil { // return nil, err // } // recipients = append(recipients, r) // } // return recipients, nil // } // // GetNotificationDeliveryStats // func (s *Store) GetNotificationDeliveryStats(ctx context.Context, filter domain.ReportFilter) (domain.NotificationDeliveryStats, error) { // query := `SELECT // COUNT(*) as total_sent, // COUNT(CASE WHEN delivery_status = 'failed' THEN 1 END) as failed_deliveries, // (COUNT(CASE WHEN delivery_status = 'sent' THEN 1 END) * 100.0 / NULLIF(COUNT(*), 0)) as success_rate, // MODE() WITHIN GROUP (ORDER BY delivery_channel) as most_used_channel // FROM notifications // WHERE timestamp BETWEEN $1 AND $2` // var stats domain.NotificationDeliveryStats // row := s.conn.QueryRow(ctx, query, filter.StartTime.Value, filter.EndTime.Value) // err := row.Scan(&stats.TotalSent, &stats.FailedDeliveries, &stats.SuccessRate, &stats.MostUsedChannel) // if err != nil { // return domain.NotificationDeliveryStats{}, fmt.Errorf("failed to get notification delivery stats: %w", err) // } // return stats, nil // } // // GetNotificationCountsByType // func (s *Store) GetNotificationCountsByType(ctx context.Context, filter domain.ReportFilter) (map[string]domain.NotificationTypeCount, error) { // query := `SELECT // type, // COUNT(*) as total, // COUNT(CASE WHEN is_read = true THEN 1 END) as read, // COUNT(CASE WHEN is_read = false THEN 1 END) as unread // FROM notifications // WHERE timestamp BETWEEN $1 AND $2 // GROUP BY type` // counts := make(map[string]domain.NotificationTypeCount) // rows, err := s.conn.Query(ctx, query, filter.StartTime.Value, filter.EndTime.Value) // if err != nil { // return nil, fmt.Errorf("failed to get notification counts by type: %w", err) // } // defer rows.Close() // for rows.Next() { // var nt domain.NotificationTypeCount // var typ string // if err := rows.Scan(&typ, &nt.Total, &nt.Read, &nt.Unread); err != nil { // return nil, err // } // counts[typ] = nt // } // return counts, nil // } // // func (s *Store) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) { // // dbNotifications, err := s.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{ // // Limit: int32(limit), // // Offset: int32(offset), // // }) // // if err != nil { // // return nil, err // // } // // result := make([]domain.Notification, 0, len(dbNotifications)) // // for _, dbNotif := range dbNotifications { // // // You may want to move this mapping logic to a shared function if not already present // // var errorSeverity *domain.NotificationErrorSeverity // // if dbNotif.ErrorSeverity.Valid { // // s := domain.NotificationErrorSeverity(dbNotif.ErrorSeverity.String) // // errorSeverity = &s // // } // // var deliveryChannel domain.DeliveryChannel // // if dbNotif.DeliveryChannel.Valid { // // deliveryChannel = domain.DeliveryChannel(dbNotif.DeliveryChannel.String) // // } else { // // deliveryChannel = "" // // } // // var priority int // // if dbNotif.Priority.Valid { // // priority = int(dbNotif.Priority.Int32) // // } // // payload, err := unmarshalPayload(dbNotif.Payload) // // if err != nil { // // payload = domain.NotificationPayload{} // // } // // result = append(result, domain.Notification{ // // ID: dbNotif.ID, // // RecipientID: dbNotif.RecipientID, // // Type: domain.NotificationType(dbNotif.Type), // // Level: domain.NotificationLevel(dbNotif.Level), // // ErrorSeverity: errorSeverity, // // Reciever: domain.NotificationRecieverSide(dbNotif.Reciever), // // IsRead: dbNotif.IsRead, // // DeliveryStatus: domain.NotificationDeliveryStatus(dbNotif.DeliveryStatus), // // DeliveryChannel: deliveryChannel, // // Payload: payload, // // Priority: priority, // // Timestamp: dbNotif.Timestamp.Time, // // Metadata: dbNotif.Metadata, // // }) // // } // // return result, nil // // }