"""
Rate limiting middleware for Flask API
Implements token bucket algorithm for request throttling
"""

from functools import wraps
from flask import request, jsonify
import time
from collections import defaultdict
import threading

class RateLimiter:
    """
    Thread-safe rate limiter using token bucket algorithm
    """
    def __init__(self):
        self.clients = defaultdict(lambda: {'tokens': 0, 'last_update': time.time(), 'initialized': False})
        self.lock = threading.Lock()
    
    def is_allowed(self, client_id, max_tokens=60, refill_rate=1.0):
        """
        Check if request is allowed for client
        
        Args:
            client_id: Unique identifier for client (IP address)
            max_tokens: Maximum tokens in bucket (requests per period)
            refill_rate: Tokens added per second
        
        Returns:
            tuple: (is_allowed: bool, retry_after: int)
        """
        with self.lock:
            now = time.time()
            client = self.clients[client_id]
            
            # Initialize new clients with full bucket
            if not client.get('initialized', False):
                client['tokens'] = max_tokens
                client['initialized'] = True
            
            # Calculate tokens to add based on time elapsed
            time_passed = now - client['last_update']
            client['tokens'] = min(
                max_tokens,
                client['tokens'] + time_passed * refill_rate
            )
            client['last_update'] = now
            
            # Check if request is allowed
            if client['tokens'] >= 1:
                client['tokens'] -= 1
                return True, 0
            else:
                # Calculate retry-after time
                retry_after = int((1 - client['tokens']) / refill_rate) + 1
                return False, retry_after
    
    def clear_client(self, client_id):
        """Remove client from rate limiter (for testing/reset)"""
        with self.lock:
            if client_id in self.clients:
                del self.clients[client_id]

# Global rate limiter instance
rate_limiter = RateLimiter()

def rate_limit(max_per_minute=60):
    """
    Decorator to apply rate limiting to Flask routes
    
    Usage:
        @app.route('/api/endpoint')
        @rate_limit(max_per_minute=30)
        def my_endpoint():
            ...
    """
    def decorator(f):
        @wraps(f)
        def wrapped(*args, **kwargs):
            # Get client identifier (IP address)
            client_id = request.remote_addr or 'unknown'
            
            # Convert per-minute limit to per-second refill rate
            refill_rate = max_per_minute / 60.0
            
            # Check if request is allowed
            is_allowed, retry_after = rate_limiter.is_allowed(
                client_id,
                max_tokens=max_per_minute,
                refill_rate=refill_rate
            )
            
            if not is_allowed:
                response = jsonify({
                    'error': 'rate_limit_exceeded',
                    'message': f'Too many requests. Please try again in {retry_after} seconds.',
                    'retry_after': retry_after
                })
                response.status_code = 429
                response.headers['Retry-After'] = str(retry_after)
                response.headers['X-RateLimit-Limit'] = str(max_per_minute)
                response.headers['X-RateLimit-Remaining'] = '0'
                return response
            
            return f(*args, **kwargs)
        return wrapped
    return decorator

def get_rate_limit_headers(client_id, max_per_minute=60):
    """
    Get rate limit headers for response
    
    Returns dict of headers to add to response
    """
    with rate_limiter.lock:
        client = rate_limiter.clients.get(client_id, {'tokens': max_per_minute})
        remaining = int(client.get('tokens', max_per_minute))
    
    return {
        'X-RateLimit-Limit': str(max_per_minute),
        'X-RateLimit-Remaining': str(max(0, remaining)),
        'X-RateLimit-Reset': str(int(time.time() + 60))
    }
