<?php
/**
 * Rate Limiting Middleware (File-based, Race-Condition Safe)
 */

declare(strict_types=1);

namespace App\Middleware;

final class RateLimitMiddleware
{
    /**
     * File-based rate limiter with file-lock to prevent race conditions.
     * For multi-server deployments, replace with Redis.
     */
    public static function check(int $maxRequests = 60, int $timeWindow = 60): void
    {
        $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
        $key = 'rl:' . md5($ip);

        // 1. Try Redis first
        $redis = \App\Core\Cache::getInstance();
        if ($redis) {
            try {
                $count = $redis->get($key);
                if ($count && (int)$count >= $maxRequests) {
                    header('Retry-After: ' . $timeWindow);
                    json_error('Too Many Requests. Please slow down.', 429);
                }

                if (!$count) {
                    $redis->setex($key, $timeWindow, 1);
                } else {
                    $redis->incr($key);
                }
                return; // Success with Redis
            } catch (\Exception $e) {
                // Fallback to file-based if Redis fails
            }
        }

        // 2. Fallback: File-based rate limiter (original logic)
        $cacheDir  = STORAGE_PATH . '/cache';
        $cacheFile = $cacheDir . '/rl_' . md5($ip) . '.json';
        if (!is_dir($cacheDir)) mkdir($cacheDir, 0755, true);

        $fp = fopen($cacheFile, 'c+');
        if ($fp === false) return;

        try {
            flock($fp, LOCK_EX);
            $now = time();
            $content = stream_get_contents($fp);
            $requests = [];
            if (!empty($content)) {
                $decoded = json_decode($content, true);
                if (is_array($decoded)) {
                    $requests = array_values(array_filter($decoded, fn($ts) => $ts > ($now - $timeWindow)));
                }
            }

            if (count($requests) >= $maxRequests) {
                flock($fp, LOCK_UN);
                fclose($fp);
                header('Retry-After: ' . $timeWindow);
                json_error('Too Many Requests. Please slow down.', 429);
            }

            $requests[] = $now;
            ftruncate($fp, 0);
            rewind($fp);
            fwrite($fp, json_encode($requests));
        } finally {
            flock($fp, LOCK_UN);
            fclose($fp);
        }
    }
}
