<?php
/**
 * Copyright since 2025 InPost S.A.
 *
 * For the full license information, please view the LICENSE file bundled with the module.
 *
 * @author InPost S.A.
 * @copyright since 2025 InPost S.A.
 * @license MIT
 */

declare(strict_types=1);

namespace InPost\International\OAuth2;

use InPost\International\OAuth2\Authentication\ClientCredentialsRepositoryInterface;
use InPost\International\OAuth2\Exception\RuntimeException;
use InPost\International\OAuth2\Token\AccessTokenInterface;
use InPost\International\OAuth2\Token\AccessTokenRepositoryInterface;
use Symfony\Component\HttpFoundation\Request;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class LazyAuthorizationProvider implements AuthorizationProviderInterface
{
    /**
     * @var AuthorizationProviderFactoryInterface
     */
    private $factory;

    /**
     * @var UriCollectionInterface
     */
    private $uriCollection;

    /**
     * @var ClientCredentialsRepositoryInterface
     */
    private $credentialsRepository;

    /**
     * @var AccessTokenRepositoryInterface|null
     */
    private $tokenRepository;

    /**
     * @var AuthorizationProviderInterface|null
     */
    private $authProvider;

    public function __construct(AuthorizationProviderFactoryInterface $factory, UriCollectionInterface $uriCollection, ClientCredentialsRepositoryInterface $credentialsRepository, AccessTokenRepositoryInterface $tokenRepository = null)
    {
        $this->factory = $factory;
        $this->uriCollection = $uriCollection;
        $this->credentialsRepository = $credentialsRepository;
        $this->tokenRepository = $tokenRepository;
    }

    public function authorize(array $scopes = []): void
    {
        $this->getAuthProvider()->authorize($scopes);
    }

    public function processAuthorizationResponse(Request $request): void
    {
        $this->getAuthProvider()->processAuthorizationResponse($request);
    }

    public function getAccessToken(bool $renew = false, array $scopes = []): AccessTokenInterface
    {
        return $this->getAuthProvider()->getAccessToken($renew, $scopes);
    }

    private function getAuthProvider(): AuthorizationProviderInterface
    {
        return $this->authProvider ?? ($this->authProvider = $this->createAuthProvider());
    }

    private function createAuthProvider(): AuthorizationProviderInterface
    {
        if (null === $credentials = $this->credentialsRepository->getClientCredentials()) {
            throw new RuntimeException('Client credentials are not available, cannot create an authorization provider.');
        }

        return $this->factory->create($this->uriCollection, $credentials, $this->tokenRepository);
    }
}
