<?php

declare(strict_types=1);

namespace App\Tests\Unit\Shared\Infrastructure\Monitoring;

use App\Shared\Infrastructure\Monitoring\SentryBeforeSendCallback;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Sentry\Event;

/**
 * Tests for PII scrubbing in Sentry events.
 *
 * Critical for RGPD compliance: ensures no personal data is sent to error tracking.
 *
 * @see Story 1.8 - T1.4: Filter PII before send (scrubber)
 */
#[CoversClass(SentryBeforeSendCallback::class)]
final class SentryBeforeSendCallbackTest extends TestCase
{
    private SentryBeforeSendCallback $callback;

    protected function setUp(): void
    {
        $this->callback = new SentryBeforeSendCallback();
    }

    #[Test]
    public function itNeverDropsEvents(): void
    {
        $event = Event::createEvent();

        $result = ($this->callback)($event, null);

        self::assertNotNull($result);
        self::assertSame($event, $result);
    }

    #[Test]
    public function itFiltersEmailFromExtra(): void
    {
        $event = Event::createEvent();
        $event->setExtra(['user_email' => 'john@example.com', 'action' => 'login']);

        $result = ($this->callback)($event, null);

        $extra = $result->getExtra();
        self::assertSame('[FILTERED]', $extra['user_email']);
        self::assertSame('login', $extra['action']);
    }

    #[Test]
    public function itFiltersPasswordFromExtra(): void
    {
        $event = Event::createEvent();
        $event->setExtra(['password' => 'secret123', 'user_id' => 'john']);

        $result = ($this->callback)($event, null);

        $extra = $result->getExtra();
        self::assertSame('[FILTERED]', $extra['password']);
        self::assertSame('john', $extra['user_id']);
    }

    #[Test]
    public function itFiltersTokenFromExtra(): void
    {
        $event = Event::createEvent();
        $event->setExtra(['auth_token' => 'abc123xyz', 'status' => 'active']);

        $result = ($this->callback)($event, null);

        $extra = $result->getExtra();
        self::assertSame('[FILTERED]', $extra['auth_token']);
        self::assertSame('active', $extra['status']);
    }

    #[Test]
    public function itFiltersJwtTokensByValue(): void
    {
        $jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U';
        $event = Event::createEvent();
        $event->setExtra(['data' => $jwt]);

        $result = ($this->callback)($event, null);

        $extra = $result->getExtra();
        self::assertSame('[FILTERED]', $extra['data']);
    }

    #[Test]
    public function itFiltersEmailValues(): void
    {
        $event = Event::createEvent();
        $event->setExtra(['contact' => 'user@example.com']);

        $result = ($this->callback)($event, null);

        $extra = $result->getExtra();
        self::assertSame('[FILTERED]', $extra['contact']);
    }

    #[Test]
    public function itFiltersNestedPii(): void
    {
        $event = Event::createEvent();
        $event->setExtra([
            'user' => [
                'email' => 'nested@example.com',
                'id' => 123,
            ],
        ]);

        $result = ($this->callback)($event, null);

        $extra = $result->getExtra();
        self::assertSame('[FILTERED]', $extra['user']['email']);
        self::assertSame(123, $extra['user']['id']);
    }

    #[Test]
    public function itFiltersPiiFromTags(): void
    {
        $event = Event::createEvent();
        $event->setTags(['user_email' => 'tagged@example.com', 'environment' => 'prod']);

        $result = ($this->callback)($event, null);

        $tags = $result->getTags();
        self::assertSame('[FILTERED]', $tags['user_email']);
        self::assertSame('prod', $tags['environment']);
    }

    #[Test]
    #[DataProvider('piiKeysProvider')]
    public function itFiltersVariousPiiKeys(string $key): void
    {
        $event = Event::createEvent();
        $event->setExtra([$key => 'sensitive_value']);

        $result = ($this->callback)($event, null);

        $extra = $result->getExtra();
        self::assertSame('[FILTERED]', $extra[$key], "Key '$key' should be filtered");
    }

    /**
     * @return iterable<string, array{string}>
     */
    public static function piiKeysProvider(): iterable
    {
        yield 'email' => ['email'];
        yield 'password' => ['password'];
        yield 'token' => ['token'];
        yield 'secret' => ['secret'];
        yield 'key' => ['api_key'];
        yield 'authorization' => ['authorization'];
        yield 'cookie' => ['cookie'];
        yield 'session' => ['session_id'];
        yield 'phone' => ['phone'];
        yield 'address' => ['address'];
        yield 'ip' => ['client_ip'];
        yield 'nom' => ['nom'];
        yield 'prenom' => ['prenom'];
        yield 'name' => ['name'];
        yield 'firstname' => ['firstname'];
        yield 'lastname' => ['lastname'];
    }

    #[Test]
    public function itPreservesSafeValues(): void
    {
        $event = Event::createEvent();
        $event->setExtra([
            'error_code' => 'E001',
            'count' => 42,
            'enabled' => true,
            'data' => ['a', 'b', 'c'],
        ]);

        $result = ($this->callback)($event, null);

        $extra = $result->getExtra();
        self::assertSame('E001', $extra['error_code']);
        self::assertSame(42, $extra['count']);
        self::assertTrue($extra['enabled']);
        self::assertSame(['a', 'b', 'c'], $extra['data']);
    }
}
