import { describe, it, expect } from 'vitest';
import { createAdminRateLimiter, FORCE_UNLOCK_LIMIT } from './admin-rate-limit.js';

describe('AdminRateLimiter', () => {
  it('allows up to maxRequests within the window', () => {
    const limiter = createAdminRateLimiter({ windowMs: 60_000, maxRequests: 3 });
    const now = new Date('2026-05-12T00:00:00Z');
    expect(limiter.check('admin-1', now).allowed).toBe(true);
    expect(limiter.check('admin-1', now).allowed).toBe(true);
    expect(limiter.check('admin-1', now).allowed).toBe(true);
  });

  it('denies the (maxRequests+1)th request and returns retryAfterSeconds', () => {
    const limiter = createAdminRateLimiter({ windowMs: 60_000, maxRequests: 2 });
    const now = new Date('2026-05-12T00:00:00Z');
    limiter.check('admin-1', now);
    limiter.check('admin-1', now);
    const denied = limiter.check('admin-1', now);
    expect(denied.allowed).toBe(false);
    expect(denied.retryAfterSeconds).toBeGreaterThan(0);
    expect(denied.retryAfterSeconds).toBeLessThanOrEqual(60);
  });

  it('isolates buckets between users', () => {
    const limiter = createAdminRateLimiter({ windowMs: 60_000, maxRequests: 1 });
    const now = new Date('2026-05-12T00:00:00Z');
    expect(limiter.check('alice', now).allowed).toBe(true);
    expect(limiter.check('bob', now).allowed).toBe(true);
    expect(limiter.check('alice', now).allowed).toBe(false);
  });

  it('starts a new window after windowMs elapses', () => {
    const limiter = createAdminRateLimiter({ windowMs: 1000, maxRequests: 1 });
    const t0 = new Date('2026-05-12T00:00:00Z');
    const t1 = new Date('2026-05-12T00:00:01.500Z');
    expect(limiter.check('admin-1', t0).allowed).toBe(true);
    expect(limiter.check('admin-1', t0).allowed).toBe(false);
    expect(limiter.check('admin-1', t1).allowed).toBe(true);
  });

  it('reset(userId) clears one bucket', () => {
    const limiter = createAdminRateLimiter({ windowMs: 60_000, maxRequests: 1 });
    const now = new Date('2026-05-12T00:00:00Z');
    limiter.check('admin-1', now);
    expect(limiter.check('admin-1', now).allowed).toBe(false);
    limiter.reset('admin-1');
    expect(limiter.check('admin-1', now).allowed).toBe(true);
  });

  it('resetAll() clears all buckets', () => {
    const limiter = createAdminRateLimiter({ windowMs: 60_000, maxRequests: 1 });
    const now = new Date('2026-05-12T00:00:00Z');
    limiter.check('alice', now);
    limiter.check('bob', now);
    limiter.resetAll();
    expect(limiter.check('alice', now).allowed).toBe(true);
    expect(limiter.check('bob', now).allowed).toBe(true);
  });

  it('FORCE_UNLOCK_LIMIT default is 10/hr', () => {
    expect(FORCE_UNLOCK_LIMIT.maxRequests).toBe(10);
    expect(FORCE_UNLOCK_LIMIT.windowMs).toBe(60 * 60 * 1000);
  });
});
