<?php

class RateLimiter {
    private $pdo;
    private $maxRequests;
    private $timeWindow;
    
    public function __construct($pdo, $maxRequests = 100, $timeWindow = 60) {
        $this->pdo = $pdo;
        $this->maxRequests = $maxRequests;
        $this->timeWindow = $timeWindow;
        
        // Create rate limiting table if it doesn't exist
        $this->createRateLimitTable();
    }
    
    private function createRateLimitTable() {
        $sql = "CREATE TABLE IF NOT EXISTS rate_limits (
            id INT AUTO_INCREMENT PRIMARY KEY,
            ip_address VARCHAR(45) NOT NULL,
            endpoint VARCHAR(255) NOT NULL,
            request_count INT NOT NULL DEFAULT 1,
            first_request_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            last_request_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            UNIQUE KEY unique_ip_endpoint (ip_address, endpoint)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
        
        $this->pdo->exec($sql);
    }
    
    public function checkRateLimit($endpoint) {
        $ip = $this->getClientIp();
        
        // Clean up old entries
        $this->cleanupOldEntries();
        
        // Check if IP has made requests before
        $stmt = $this->pdo->prepare(
            "INSERT INTO rate_limits (ip_address, endpoint, request_count) 
             VALUES (?, ?, 1)
             ON DUPLICATE KEY UPDATE 
                request_count = IF(
                    last_request_at < DATE_SUB(NOW(), INTERVAL ? SECOND),
                    1,
                    request_count + 1
                ),
                first_request_at = IF(
                    last_request_at < DATE_SUB(NOW(), INTERVAL ? SECOND),
                    NOW(),
                    first_request_at
                ),
                last_request_at = NOW()"
        );
        
        $stmt->execute([$ip, $endpoint, $this->timeWindow, $this->timeWindow]);
        
        // Get current count for this IP and endpoint
        $stmt = $this->pdo->prepare(
            "SELECT request_count, first_request_at 
             FROM rate_limits 
             WHERE ip_address = ? AND endpoint = ?"
        );
        $stmt->execute([$ip, $endpoint]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if ($result) {
            $elapsed = time() - strtotime($result['first_request_at']);
            
            // If within time window and exceeded limit
            if ($elapsed < $this->timeWindow && $result['request_count'] > $this->maxRequests) {
                $retryAfter = $this->timeWindow - $elapsed;
                header("Retry-After: $retryAfter");
                header('X-RateLimit-Limit: ' . $this->maxRequests);
                header('X-RateLimit-Remaining: 0');
                header('X-RateLimit-Reset: ' . (time() + $retryAfter));
                
                http_response_code(429);
                echo json_encode([
                    'success' => false,
                    'message' => 'Too many requests. Please try again later.',
                    'retry_after' => $retryAfter
                ]);
                exit;
            }
            
            // Set rate limit headers
            $remaining = max(0, $this->maxRequests - $result['request_count']);
            header('X-RateLimit-Limit: ' . $this->maxRequests);
            header('X-RateLimit-Remaining: ' . $remaining);
            header('X-RateLimit-Reset: ' . (time() + ($this->timeWindow - $elapsed)));
        }
        
        return true;
    }
    
    private function cleanupOldEntries() {
        // Clean up entries older than 2 time windows
        $stmt = $this->pdo->prepare(
            "DELETE FROM rate_limits 
             WHERE last_request_at < DATE_SUB(NOW(), INTERVAL ? * 2 SECOND)"
        );
        $stmt->execute([$this->timeWindow]);
    }
    
    private function getClientIp() {
        $ip = $_SERVER['REMOTE_ADDR'];
        
        // Check for Cloudflare headers
        if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
            $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
        
        return $ip;
    }
}

// Usage example:
// $rateLimiter = new RateLimiter($pdo, 100, 60); // 100 requests per minute
// $rateLimiter->checkRateLimit('/api/endpoint');
