<?php

declare(strict_types=1);

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

use App\Shared\Infrastructure\Monitoring\PiiScrubberLogProcessor;
use DateTimeImmutable;
use Monolog\Level;
use Monolog\LogRecord;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

/**
 * @see Story 1.8 - T5.4: Filter PII from logs (scrubber processor)
 */
#[CoversClass(PiiScrubberLogProcessor::class)]
final class PiiScrubberLogProcessorTest extends TestCase
{
    private PiiScrubberLogProcessor $processor;

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

    #[Test]
    public function itRedactsEmailInContext(): void
    {
        $record = $this->createLogRecord(
            context: ['email' => 'user@example.com'],
        );

        $result = ($this->processor)($record);

        self::assertSame('[REDACTED]', $result->context['email']);
    }

    #[Test]
    public function itRedactsPasswordInContext(): void
    {
        $record = $this->createLogRecord(
            context: ['password' => 'secret123'],
        );

        $result = ($this->processor)($record);

        self::assertSame('[REDACTED]', $result->context['password']);
    }

    #[Test]
    public function itRedactsNestedPii(): void
    {
        $record = $this->createLogRecord(
            context: [
                'user' => [
                    'id' => 'uuid-123',
                    'email' => 'user@example.com',
                    'name' => 'John Doe',
                ],
            ],
        );

        $result = ($this->processor)($record);

        self::assertSame('uuid-123', $result->context['user']['id']);
        self::assertSame('[REDACTED]', $result->context['user']['email']);
        self::assertSame('[REDACTED]', $result->context['user']['name']);
    }

    #[Test]
    public function itRedactsJwtTokensByValue(): void
    {
        $jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U';

        $record = $this->createLogRecord(
            context: ['auth_header' => $jwt],
        );

        $result = ($this->processor)($record);

        self::assertSame('[REDACTED]', $result->context['auth_header']);
    }

    #[Test]
    public function itRedactsEmailValues(): void
    {
        $record = $this->createLogRecord(
            context: ['some_field' => 'contact@school.fr'],
        );

        $result = ($this->processor)($record);

        self::assertSame('[REDACTED]', $result->context['some_field']);
    }

    #[Test]
    public function itPreservesSafeValues(): void
    {
        $record = $this->createLogRecord(
            context: [
                'correlation_id' => '01234567-89ab-cdef-0123-456789abcdef',
                'tenant_id' => 'tenant-uuid',
                'event_type' => 'UserCreated',
                'count' => 42,
            ],
        );

        $result = ($this->processor)($record);

        self::assertSame('01234567-89ab-cdef-0123-456789abcdef', $result->context['correlation_id']);
        self::assertSame('tenant-uuid', $result->context['tenant_id']);
        self::assertSame('UserCreated', $result->context['event_type']);
        self::assertSame(42, $result->context['count']);
    }

    #[Test]
    public function itRedactsPiiInExtra(): void
    {
        $record = $this->createLogRecord(
            extra: ['user_email' => 'admin@classeo.fr'],
        );

        $result = ($this->processor)($record);

        self::assertSame('[REDACTED]', $result->extra['user_email']);
    }

    #[Test]
    #[DataProvider('piiKeyProvider')]
    public function itRedactsVariousPiiKeys(string $key): void
    {
        $record = $this->createLogRecord(
            context: [$key => 'sensitive_value'],
        );

        $result = ($this->processor)($record);

        self::assertSame('[REDACTED]', $result->context[$key]);
    }

    /**
     * @return iterable<string, array{string}>
     */
    public static function piiKeyProvider(): iterable
    {
        yield 'email' => ['email'];
        yield 'password' => ['password'];
        yield 'token' => ['token'];
        yield 'secret' => ['secret'];
        yield 'authorization' => ['authorization'];
        yield 'cookie' => ['cookie'];
        yield 'phone' => ['phone'];
        yield 'address' => ['address'];
        yield 'nom' => ['nom'];
        yield 'prenom' => ['prenom'];
        yield 'name' => ['name'];
        yield 'firstname' => ['firstname'];
        yield 'lastname' => ['lastname'];
        yield 'ip' => ['ip'];
        yield 'user_agent' => ['user_agent'];
        yield 'user_email' => ['user_email'];
        yield 'auth_token' => ['auth_token'];
    }

    /**
     * @param array<string, mixed> $context
     * @param array<string, mixed> $extra
     */
    private function createLogRecord(
        string $message = 'Test message',
        array $context = [],
        array $extra = [],
    ): LogRecord {
        return new LogRecord(
            datetime: new DateTimeImmutable(),
            channel: 'test',
            level: Level::Info,
            message: $message,
            context: $context,
            extra: $extra,
        );
    }
}
