import { listAddressesNeedingExpiryWarning, markExpiryWarned } from "./db.ts";
import type { Dispatcher } from "./dispatch.ts";
import type { SqlExecutor } from "./storage.ts";
import type { AddressRow, OwnerRef } from "./types.ts";
// The reminder window, driven by the cleanup cron running once a day.
//
// Warning anything inside [24h, 48h] means every address gets seen by a run
// while it still has at least a day left. Using [0h, 24h] instead would let
// an address expiring 25 hours from now slip past today's run and only get
// warned at tomorrow's, an hour before it goes.
//
// The tradeoff: an address whose whole life is under ~48h may never be
// warned, because no run ever catches it inside the window. That's
// deliberate. "Expires in 24 hours" seconds after someone made a 24-hour
// address is noise, not a service.
const WARN_AFTER_SECONDS = 24 * 60 * 60;
const WARN_BEFORE_SECONDS = 48 * 60 * 60;
function groupByOwner(rows: AddressRow[]): Map<string, { owner: OwnerRef; rows: AddressRow[] }> {
const groups = new Map<string, { owner: OwnerRef; rows: AddressRow[] }>();
for (const row of rows) {
const key = `${row.owner_type}:${row.owner_id}`;
const existing = groups.get(key);
if (existing) {
existing.rows.push(row);
} else {
groups.set(key, { owner: { type: row.owner_type, id: row.owner_id }, rows: [row] });
}
}
return groups;
}
// <t:...:R> renders as "in 20 hours" in the reader's own locale and timezone,
// so the message never has to guess either.
function buildMessage(rows: AddressRow[]): string {
const lines = rows.map((row) => {
const label = row.note ? ` (${row.note.replaceAll("`", "")})` : "";
return `\`${row.address}\`${label}, expires <t:${row.expires_at}:R>`;
});