/**
 * Test script for Rate Limiter functionality
 * Run with: npx tsx dev/test-rate-limiter.ts
 */

import { RateLimiter } from '../lib/services/rate-limiter';

// Mock API call function
async function mockApiCall(id: number, delay: number = 10): Promise<{ id: number; timestamp: number }> {
  await new Promise(resolve => setTimeout(resolve, delay));
  return { id, timestamp: Date.now() };
}

async function testRateLimiter() {
  console.log('🔍 Testing Rate Limiter Functionality\n');

  try {
    // Test 1: Basic throttling with 5 requests/second
    console.log('Test 1: Basic throttling (5 requests/second)');
    const limiter1 = new RateLimiter(5);
    const startTime1 = Date.now();
    const results1: any[] = [];

    // Queue 10 requests (should take ~2 seconds with 5 req/sec limit)
    const promises1 = Array.from({ length: 10 }, (_, i) =>
      limiter1.throttle(() => mockApiCall(i + 1))
    );

    for (const promise of promises1) {
      const result = await promise;
      results1.push(result);
    }

    const duration1 = Date.now() - startTime1;
    console.log(`✅ Completed 10 requests in ${duration1}ms`);
    console.log(`   Expected: ~2000ms (10 requests ÷ 5 req/sec)`);
    console.log(`   Within acceptable range: ${duration1 >= 1800 && duration1 <= 2500 ? 'Yes' : 'No'}\n`);

    // Test 2: High-volume throttling with 10 requests/second
    console.log('Test 2: High-volume throttling (10 requests/second)');
    const limiter2 = new RateLimiter(10);
    const startTime2 = Date.now();
    const results2: any[] = [];

    // Queue 25 requests (should take ~2.5 seconds with 10 req/sec limit)
    const promises2 = Array.from({ length: 25 }, (_, i) =>
      limiter2.throttle(() => mockApiCall(i + 1))
    );

    for (const promise of promises2) {
      const result = await promise;
      results2.push(result);
    }

    const duration2 = Date.now() - startTime2;
    console.log(`✅ Completed 25 requests in ${duration2}ms`);
    console.log(`   Expected: ~2500ms (25 requests ÷ 10 req/sec)`);
    console.log(`   Within acceptable range: ${duration2 >= 2300 && duration2 <= 3000 ? 'Yes' : 'No'}\n`);

    // Test 3: Verify rate limit enforcement
    console.log('Test 3: Verify rate limit enforcement (10 requests/second)');
    const limiter3 = new RateLimiter(10);
    const timestamps: number[] = [];

    // Execute 15 requests and track timestamps
    const promises3 = Array.from({ length: 15 }, (_, i) =>
      limiter3.throttle(async () => {
        const now = Date.now();
        timestamps.push(now);
        return mockApiCall(i + 1, 1);
      })
    );

    await Promise.all(promises3);

    // Check that no more than 10 requests happened in any 1-second window
    let maxRequestsInWindow = 0;
    for (let i = 0; i < timestamps.length; i++) {
      const windowStart = timestamps[i];
      const windowEnd = windowStart + 1000;
      const requestsInWindow = timestamps.filter(t => t >= windowStart && t < windowEnd).length;
      maxRequestsInWindow = Math.max(maxRequestsInWindow, requestsInWindow);
    }

    console.log(`✅ Maximum requests in any 1-second window: ${maxRequestsInWindow}`);
    console.log(`   Rate limit respected: ${maxRequestsInWindow <= 10 ? 'Yes' : 'No'}\n`);

    // Test 4: Queue length tracking
    console.log('Test 4: Queue length tracking');
    const limiter4 = new RateLimiter(5);
    
    // Queue multiple requests without awaiting
    const promises4 = Array.from({ length: 20 }, (_, i) =>
      limiter4.throttle(() => mockApiCall(i + 1, 50))
    );

    // Check queue length immediately after queuing
    await new Promise(resolve => setTimeout(resolve, 10));
    const queueLength = limiter4.getQueueLength();
    console.log(`✅ Queue length after queuing 20 requests: ${queueLength}`);
    console.log(`   Queue has pending requests: ${queueLength > 0 ? 'Yes' : 'No'}`);

    // Wait for all to complete
    await Promise.all(promises4);
    const finalQueueLength = limiter4.getQueueLength();
    console.log(`✅ Queue length after completion: ${finalQueueLength}`);
    console.log(`   Queue is empty: ${finalQueueLength === 0 ? 'Yes' : 'No'}\n`);

    // Test 5: Current request count tracking
    console.log('Test 5: Current request count tracking');
    const limiter5 = new RateLimiter(10);
    const requestCounts: number[] = [];

    // Execute requests and track current count
    const promises5 = Array.from({ length: 15 }, (_, i) =>
      limiter5.throttle(async () => {
        const count = limiter5.getCurrentRequestCount();
        requestCounts.push(count);
        return mockApiCall(i + 1, 1);
      })
    );

    await Promise.all(promises5);

    const maxCount = Math.max(...requestCounts);
    console.log(`✅ Maximum concurrent request count: ${maxCount}`);
    console.log(`   Never exceeded limit: ${maxCount <= 10 ? 'Yes' : 'No'}\n`);

    // Test 6: Reset functionality
    console.log('Test 6: Reset functionality');
    const limiter6 = new RateLimiter(5);
    
    // Queue some requests
    const promises6 = Array.from({ length: 10 }, (_, i) =>
      limiter6.throttle(() => mockApiCall(i + 1, 100))
    );

    // Wait a bit then reset
    await new Promise(resolve => setTimeout(resolve, 50));
    const queueBeforeReset = limiter6.getQueueLength();
    limiter6.reset();
    const queueAfterReset = limiter6.getQueueLength();

    console.log(`✅ Queue length before reset: ${queueBeforeReset}`);
    console.log(`✅ Queue length after reset: ${queueAfterReset}`);
    console.log(`   Reset cleared queue: ${queueAfterReset === 0 ? 'Yes' : 'No'}\n`);

    // Test 7: Error handling
    console.log('Test 7: Error handling');
    const limiter7 = new RateLimiter(10);
    let errorCaught = false;

    try {
      await limiter7.throttle(async () => {
        throw new Error('Mock API error');
      });
    } catch (error) {
      errorCaught = true;
    }

    console.log(`✅ Error properly propagated: ${errorCaught ? 'Yes' : 'No'}`);
    
    // Verify limiter still works after error
    const resultAfterError = await limiter7.throttle(() => mockApiCall(1));
    console.log(`✅ Limiter functional after error: ${resultAfterError.id === 1 ? 'Yes' : 'No'}\n`);

    // Test 8: Parallel execution within limit
    console.log('Test 8: Parallel execution within limit');
    const limiter8 = new RateLimiter(10);
    const startTime8 = Date.now();

    // Queue 10 requests that each take 100ms
    // With 10 req/sec limit, they should execute in parallel (not sequentially)
    const promises8 = Array.from({ length: 10 }, (_, i) =>
      limiter8.throttle(() => mockApiCall(i + 1, 100))
    );

    await Promise.all(promises8);
    const duration8 = Date.now() - startTime8;

    console.log(`✅ Completed 10 requests (100ms each) in ${duration8}ms`);
    console.log(`   Executed in parallel: ${duration8 < 500 ? 'Yes' : 'No'}`);
    console.log(`   (Sequential would take ~1000ms, parallel ~100ms)\n`);

    // Test 9: Stress test with many requests
    console.log('Test 9: Stress test (100 requests at 10 req/sec)');
    const limiter9 = new RateLimiter(10);
    const startTime9 = Date.now();

    const promises9 = Array.from({ length: 100 }, (_, i) =>
      limiter9.throttle(() => mockApiCall(i + 1, 1))
    );

    await Promise.all(promises9);
    const duration9 = Date.now() - startTime9;

    console.log(`✅ Completed 100 requests in ${duration9}ms`);
    console.log(`   Expected: ~10000ms (100 requests ÷ 10 req/sec)`);
    console.log(`   Within acceptable range: ${duration9 >= 9500 && duration9 <= 11000 ? 'Yes' : 'No'}\n`);

    // Test 10: Different rate limits
    console.log('Test 10: Custom rate limits');
    const limiter10a = new RateLimiter(2); // 2 req/sec
    const limiter10b = new RateLimiter(20); // 20 req/sec

    const startTime10a = Date.now();
    await Promise.all(
      Array.from({ length: 6 }, (_, i) =>
        limiter10a.throttle(() => mockApiCall(i + 1, 1))
      )
    );
    const duration10a = Date.now() - startTime10a;

    const startTime10b = Date.now();
    await Promise.all(
      Array.from({ length: 40 }, (_, i) =>
        limiter10b.throttle(() => mockApiCall(i + 1, 1))
      )
    );
    const duration10b = Date.now() - startTime10b;

    console.log(`✅ 6 requests at 2 req/sec: ${duration10a}ms (expected ~3000ms)`);
    console.log(`✅ 40 requests at 20 req/sec: ${duration10b}ms (expected ~2000ms)`);
    console.log(`   Both within acceptable ranges: ${
      (duration10a >= 2700 && duration10a <= 3500) &&
      (duration10b >= 1800 && duration10b <= 2500) ? 'Yes' : 'No'
    }\n`);

    console.log('🎉 All rate limiter tests completed successfully!');

  } catch (error) {
    console.error('❌ Test failed with error:', error);
    throw error;
  }
}

// Run the tests
testRateLimiter()
  .then(() => {
    console.log('\n✅ Test script completed successfully');
    process.exit(0);
  })
  .catch((error) => {
    console.error('\n❌ Test script failed:', error);
    process.exit(1);
  });
