package repositories import ( "time" "gorm.io/gorm" "github.com/treytartt/casera-api/internal/models" ) // ReminderRepository handles database operations for task reminder logs type ReminderRepository struct { db *gorm.DB } // NewReminderRepository creates a new reminder repository func NewReminderRepository(db *gorm.DB) *ReminderRepository { return &ReminderRepository{db: db} } // HasSentReminder checks if a reminder has already been sent for the given // task, user, due date, and reminder stage. func (r *ReminderRepository) HasSentReminder(taskID, userID uint, dueDate time.Time, stage models.ReminderStage) (bool, error) { // Normalize to date only dueDateOnly := time.Date(dueDate.Year(), dueDate.Month(), dueDate.Day(), 0, 0, 0, 0, time.UTC) var count int64 err := r.db.Model(&models.TaskReminderLog{}). Where("task_id = ? AND user_id = ? AND due_date = ? AND reminder_stage = ?", taskID, userID, dueDateOnly, stage). Count(&count).Error if err != nil { return false, err } return count > 0, nil } // LogReminder records that a reminder was sent. // Returns the created log entry or an error if the reminder was already sent // (unique constraint violation). func (r *ReminderRepository) LogReminder(taskID, userID uint, dueDate time.Time, stage models.ReminderStage, notificationID *uint) (*models.TaskReminderLog, error) { // Normalize to date only dueDateOnly := time.Date(dueDate.Year(), dueDate.Month(), dueDate.Day(), 0, 0, 0, 0, time.UTC) log := &models.TaskReminderLog{ TaskID: taskID, UserID: userID, DueDate: dueDateOnly, ReminderStage: stage, SentAt: time.Now().UTC(), NotificationID: notificationID, } err := r.db.Create(log).Error if err != nil { return nil, err } return log, nil } // GetSentRemindersForTask returns all reminder logs for a specific task and user. func (r *ReminderRepository) GetSentRemindersForTask(taskID, userID uint) ([]models.TaskReminderLog, error) { var logs []models.TaskReminderLog err := r.db.Where("task_id = ? AND user_id = ?", taskID, userID). Order("sent_at DESC"). Find(&logs).Error return logs, err } // GetSentRemindersForDueDate returns all reminder logs for a specific task, // user, and due date. func (r *ReminderRepository) GetSentRemindersForDueDate(taskID, userID uint, dueDate time.Time) ([]models.TaskReminderLog, error) { dueDateOnly := time.Date(dueDate.Year(), dueDate.Month(), dueDate.Day(), 0, 0, 0, 0, time.UTC) var logs []models.TaskReminderLog err := r.db.Where("task_id = ? AND user_id = ? AND due_date = ?", taskID, userID, dueDateOnly). Order("sent_at DESC"). Find(&logs).Error return logs, err } // CleanupOldLogs removes reminder logs older than the specified number of days. // This helps keep the table from growing indefinitely. func (r *ReminderRepository) CleanupOldLogs(daysOld int) (int64, error) { cutoff := time.Now().UTC().AddDate(0, 0, -daysOld) result := r.db.Where("sent_at < ?", cutoff). Delete(&models.TaskReminderLog{}) return result.RowsAffected, result.Error } // GetRecentReminderStats returns statistics about recent reminders sent. // Useful for admin/monitoring purposes. func (r *ReminderRepository) GetRecentReminderStats(sinceHours int) (map[string]int64, error) { since := time.Now().UTC().Add(-time.Duration(sinceHours) * time.Hour) stats := make(map[string]int64) // Count by stage rows, err := r.db.Model(&models.TaskReminderLog{}). Select("reminder_stage, COUNT(*) as count"). Where("sent_at >= ?", since). Group("reminder_stage"). Rows() if err != nil { return nil, err } defer rows.Close() for rows.Next() { var stage string var count int64 if err := rows.Scan(&stage, &count); err != nil { return nil, err } stats[stage] = count } return stats, nil }