<?php

require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/Logger.php';

/**
 * Rate limiting implementation for API endpoints
 */
class RateLimiter {
    // Cache period constants
    const PERIOD_HOUR = 3600;  // seconds in an hour
    const PERIOD_DAY = 86400;  // seconds in a day
    
    /**
     * Check if a request is within rate limits
     * 
     * @param string $clientId Client identifier
     * @param string $endpoint API endpoint
     * @return array Result with status and limits information
     */
    public static function checkRateLimit($clientId, $endpoint) {
        try {
            $db = Database::getApiConnection();
            
            $hourLimit = RATE_LIMIT_HOUR;
            $dayLimit = RATE_LIMIT_DAY;
            $now = time();
            
            // Get current hour timestamp
            $hourTimestamp = $now - ($now % self::PERIOD_HOUR);
            // Get current day timestamp (midnight)
            $dayTimestamp = strtotime(date('Y-m-d'));
            
            // Check hourly usage
            $hourlyRequests = self::getRequestCount($db, $clientId, $hourTimestamp);
            
            // Check daily usage
            $dailyRequests = self::getRequestCount($db, $clientId, $dayTimestamp);
            
            // Prepare response
            $result = [
                'allowed' => true,
                'hourly' => [
                    'limit' => $hourLimit,
                    'remaining' => $hourLimit - $hourlyRequests,
                    'reset' => $hourTimestamp + self::PERIOD_HOUR
                ],
                'daily' => [
                    'limit' => $dayLimit,
                    'remaining' => $dayLimit - $dailyRequests,
                    'reset' => $dayTimestamp + self::PERIOD_DAY
                ]
            ];
            
            // If any limit is exceeded, mark as not allowed
            if ($hourlyRequests >= $hourLimit || $dailyRequests >= $dayLimit) {
                $result['allowed'] = false;
                
                // Determine which limit was exceeded for the message
                if ($hourlyRequests >= $hourLimit) {
                    $result['retry_after'] = $hourTimestamp + self::PERIOD_HOUR - $now;
                    $result['message'] = 'Hourly rate limit exceeded';
                } else {
                    $result['retry_after'] = $dayTimestamp + self::PERIOD_DAY - $now;
                    $result['message'] = 'Daily rate limit exceeded';
                }
                
                Logger::log(Logger::WARNING, "Rate limit exceeded for client: {$clientId}", [
                    'endpoint' => $endpoint,
                    'hourly' => $hourlyRequests,
                    'daily' => $dailyRequests
                ]);
            } else {
                // If within limits, increment the counters
                self::incrementCounter($db, $clientId, $hourTimestamp);
                self::incrementCounter($db, $clientId, $dayTimestamp);
            }
            
            return $result;
            
        } catch (Exception $e) {
            Logger::log(Logger::ERROR, "Rate limit check failed: " . $e->getMessage());
            
            // On error, default to allowing the request
            return [
                'allowed' => true,
                'hourly' => ['limit' => $hourLimit, 'remaining' => 1, 'reset' => time() + self::PERIOD_HOUR],
                'daily' => ['limit' => $dayLimit, 'remaining' => 1, 'reset' => time() + self::PERIOD_DAY]
            ];
        }
    }
    
    /**
     * Get the count of requests for a time period
     * 
     * @param mysqli $db Database connection
     * @param string $clientId Client ID
     * @param int $periodStart Period start timestamp
     * @return int Request count
     */
    private static function getRequestCount($db, $clientId, $periodStart) {
        // Use a table to track rate limits per client
        // First check if we have a record for this client and period
        $stmt = $db->prepare("
            SELECT request_count 
            FROM rate_limits 
            WHERE client_id = ? AND period_start = ?
        ");
        
        $stmt->bind_param("si", $clientId, $periodStart);
        $stmt->execute();
        $result = $stmt->get_result();
        
        if ($result->num_rows > 0) {
            $row = $result->fetch_assoc();
            $count = $row['request_count'];
        } else {
            $count = 0;
        }
        
        $stmt->close();
        return $count;
    }
    
    /**
     * Increment the counter for a client in a time period
     * 
     * @param mysqli $db Database connection
     * @param string $clientId Client ID
     * @param int $periodStart Period start timestamp
     * @return bool Success status
     */
    private static function incrementCounter($db, $clientId, $periodStart) {
        // Insert or update the counter
        $stmt = $db->prepare("
            INSERT INTO rate_limits (client_id, period_start, request_count) 
            VALUES (?, ?, 1) 
            ON DUPLICATE KEY UPDATE request_count = request_count + 1
        ");
        
        $stmt->bind_param("si", $clientId, $periodStart);
        $result = $stmt->execute();
        $stmt->close();
        
        return $result;
    }
} 