<?php

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Security;

use Flowaxy\Contracts\Security\RateLimiterInterface;
use Flowaxy\Support\Facades\Log;
use Throwable;

/**
 * Middleware для rate limiting на всех API endpoints
 *
 * @package Flowaxy\Infrastructure\Security
 */
final class RateLimitingMiddleware
{
    public function __construct(
        private readonly RateLimiterInterface $rateLimiter
    ) {
    }

    /**
     * Обработать запрос с rate limiting
     *
     * @param string $key Ключ для rate limiting (IP, user ID, etc.)
     * @param int $maxAttempts Максимальное количество попыток
     * @param int $decayMinutes Время блокировки в минутах
     * @param callable $handler Обработчик запроса
     * @return mixed
     * @throws \RuntimeException Если превышен лимит
     */
    public function handle(string $key, int $maxAttempts, int $decayMinutes, callable $handler): mixed
    {
        if ($this->rateLimiter->tooManyAttempts($key, $maxAttempts)) {
            $seconds = $this->rateLimiter->availableIn($key);
            try {
                Log::Warning('Rate limit exceeded', [
                    'key' => $key,
                    'seconds_remaining' => $seconds,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }

            http_response_code(429);
            header('Retry-After: ' . $seconds);
            throw new \RuntimeException('Too many requests. Please try again later.');
        }

        $this->rateLimiter->hit($key, $decayMinutes);

        return $handler();
    }
}
