<?php
namespace Fifa\ConnectServiceBus\Sdk\Encryption\Encrypt;

use Fifa\ConnectServiceBus\Sdk\Api\ApiException;
use Fifa\ConnectServiceBus\Sdk\Authentication\CacheStorageInterface;
use Fifa\ConnectServiceBus\Sdk\Encryption\CertificateCache;
use Fifa\ConnectServiceBus\Sdk\Encryption\CertificateCacheInterface;
use Fifa\ConnectServiceBus\Sdk\Encryption\Model\PublicCertificate;
use Fifa\ConnectServiceBus\Sdk\Exception\DataNotFoundException;
use Fifa\ConnectServiceBus\Sdk\Exception\PublicCertificateNotFoundException;
use Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusCertificateClientInterface;

/**
 * Class PublicCertificateProvider
 * @package Fifa\ConnectServiceBus\Sdk\Encryption\Encrypt
 */
class PublicCertificateProvider implements PublicCertificateProviderInterface
{
    /**
     * @var FifaConnectServiceBusCertificateClientInterface
     */
    private $certificateClient;
    /**
     * @var CertificateCacheInterface
     */
    private $certificateCache;

    /**
     * Constructor
     *
     * @param FifaConnectServiceBusCertificateClientInterface $certificateClient
     * @param CacheStorageInterface $cacheStorage
     * @param int $expirationTimeSpanInSeconds - for how long cache should be valid until it's created, in seconds (default 86400 = 1 day)
     */
    public function __construct(FifaConnectServiceBusCertificateClientInterface $certificateClient, CacheStorageInterface $cacheStorage, int $expirationTimeSpanInSeconds = 86400)
    {
        $this->certificateClient = $certificateClient;
        $this->certificateCache = new CertificateCache($cacheStorage, $expirationTimeSpanInSeconds);
    }

    /**
     * Gets certificate
     *
     * @param string $queueIdentifier
     * @return PublicCertificate
     */
    public function get(string $queueIdentifier): PublicCertificate
    {
        $certificate = $this->certificateCache->getCertificateFromCache($queueIdentifier);
        if (is_null($certificate)) {
            $certificate = $this->reload(($queueIdentifier));
        }

        return $certificate;
    }

    /**
     * Reload the certificate
     *
     * @param string $queueIdentifier
     * @return PublicCertificate
     */
    private function reload(string $queueIdentifier): PublicCertificate
    {
        try {
            $key = $this->certificateClient->downloadCertificate($queueIdentifier);
        }
        catch (DataNotFoundException $e) {
            $message = 'Organisation ' . $queueIdentifier . ' have not uploaded their public key.';
            $apiException = new ApiException($message, $e->getCode(), $e->getResponseHeaders(), $e->getResponseBody());
            throw new PublicCertificateNotFoundException($apiException);
        }

        $certificate = new PublicCertificate($queueIdentifier, $key);
        $this->certificateCache->storeCache($certificate);

        return $certificate;
    }
}