<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Infrastructure\Security;

use App\Administration\Domain\Model\User\UserId;
use App\Administration\Infrastructure\Security\JwtPayloadEnricher;
use App\Administration\Infrastructure\Security\SecurityUser;
use App\Shared\Infrastructure\Tenant\TenantId;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class JwtPayloadEnricherTest extends TestCase
{
    private JwtPayloadEnricher $enricher;

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

    #[Test]
    public function onJWTCreatedAddsCustomClaimsToPayload(): void
    {
        $userId = UserId::generate();
        $tenantId = TenantId::fromString('550e8400-e29b-41d4-a716-446655440002');

        $securityUser = new SecurityUser(
            userId: $userId,
            email: 'user@example.com',
            hashedPassword: 'hashed',
            tenantId: $tenantId,
            roles: ['ROLE_PARENT'],
        );

        $initialPayload = ['username' => 'user@example.com'];
        $event = new JWTCreatedEvent($initialPayload, $securityUser);

        $this->enricher->onJWTCreated($event);

        $payload = $event->getData();

        self::assertSame((string) $userId, $payload['user_id']);
        self::assertSame((string) $tenantId, $payload['tenant_id']);
        self::assertSame(['ROLE_PARENT'], $payload['roles']);
    }

    #[Test]
    public function onJWTCreatedPreservesExistingPayloadData(): void
    {
        $securityUser = new SecurityUser(
            userId: UserId::generate(),
            email: 'user@example.com',
            hashedPassword: 'hashed',
            tenantId: TenantId::fromString('550e8400-e29b-41d4-a716-446655440002'),
            roles: ['ROLE_ADMIN'],
        );

        $initialPayload = [
            'username' => 'user@example.com',
            'iat' => 1706436600,
            'exp' => 1706438400,
        ];
        $event = new JWTCreatedEvent($initialPayload, $securityUser);

        $this->enricher->onJWTCreated($event);

        $payload = $event->getData();

        self::assertSame('user@example.com', $payload['username']);
        self::assertSame(1706436600, $payload['iat']);
        self::assertSame(1706438400, $payload['exp']);
    }

    #[Test]
    public function onJWTCreatedDoesNothingForNonSecurityUser(): void
    {
        $nonSecurityUser = $this->createMock(\Symfony\Component\Security\Core\User\UserInterface::class);

        $initialPayload = ['username' => 'other@example.com'];
        $event = new JWTCreatedEvent($initialPayload, $nonSecurityUser);

        $this->enricher->onJWTCreated($event);

        $payload = $event->getData();

        // Payload should remain unchanged
        self::assertSame(['username' => 'other@example.com'], $payload);
    }
}
