<?php

/*
 * This file is part of the Serenity package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Serenity\CoreBundle\Shared\Mercure\Security;

use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Token\DataSet;
use Lcobucci\JWT\UnencryptedToken;
use Lcobucci\JWT\Validation\Constraint\SignedWith;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Mercure\Jwt\TokenProviderInterface;

readonly class JWTProvider implements TokenProviderInterface
{
    public function __construct(
        /** @var non-empty-string $mercurePublisherJwtKey */
        #[Autowire(env: 'MERCURE_PUBLISHER_JWT_KEY')]
        private string $mercurePublisherJwtKey)
    {
    }

    public function getJwt(): string
    {
        $publish = ['*'];

        return $this->config()->builder()->withClaim('mercure', ['publish' => $publish])
            ->getToken($this->config()->signer(), $this->config()->signingKey())->toString();
    }

    /**
     * @param non-empty-string $jwt
     */
    public function decodeJwt(string $jwt): ?DataSet
    {
        $token = $this->config()->parser()->parse($jwt);
        if (!$this->config()->validator()->validate($token, new SignedWith($this->config()->signer(), $this->config()->signingKey()))) {
            return null;
        }
        \assert($token instanceof UnencryptedToken);

        return $token->claims();
    }

    private function config(): Configuration
    {
        return Configuration::forSymmetricSigner(new Sha256(), InMemory::plainText($this->mercurePublisherJwtKey));
    }
}
