<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Monitoring;

use App\Shared\Infrastructure\Audit\CorrelationIdHolder;
use App\Shared\Infrastructure\Tenant\TenantContext;
use Sentry\State\HubInterface;
use Sentry\State\Scope;
use Sentry\UserDataBag;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Enriches Sentry error reports with tenant, user, and correlation context.
 *
 * Runs after authentication so user context is available.
 * Critical: Filters PII before sending to GlitchTip (NFR-S3 compliance).
 */
final readonly class SentryContextEnricher
{
    public function __construct(
        private HubInterface $sentryHub,
        private TenantContext $tenantContext,
        private Security $security,
    ) {
    }

    /**
     * Enrich Sentry scope with request context.
     *
     * Uses CONTROLLER event (after firewall) so user context is available.
     * Correlation ID and tenant are already resolved by their respective middlewares.
     */
    #[AsEventListener(event: KernelEvents::CONTROLLER, priority: -100)]
    public function onKernelController(ControllerEvent $event): void
    {
        if (!$event->isMainRequest()) {
            return;
        }

        $this->sentryHub->configureScope(function (Scope $scope): void {
            // Add correlation ID for distributed tracing
            $correlationId = CorrelationIdHolder::get();
            if ($correlationId !== null) {
                $scope->setTag('correlation_id', $correlationId->value());
            }

            // Add tenant context (use subdomain for consistency with metrics)
            if ($this->tenantContext->hasTenant()) {
                $scope->setTag('tenant_id', $this->tenantContext->getCurrentTenantConfig()->subdomain);
            }

            // Add user context (ID only - no PII)
            $user = $this->security->getUser();
            if ($user !== null) {
                // Only send user ID, never email or username (RGPD compliance)
                $scope->setUser(new UserDataBag(
                    id: method_exists($user, 'getId') ? (string) $user->getId() : null,
                ));
            }
        });
    }
}
