import config from '@/shared/config';
import AuthRefreshTokensDBApi from '@/db/api/auth_refresh_tokens';

/**
 * Refresh-token retention maintenance (Phase 5 / Workstream 14). Expired and
 * rotated/revoked refresh-token rows accumulate forever otherwise. A row past
 * its `expiresAt` can no longer be presented (the cookie is expired) and is no
 * longer needed for reuse-detection, so it is deleted once it is older than the
 * configured retention grace window.
 */

/**
 * The cutoff `expiresAt` before which rows are deleted: `now - retentionMs`.
 * Pure and exported for testing. A non-positive `retentionMs` is treated as 0
 * (delete everything already expired).
 */
export function computeRefreshTokenCutoff(now: Date, retentionMs: number): Date {
  const safeRetentionMs = Number.isFinite(retentionMs) && retentionMs > 0 ? retentionMs : 0;
  return new Date(now.getTime() - safeRetentionMs);
}

export interface RefreshTokenCleanupResult {
  readonly cutoff: Date;
  readonly deleted: number;
}

/**
 * Deletes refresh-token rows that expired before `now - retentionMs`. Defaults
 * pull from config/clock so the CLI command is a one-liner; both are injectable
 * for tests. Logs an observable summary line.
 */
export async function cleanupExpiredRefreshTokens(options: {
  now?: Date;
  retentionMs?: number;
} = {}): Promise<RefreshTokenCleanupResult> {
  const now = options.now ?? new Date();
  const retentionMs = options.retentionMs ?? config.auth.refreshTokenRetentionMs;
  const cutoff = computeRefreshTokenCutoff(now, retentionMs);

  const deleted = await AuthRefreshTokensDBApi.deleteExpiredBefore(cutoff);

  console.log(
    `[refresh-token-maintenance] deleted ${deleted} refresh-token row(s) expired before ${cutoff.toISOString()} (retention ${retentionMs}ms).`,
  );

  return { cutoff, deleted };
}
