<?php
declare(strict_types=1);

namespace App\Framework\Http\Session;

use App\Framework\DI\Container;
use App\Framework\Http\HttpMiddleware;
use App\Framework\Http\MiddlewareContext;
use App\Framework\Http\MiddlewarePriority;
use App\Framework\Http\MiddlewarePriorityAttribute;
use App\Framework\Http\RequestStateManager;
use App\Framework\Http\ResponseManipulator;

#[MiddlewarePriorityAttribute(MiddlewarePriority::SESSION)]
final readonly class SessionMiddleware implements HttpMiddleware
{
    public function __construct(
        private Container $container,
        private SessionManager $sessionManager
    ) {}

    public function __invoke(MiddlewareContext $context, callable $next, RequestStateManager $stateManager): MiddlewareContext
    {
        $session = $this->sessionManager->getOrCreateSession($context->request);

        $userAgent = $context->request->headers->get('User-Agent')[0] ?? '';
        #$ipAddress = $context->request->headers->get('REMOTE_ADDR') ?? '';
        $ipAddress = $context->request->server->getClientIp();

        if($session->has(SessionKey::SECURITY->value)) {
            $isValid = $session->security->validate($userAgent, $ipAddress);

            if (!$isValid) {
                // Session ist kompromittiert - neue erstellen
                $session = $this->sessionManager->createNewSession();
                $session->security->initialize($userAgent, $ipAddress);
            } else {
                // Letzte Aktivität aktualisieren
                $session->security->updateLastActivity();

                // Session-ID-Rotation bei Bedarf
                if ($session->security->shouldRegenerateId()) {
                    $session = $this->sessionManager->regenerateSession($session);
                }
            }
        } else {
            // Neue Session mit Sicherheitsdaten initialisieren
            $session->security->initialize($userAgent, $ipAddress);
        }

        #$this->container->bind(Session::class, $session);

        $this->container->forget(Session::class);
        $this->container->instance(Session::class, $session);


        $context = $next($context);


        // Flash-Daten für den nächsten Request vorbereiten
        $session->flash->age();

        // Session speichern
        $responseWithSession = $this->sessionManager->saveSession($session, $context->response);

        return $context->withResponse($responseWithSession);

    }
}
