<?php

declare(strict_types=1);

namespace Apexl\Tests\User\UnitTests;

use apexl\Config\ConfigurationMock;
use apexl\Config\Exceptions\MissingConfigException;
use apexl\Io\modules\user\entities\userEntity;
use apexl\Io\modules\user\interfaces\JwtKeyProviderInterface;
use apexl\Io\modules\user\services\JwtCreator;
use apexl\Io\TestInfrastructure\UnitTest;
use Apexl\Tests\User\Helpers\ChecksDecodedJwtToken;
use DI\DependencyException;
use DI\NotFoundException;
use Exception;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;
use PHPUnit\Framework\Attributes\Test;
use function apexl\Io\container;

final class JwtCreatorTest extends UnitTest
{
    use ChecksDecodedJwtToken;

    /**
     * @throws NotFoundException
     * @throws MissingConfigException
     * @throws DependencyException
     * @throws Exception
     */
    #[Test]
    public function forUser(): void
    {
        $sessionId = $this->faker->uuid;
        $serverName = $this->faker->domainName();
        $issuedAt = $this->faker->dateTime();
        $secretKey = $this->faker->lexify(implode('?', array_fill(0, 512, '?')));
        $algorithm = $this->faker->randomElement([
            'HS256',
            'HS384',
            'HS512',
        ]);
        $lifetime = $this->faker->numberBetween(10, 10_000);

        $user = userEntity::factory()->create(['id' => $this->faker->numberBetween()], false);

        $config = new ConfigurationMock([
            'auth.jwt.secret_key' => $secretKey,
            'auth.jwt.algorithm' => $algorithm,
            'auth.jwt.lifetime' => $lifetime,
        ]);

        $jwt = container()->make(JwtCreator::class, [
            'config' => $config,
        ])->forUser($user, $sessionId, $issuedAt, $serverName);

        $key = container()->make(JwtKeyProviderInterface::class, [
            'config' => $config,
        ])->key();

        try {
            $decoded = JWT::decode($jwt, $key);
        } catch (ExpiredException $e) {
            $decoded = $e->getPayload();
        }

        $this->checkDecodedJwtToken($decoded, $user->id, $sessionId, $lifetime, $issuedAt, $serverName);
    }
}