import { Context, Next } from 'hono';
import Redis from 'ioredis';
import { config } from '../config';
import { logger } from '../utils/logger';
import { getWorkerConfig } from '@wcag-ada/config';

const workerConfig = getWorkerConfig();
const redis = new Redis({
  host: workerConfig.redis.host,
  port: workerConfig.redis.port,
  password: workerConfig.redis.password,
  db: workerConfig.redis.db,
});

interface RateLimitOptions {
  limit?: number;
  window?: number; // in milliseconds
  keyGenerator?: (c: Context) => string;
}

export const rateLimiter = (options: RateLimitOptions = {}) => {
  const {
    limit = config.API_RATE_LIMIT,
    window = config.API_RATE_WINDOW,
    keyGenerator = (c) => {
      const userId = c.get('userId');
      const ip = c.req.header('x-forwarded-for') || c.req.header('x-real-ip') || 'unknown';
      return userId ? `rate:user:${userId}` : `rate:ip:${ip}`;
    },
  } = options;
  
  return async (c: Context, next: Next) => {
    const key = keyGenerator(c);
    
    try {
      // Get current count
      const current = await redis.get(key);
      const count = current ? parseInt(current) : 0;
      
      // Check if limit exceeded
      if (count >= limit) {
        const ttl = await redis.pttl(key);
        
        c.header('X-RateLimit-Limit', limit.toString());
        c.header('X-RateLimit-Remaining', '0');
        c.header('X-RateLimit-Reset', new Date(Date.now() + ttl).toISOString());
        
        return c.json(
          {
            error: 'Rate limit exceeded',
            retryAfter: Math.ceil(ttl / 1000),
          },
          429
        );
      }
      
      // Increment counter
      const pipeline = redis.pipeline();
      pipeline.incr(key);
      pipeline.pexpire(key, window);
      await pipeline.exec();
      
      // Set headers
      c.header('X-RateLimit-Limit', limit.toString());
      c.header('X-RateLimit-Remaining', (limit - count - 1).toString());
      c.header('X-RateLimit-Reset', new Date(Date.now() + window).toISOString());
      
      return next();
    } catch (error) {
      logger.error('Rate limiter error:', error);
      // Continue on error - don't block requests due to rate limiter failure
      return next();
    }
  };
};