<?php

declare(strict_types=1);

namespace NoahVet\Reef\Factory;

use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken;
use NoahVet\Reef\Domain\Log\SimplePrincipal;
use NoahVet\Reef\Domain\Log\SimplePrincipalInterface;
use NoahVet\Reef\Jane\Model\UserinfoGetResponse200;
use NoahVet\Reef\Security\Authentication\Token\ReefOAuthToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;

class SimplePrincipalFactory implements SimplePrincipalFactoryInterface
{
    private ?TokenInterface $token;

    public function __construct(
        private readonly string $reefServiceToken,
        private readonly ClientFactoryInterface $clientFactory,
        TokenStorageInterface $tokenStorage,
    ) {
        $this->token = $tokenStorage->getToken();
    }

    public function create(string $type): SimplePrincipalInterface
    {
        return match (true) {
            'service_authentication' == $type => $this->createByServiceAuthentication(),
            'user_authentication' == $type => $this->createByUserAuthentication(),
            default => throw new \LogicException(
                "The $type should be equals to `service_authentication` or `user_authentication`.",
            ),
        };
    }

    protected function createByUserAuthentication(): SimplePrincipalInterface
    {
        return $this->createSimplePrincipal($this->reefServiceToken);
    }

    protected function createByServiceAuthentication(): SimplePrincipalInterface
    {
        if (!$this->token) {
            throw new \LogicException('The token should not be null at this step.');
        }

        if ($this->token instanceof ReefOAuthToken) {
            return $this->createSimplePrincipal($this->token->getBearerToken());
        }

        /* @psalm-ignore RedundantCondition */
        if (\is_a($this->token, OAuthToken::class)) {
            return $this->createSimplePrincipal($this->token->getAccessToken());
        }

        throw new \LogicException('The bearer token should not be null at this step.');
    }

    protected function createSimplePrincipal(string $bearer): SimplePrincipalInterface
    {
        /** @var UserinfoGetResponse200 $userinfo */
        $userinfo = $this->clientFactory->create($bearer)->userinfo();

        return new SimplePrincipal($userinfo->getIdentifier());
    }
}
