package store

import (
	"context"
	"database/sql"
	"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) {
	// MAX over an empty set is one row holding NULL, not zero rows, so this
	// scans into a NullInt64 — the same trap OldestPendingTelegram spells out.
	// A bare int64 turned the ordinary "nothing sent yet" case into a scan
	// error, and RepeatUnacked aborts its whole sweep on one, so the first
	// repeat could never go out for any rule.
	var millis sql.NullInt64
	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.Valid {
		return time.Time{}, nil
	}
	return time.UnixMilli(millis.Int64).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()
	// No pending nudges is not an error — already acked or never sent — so the
	// rows-affected count is not read at all: every outcome below this line is
	// the same nil.
	_, 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)
	}
	return nil
}
