<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Middleware;

use App\Administration\Application\Service\Cache\PaginatedQueryCache;
use App\Administration\Domain\Event\CompteActive;
use App\Administration\Domain\Event\InvitationParentActivee;
use App\Administration\Domain\Event\InvitationParentEnvoyee;
use App\Administration\Domain\Event\InvitationRenvoyee;
use App\Administration\Domain\Event\UtilisateurInvite;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
use Symfony\Component\Messenger\Stamp\ReceivedStamp;

/**
 * Invalidates paginated query caches synchronously for events routed to async transport.
 *
 * Without this middleware, cache invalidation for async-routed events (UtilisateurInvite,
 * CompteActive, etc.) would only happen when the async worker processes the event,
 * causing stale data in the UI until then.
 *
 * This middleware runs before SendMessageMiddleware, ensuring the cache is invalidated
 * immediately during the originating HTTP request. The PaginatedQueryCacheInvalidator
 * handlers still exist as a safety net for worker-side processing.
 */
final readonly class PaginatedCacheInvalidationMiddleware implements MiddlewareInterface
{
    public function __construct(
        private PaginatedQueryCache $cache,
    ) {
    }

    public function handle(Envelope $envelope, StackInterface $stack): Envelope
    {
        if ($envelope->last(ReceivedStamp::class) === null) {
            $this->invalidateIfNeeded($envelope->getMessage());
        }

        return $stack->next()->handle($envelope, $stack);
    }

    private function invalidateIfNeeded(object $message): void
    {
        match (true) {
            $message instanceof UtilisateurInvite,
            $message instanceof CompteActive,
            $message instanceof InvitationRenvoyee => $this->cache->invalidate('users', (string) $message->tenantId),

            $message instanceof InvitationParentEnvoyee => $this->cache->invalidate('parent_invitations', (string) $message->tenantId),

            $message instanceof InvitationParentActivee => $this->invalidateParentActivee($message),

            default => null,
        };
    }

    private function invalidateParentActivee(InvitationParentActivee $event): void
    {
        $tenantId = (string) $event->tenantId;
        $this->cache->invalidate('parent_invitations', $tenantId);
        $this->cache->invalidate('users', $tenantId);
    }
}
