<?php

namespace Gestoreasy\Core\Http;

use Gestoreasy\Core\Config\Config;
use Gestoreasy\Core\Tenant\TenantContext;

class RateLimitMiddleware
{
    private static array $requests = [];
    
    public static function check(string $key, int $maxRequests, int $windowSeconds): bool
    {
        $now = time();
        $windowStart = $now - $windowSeconds;
        
        // Limpar requisições antigas
        if (isset(self::$requests[$key])) {
            self::$requests[$key] = array_filter(
                self::$requests[$key],
                fn($timestamp) => $timestamp > $windowStart
            );
        }
        
        // Contar requisições na janela atual
        $currentRequests = count(self::$requests[$key] ?? []);
        
        if ($currentRequests >= $maxRequests) {
            return false;
        }
        
        // Registrar nova requisição
        self::$requests[$key][] = $now;
        
        return true;
    }
    
    public static function checkByIp(string $ip, int $maxRequests = null, int $windowSeconds = null): bool
    {
        $maxRequests = $maxRequests ?? (int) Config::get('RATE_LIMIT_PER_IP', 100);
        $windowSeconds = $windowSeconds ?? (int) Config::get('RATE_LIMIT_WINDOW_SECONDS', 60);
        
        return self::check("ip:{$ip}", $maxRequests, $windowSeconds);
    }
    
    public static function checkByTenant(string $tenantId, int $maxRequests = null, int $windowSeconds = null): bool
    {
        $maxRequests = $maxRequests ?? (int) Config::get('RATE_LIMIT_PER_TENANT', 500);
        $windowSeconds = $windowSeconds ?? (int) Config::get('RATE_LIMIT_WINDOW_SECONDS', 60);
        
        return self::check("tenant:{$tenantId}", $maxRequests, $windowSeconds);
    }
    
    public static function checkCnpjRefresh(string $cnpj, string $tenantId): array
    {
        $minSeconds = (int) Config::get('CNPJ_REFRESH_MIN_SECONDS', 60);
        $key = "cnpj_refresh:{$tenantId}:{$cnpj}";
        $now = time();
        
        if (isset(self::$requests[$key])) {
            $lastRequest = max(self::$requests[$key]);
            $timeSinceLastRequest = $now - $lastRequest;
            
            if ($timeSinceLastRequest < $minSeconds) {
                return [
                    'allowed' => false,
                    'retry_in_seconds' => $minSeconds - $timeSinceLastRequest
                ];
            }
        }
        
        // Registrar nova requisição
        self::$requests[$key] = [$now];
        
        return ['allowed' => true];
    }
    
    public static function enforceForSensitiveRoutes(Request $request): ?Response
    {
        $clientIp = $request->getClientIp();
        $tenantId = TenantContext::getTenantId();
        $path = $request->getPath();
        
        // Rate limiting específico para rotas sensíveis
        $sensitiveRoutes = [
            '/api/auth/login' => ['ip' => 10, 'tenant' => 50],
            '/api/auth/refresh' => ['ip' => 20, 'tenant' => 100],
            '/api/clientes/cnpj/' => ['ip' => 5, 'tenant' => 20],
            // Admin area hardening
            '/api/admin/auth/login' => ['ip' => 5, 'tenant' => 0],
            '/api/admin/auth/recovery' => ['ip' => 3, 'tenant' => 0]
        ];
        
        foreach ($sensitiveRoutes as $route => $limits) {
            if (strpos($path, $route) === 0) {
                // Verificar limite por IP
                if (!self::checkByIp($clientIp, $limits['ip'])) {
                    return Response::json([
                        'error' => [
                            'code' => 'rate_limit_exceeded_ip',
                            'message' => 'Muitas requisições deste IP. Tente novamente em alguns minutos.'
                        ]
                    ], 429);
                }
                // Verificar limite por tenant (se aplicável)
                if ($tenantId && isset($limits['tenant']) && $limits['tenant'] > 0 && !self::checkByTenant($tenantId, $limits['tenant'])) {
                    return Response::json([
                        'error' => [
                            'code' => 'rate_limit_exceeded_tenant',
                            'message' => 'Muitas requisições deste tenant. Tente novamente em alguns minutos.'
                        ]
                    ], 429);
                }
                
                break;
            }
        }
        
        return null; // Permitir requisição
    }
}