<?php

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Notification\EventListener;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Context\UserContext;
use CpCreation\VitiCore\User\Model\User;
use Random\RandomException;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Initialise le contexte utilisateur global au début de chaque requête.
 *
 * Ce listener collecte et enregistre plusieurs identifiants liés
 * à la session et à l’utilisateur courant dans la classe statique
 * {@see UserContext}.
 *
 * Données enregistrées :
 *  - `UserContext::$identifierWindowId` : identifiant unique de fenêtre
 *    (provenant de l’en-tête `X-Window-Id`, ou généré si absent).
 *  - `UserContext::$identifierSession` : identifiant de session Symfony.
 *  - `UserContext::$identifierUserId` : identifiant de l’utilisateur connecté.
 *
 * Ces informations permettent d’associer des événements, logs ou actions
 * à un contexte utilisateur précis, même avant l’authentification complète.
 *
 * ---
 *
 * ## Exemple d’utilisation
 * Les composants applicatifs (logs, statistiques, requêtes en arrière-plan)
 * peuvent accéder à ces identifiants à tout moment via :
 *
 * ```
 * $windowId = UserContext::$identifierWindowId;
 * $sessionId = UserContext::$identifierSession;
 * $userId = UserContext::$identifierUserId;
 * ```
 *
 * ---
 *
 * ## Notes
 * - L’écouteur s’exécute sur `kernel.request` après le firewall Symfony
 *   afin que l’utilisateur authentifié soit déjà rechargé depuis la session.
 * - Le `X-Window-Id` peut être utilisé côté front pour distinguer plusieurs
 *   onglets ou fenêtres d’un même utilisateur.
 */
#[AsEventListener(event: KernelEvents::REQUEST, priority: 5)]
readonly class UserContextListener
{
    public function __construct(private Security $security)
    {
    }

    /**
     * @throws RandomException
     */
    public function __invoke(RequestEvent $event): void
    {
        $windowId = $event->getRequest()->headers->get('X-Window-Id');
        UserContext::$identifierWindowId = $windowId;
        if (!$windowId) {
            UserContext::$identifierWindowId = bin2hex(random_bytes(16));
        }
        $event->getRequest()->headers->set('X-Window-Id', UserContext::$identifierWindowId);
        if ($event->getRequest()->hasSession()) {
            UserContext::$identifierSession = $event->getRequest()->getSession()->getId();
        }
        $user = $this->security->getUser();
        if ($user instanceof User) {
            UserContext::$identifierUserId = $user->getId();
        }
    }
}
