import { backfillAccounts, backfillDone, backfillOnce } from "../backfill";
import { all, batch, stmt } from "../db";
import { accountDb } from "../scoped-db";
import type { ScopedValue } from "../scoped-db/types";
import { scratchAccountIds } from "./directory";
import { periodOf } from "./record";
const INDEX = "usage-leaderboard";
export type UsageRow = { account_id: string; meter: string; quantity: number };
type Sql = { exec<T extends Record<string, ScopedValue>>(sql: string, ...params: ScopedValue[]): { toArray(): T[] } };
/** An account's counters and gauge peaks for a period, as its own AccountState stores them. */
export const PERIOD_USAGE_SQL = `SELECT account_id, meter, quantity FROM usage_periods WHERE period = ?1 AND quantity > 0
UNION ALL SELECT account_id, meter, peak AS quantity FROM usage_gauges WHERE period = ?1 AND peak > 0`;
async function write(accountId: string, period: string, rows: UsageRow[], now: number): Promise<void> {
const ids = [...new Set([accountId, ...rows.map((row) => row.account_id)])];
await batch([
stmt(
`DELETE FROM usage_leaderboard WHERE period = ? AND account_id IN (${ids.map(() => "?").join(", ")})`,
period,
...ids,
),
...rows.map((row) =>
stmt(
`INSERT INTO usage_leaderboard (period, meter, account_id, quantity, updated_at) VALUES (?, ?, ?, ?, ?)
ON CONFLICT (period, meter, account_id) DO UPDATE SET quantity = excluded.quantity, updated_at = excluded.updated_at`,
period,
row.meter,
row.account_id,
row.quantity,
now,
),
),
]);
}
/**
* AccountState alarm, a few minutes after usage moves: replaces the account's rows for the current period, and