"""
Rate Limiting Module
Implement rate limiting and request optimization
"""

import asyncio
import time
from collections import deque
from typing import Dict, List, Optional

class RateLimiter:
    """Rate limiter for API requests"""
    
    def __init__(self, max_requests: int = 10, time_window: int = 60):
        self.max_requests = max_requests
        self.time_window = time_window
        self.requests = deque()
        self.lock = asyncio.Lock()
    
    async def acquire(self):
        """Acquire permission to make a request"""
        async with self.lock:
            now = time.time()
            
            # Remove old requests outside time window
            while self.requests and self.requests[0] <= now - self.time_window:
                self.requests.popleft()
            
            # Check if we can make a request
            if len(self.requests) < self.max_requests:
                self.requests.append(now)
                return
            
            # Calculate wait time
            oldest_request = self.requests[0]
            wait_time = self.time_window - (now - oldest_request)
            
            if wait_time > 0:
                await asyncio.sleep(wait_time)
                return self.acquire()
    
    async def wait_if_needed(self):
        """Wait if rate limit would be exceeded"""
        await self.acquire()

class RequestOptimizer:
    """Optimize requests for better performance"""
    
    def __init__(self):
        self.rate_limiters: Dict[str, RateLimiter] = {}
        self.default_limiter = RateLimiter(max_requests=5, time_window=60)
    
    def get_rate_limiter(self, domain: str, max_requests: int = 5, time_window: int = 60) -> RateLimiter:
        """Get or create rate limiter for domain"""
        key = f"{domain}:{max_requests}:{time_window}"
        
        if key not in self.rate_limiters:
            self.rate_limiters[key] = RateLimiter(max_requests, time_window)
        
        return self.rate_limiters[key]
    
    async def make_request(self, session, url, headers=None, max_retries=3):
        """Make optimized request with retry logic"""
        domain = url.split('//')[-1].split('/')[0]
        limiter = self.get_rate_limiter(domain)
        
        await limiter.wait_if_needed()
        
        for attempt in range(max_retries):
            try:
                async with session.get(url, headers=headers) as response:
                    return response
            except Exception as e:
                if attempt == max_retries - 1:
                    raise
                await asyncio.sleep(2 ** attempt)  # Exponential backoff
        
        return None
