/**
 * @jest-environment node
 */

import {
  describe,
  it,
  expect,
  jest,
  beforeEach,
  afterEach,
} from "@jest/globals";

describe("Rate Limiter Memory Cleanup", () => {
  let memoryStore: Map<string, { count: number; reset: number }>;
  let cleanupExpiredEntries: () => void;
  const MAX_ENTRIES = 10000;

  beforeEach(() => {
    // Create a fresh memory store for each test
    memoryStore = new Map<string, { count: number; reset: number }>();

    // Define cleanup function (same logic as in rate-limiter.ts)
    cleanupExpiredEntries = () => {
      const now = Date.now();
      let removedCount = 0;

      // Remove expired entries
      for (const [key, record] of memoryStore.entries()) {
        if (now > record.reset) {
          memoryStore.delete(key);
          removedCount++;
        }
      }

      // Enforce max entries limit (remove oldest entries if needed)
      if (memoryStore.size > MAX_ENTRIES) {
        const sortedEntries = Array.from(memoryStore.entries()).sort(
          (a, b) => a[1].reset - b[1].reset,
        );

        const entriesToRemove = sortedEntries.slice(
          0,
          memoryStore.size - MAX_ENTRIES,
        );
        entriesToRemove.forEach(([key]) => {
          memoryStore.delete(key);
          removedCount++;
        });
      }

      return removedCount;
    };
  });

  afterEach(() => {
    jest.clearAllTimers();
  });

  it("should remove expired entries", () => {
    const now = Date.now();

    // Add expired entries
    memoryStore.set("expired1", { count: 5, reset: now - 1000 });
    memoryStore.set("expired2", { count: 3, reset: now - 2000 });

    // Add active entries
    memoryStore.set("active1", { count: 2, reset: now + 10000 });
    memoryStore.set("active2", { count: 1, reset: now + 20000 });

    expect(memoryStore.size).toBe(4);

    // Run cleanup
    cleanupExpiredEntries();

    // Should only keep active entries
    expect(memoryStore.size).toBe(2);
    expect(memoryStore.has("expired1")).toBe(false);
    expect(memoryStore.has("expired2")).toBe(false);
    expect(memoryStore.has("active1")).toBe(true);
    expect(memoryStore.has("active2")).toBe(true);
  });

  it("should not affect active rate limiting", () => {
    const now = Date.now();
    const resetTime = now + 60000;

    // Simulate active rate limiting
    memoryStore.set("user1", { count: 3, reset: resetTime });
    memoryStore.set("user2", { count: 5, reset: resetTime });

    // Run cleanup
    cleanupExpiredEntries();

    // Active entries should remain unchanged
    expect(memoryStore.size).toBe(2);
    expect(memoryStore.get("user1")).toEqual({ count: 3, reset: resetTime });
    expect(memoryStore.get("user2")).toEqual({ count: 5, reset: resetTime });
  });

  it("should enforce MAX_ENTRIES limit", () => {
    const now = Date.now();

    // Add more than MAX_ENTRIES
    for (let i = 0; i < MAX_ENTRIES + 100; i++) {
      memoryStore.set(`user${i}`, { count: 1, reset: now + i * 1000 });
    }

    expect(memoryStore.size).toBe(MAX_ENTRIES + 100);

    // Run cleanup
    cleanupExpiredEntries();

    // Should enforce limit
    expect(memoryStore.size).toBe(MAX_ENTRIES);
  });

  it("should remove oldest entries when enforcing limit", () => {
    const now = Date.now();

    // Add entries with different reset times
    for (let i = 0; i < MAX_ENTRIES + 50; i++) {
      memoryStore.set(`user${i}`, { count: 1, reset: now + i * 1000 });
    }

    // Run cleanup
    cleanupExpiredEntries();

    // Oldest entries should be removed
    expect(memoryStore.has("user0")).toBe(false);
    expect(memoryStore.has("user49")).toBe(false);

    // Newest entries should remain
    expect(memoryStore.has(`user${MAX_ENTRIES + 49}`)).toBe(true);
    expect(memoryStore.has(`user${MAX_ENTRIES + 40}`)).toBe(true);
  });

  it("should handle empty store", () => {
    expect(memoryStore.size).toBe(0);

    // Should not throw
    expect(() => cleanupExpiredEntries()).not.toThrow();

    expect(memoryStore.size).toBe(0);
  });

  it("should handle mixed expired and active entries with limit enforcement", () => {
    const now = Date.now();

    // Add expired entries
    for (let i = 0; i < 100; i++) {
      memoryStore.set(`expired${i}`, { count: 1, reset: now - 1000 });
    }

    // Add active entries exceeding limit
    for (let i = 0; i < MAX_ENTRIES + 50; i++) {
      memoryStore.set(`active${i}`, { count: 1, reset: now + i * 1000 });
    }

    const initialSize = memoryStore.size;
    expect(initialSize).toBe(MAX_ENTRIES + 150);

    // Run cleanup
    cleanupExpiredEntries();

    // Should remove all expired entries and enforce limit on active ones
    expect(memoryStore.size).toBe(MAX_ENTRIES);

    // No expired entries should remain
    expect(memoryStore.has("expired0")).toBe(false);
    expect(memoryStore.has("expired99")).toBe(false);
  });
});
