<?php
declare(strict_types=1);

namespace App\Application\Security\Middleware;

use App\Application\Security\Events\{
    Web\CsrfViolationEvent,
    Network\SuspiciousNetworkActivityEvent,
    Input\InputValidationFailureEvent
};
use App\Framework\Core\Events\EventDispatcher;
use Psr\Http\Message\{ServerRequestInterface, ResponseInterface};
use Psr\Http\Server\{MiddlewareInterface, RequestHandlerInterface};

final class SecurityEventMiddleware implements MiddlewareInterface
{
    private array $requestCounts = [];
    private const RATE_LIMIT_THRESHOLD = 100;
    private const TIME_WINDOW = 300; // 5 Minuten

    public function __construct(
        private EventDispatcher $eventDispatcher
    ) {}

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $this->checkRateLimit($request);
        $this->validateCsrfToken($request);

        $response = $handler->handle($request);

        $this->analyzeResponse($request, $response);

        return $response;
    }

    private function checkRateLimit(ServerRequestInterface $request): void
    {
        $clientIp = $this->getClientIp($request);
        $currentTime = time();

        // Rate Limiting Check
        if (!isset($this->requestCounts[$clientIp])) {
            $this->requestCounts[$clientIp] = [];
        }

        // Alte Einträge entfernen
        $this->requestCounts[$clientIp] = array_filter(
            $this->requestCounts[$clientIp],
            fn($timestamp) => $currentTime - $timestamp < self::TIME_WINDOW
        );

        $this->requestCounts[$clientIp][] = $currentTime;

        if (count($this->requestCounts[$clientIp]) > self::RATE_LIMIT_THRESHOLD) {
            $this->eventDispatcher->dispatch(new SuspiciousNetworkActivityEvent(
                sourceIp: $clientIp,
                activityType: 'rate_limit_exceeded',
                requestCount: count($this->requestCounts[$clientIp]),
                timeWindow: self::TIME_WINDOW . 's'
            ));
        }
    }

    private function validateCsrfToken(ServerRequestInterface $request): void
    {
        $method = $request->getMethod();
        if (!in_array($method, ['POST', 'PUT', 'DELETE', 'PATCH'])) {
            return;
        }

        $sessionToken = $_SESSION['csrf_token'] ?? null;
        $requestToken = $request->getParsedBody()['csrf_token'] ??
                       $request->getHeaderLine('X-CSRF-Token');

        if (!$sessionToken || !$requestToken || !hash_equals($sessionToken, $requestToken)) {
            $this->eventDispatcher->dispatch(new CsrfViolationEvent(
                requestPath: $request->getUri()->getPath(),
                method: $method,
                expectedToken: $sessionToken,
                providedToken: $requestToken
            ));
        }
    }

    private function analyzeResponse(ServerRequestInterface $request, ResponseInterface $response): void
    {
        // Suspicious response patterns
        if ($response->getStatusCode() === 403) {
            // Access denied - könnte bereits von Authorization Middleware gehandhabt werden
        }

        if ($response->getStatusCode() >= 500) {
            // Server errors - könnte auf Angriffe hindeuten
        }
    }

    private function getClientIp(ServerRequestInterface $request): string
    {
        $serverParams = $request->getServerParams();
        return $serverParams['HTTP_X_FORWARDED_FOR'] ??
               $serverParams['HTTP_X_REAL_IP'] ??
               $serverParams['REMOTE_ADDR'] ??
               'unknown';
    }
}
