package store import ( "context" "fmt" "time" ) // WasAcked returns true when the rule has no pending (un-acked) telegram // nudges. A resolved nudge (acted/snoozed/ignored) means the user has seen // and dealt with it — the alarm is considered acked. func (s *Store) WasAcked(ctx context.Context, key string) (bool, error) { var n int err := s.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM nudges WHERE rule = ? AND channel = 'telegram' AND outcome = 'pending'`, key).Scan(&n) if err != nil { return false, fmt.Errorf("was acked %s: %w", key, err) } return n == 0, nil } // MarkSent records that a sev4 telegram nudge was sent (or re-sent) for the // given rule at the given time. Used by the repeat-til-ack loop to clock the // repeat interval. func (s *Store) MarkSent(ctx context.Context, key string, ts time.Time) error { _, err := s.db.ExecContext(ctx, `INSERT INTO ack_sends (rule, sent_at) VALUES (?, ?)`, key, ts.UnixMilli()) if err != nil { return fmt.Errorf("mark sent %s: %w", key, err) } return nil } // LastSent returns the most recent send timestamp for the given rule's // telegram nudge. Returns zero time if nothing has been sent yet (the initial // send goes through RecordNudge, not MarkSent, so the first MarkSent comes on // the repeat path — LastSent may legitimately be zero until then). func (s *Store) LastSent(ctx context.Context, key string) (time.Time, error) { var millis int64 err := s.db.QueryRowContext(ctx, `SELECT MAX(sent_at) FROM ack_sends WHERE rule = ?`, key).Scan(&millis) if err != nil { return time.Time{}, fmt.Errorf("last sent %s: %w", key, err) } if millis == 0 { return time.Time{}, nil } return time.UnixMilli(millis).UTC(), nil } // MarkAcked marks ALL pending telegram nudges for the rule as "acted" — // stopping the repeat-til-ack loop. Called when the user acknowledges the // alarm (voice acknowledgment, Telegram callback, etc.). func (s *Store) MarkAcked(ctx context.Context, key string) error { now := time.Now() res, err := s.db.ExecContext(ctx, `UPDATE nudges SET outcome = 'acted', outcome_ts = ? WHERE rule = ? AND channel = 'telegram' AND outcome = 'pending'`, now.UnixMilli(), key) if err != nil { return fmt.Errorf("mark acked %s: %w", key, err) } n, _ := res.RowsAffected() if n == 0 { // no pending nudges — already acked or never sent; not an error. return nil } return nil }