import { mock, test } from 'node:test';
import assert from 'node:assert/strict';
import AuthRefreshTokensDBApi from '@/db/api/auth_refresh_tokens';
import {
  cleanupExpiredRefreshTokens,
  computeRefreshTokenCutoff,
} from '@/services/refresh-token-maintenance';

const now = new Date('2026-06-11T12:00:00.000Z');

test('cutoff subtracts the retention window from now', () => {
  const oneDayMs = 24 * 60 * 60 * 1000;
  const cutoff = computeRefreshTokenCutoff(now, oneDayMs);
  assert.equal(cutoff.toISOString(), '2026-06-10T12:00:00.000Z');
});

test('a non-positive or invalid retention window deletes everything already expired (cutoff = now)', () => {
  assert.equal(computeRefreshTokenCutoff(now, 0).getTime(), now.getTime());
  assert.equal(computeRefreshTokenCutoff(now, -5).getTime(), now.getTime());
  assert.equal(computeRefreshTokenCutoff(now, Number.NaN).getTime(), now.getTime());
});

test('the cutoff is always at or before now', () => {
  const cutoff = computeRefreshTokenCutoff(now, 7 * 24 * 60 * 60 * 1000);
  assert.ok(cutoff.getTime() <= now.getTime());
});

test('cleanupExpiredRefreshTokens deletes before the computed cutoff and returns the count', async () => {
  const oneDayMs = 24 * 60 * 60 * 1000;
  const deleteMock = mock.method(
    AuthRefreshTokensDBApi,
    'deleteExpiredBefore',
    async () => 4,
  );

  try {
    const result = await cleanupExpiredRefreshTokens({ now, retentionMs: oneDayMs });

    assert.equal(result.deleted, 4);
    assert.equal(result.cutoff.toISOString(), '2026-06-10T12:00:00.000Z');
    assert.equal(deleteMock.mock.callCount(), 1);
    const [cutoffArg] = deleteMock.mock.calls[0].arguments;
    assert.equal((cutoffArg as Date).toISOString(), '2026-06-10T12:00:00.000Z');
  } finally {
    deleteMock.mock.restore();
  }
});
