<?php 
 
namespace IntegrationBundle\Service\Diia; 
 
use CoreBundle\Entity\Dealer; 
use CoreBundle\Model\Eusphpe\Eusphpe; 
use GuzzleHttp\Client as HttpClient; 
use IntegrationBundle\Exception\HandlerNotFoundException; 
use IntegrationBundle\Exception\ResponseErrorException; 
use Psr\Log\LoggerInterface; 
use Symfony\Component\Yaml\Yaml; 
 
class DiiaService 
{ 
    const CACHE_KEY = 'diia_token'; 
    const CACHE_LIFETIME_IN_SECONDS = 7100; 
    const DIIA_CERT = 'Diia_2022.cer'; 
 
/*    Токен авторизації "Віді страхування" PV-4222*/ 
    const DEF_AUTH_ACQUIRER_TOKEN = 'YWNxdWlyZXJfNDc5OnZpZGlfdGVzdF90b2tlbl85aWt3NDU='; 
 
    use MakesHttpRequests; 
 
    /** 
     * The acquirer token, which you can get from the employee of 'Diia' service. 
     * 
     * @var string 
     */ 
    protected $acquirerToken; 
 
    /** 
     * The session token, which you can get by authorizing with acquirer token. 
     * 
     * @var string|null 
     */ 
    protected $sessionToken; 
    /** 
     * @var SessionHandlerProvider 
     */ 
    private $handlerProvider; 
    /** 
     * @var Eusphpe 
     */ 
    private $eusphpe; 
    /** 
     * @var false|string 
     */ 
    private $vidiPrivateKey; 
    /** 
     * @var false|string 
     */ 
    private $vidiPrivateKeyPassword; 
 
    /** 
     * @var false|string 
     */ 
    private $diiaSert; 
 
    private ?string $diiaCredentialsPath; 
    private ?string $vidiPrivateKeyFilePath; 
    private ?string $vidiDefPrivateKey; 
    private ?string $diiaSertFilePath; 
 
    /** 
     * @param string $acquirerToken 
     * @param SessionHandlerProvider $handlerProvider 
     * @param LoggerInterface $logger 
     * @param Eusphpe $eusphpe 
     * @param string $diia_credentials_path 
     * @param string $vidiPrivateKeyFilePath 
     * @param string $vidiPrivateKeyPasswordFilePath 
     * @param string $diiaSertFilePath 
     * @param bool $testingMode 
     * @param HttpClient|null $guzzle 
     */ 
    public function __construct( 
        string $acquirerToken, 
        SessionHandlerProvider $handlerProvider, 
        LoggerInterface $logger, 
        Eusphpe $eusphpe, 
        string $diia_credentials_path, 
        string $vidiPrivateKeyFilePath, 
        string $vidiPrivateKeyPasswordFilePath, 
        string $diiaSertFilePath, 
        bool $testingMode = false, 
        HttpClient $guzzle = null 
    ) { 
        $this->acquirerDefToken = $acquirerToken; 
        $this->testingMode = $testingMode; 
        $this->handlerProvider = $handlerProvider; 
        $this->eusphpe = $eusphpe; 
        // If there were no guzzle instance provided, make the default one. 
        $this->setLogger($logger); 
 
        $this->diiaCredentialsPath = $diia_credentials_path; 
 
        if (file_exists($vidiPrivateKeyFilePath)) { 
            $this->vidiDefPrivateKey = file_get_contents($vidiPrivateKeyFilePath, FILE_USE_INCLUDE_PATH); 
        } 
        if (file_exists($vidiPrivateKeyPasswordFilePath)) { 
            $this->vidiDefPrivateKeyPassword = file_get_contents($vidiPrivateKeyPasswordFilePath, FILE_USE_INCLUDE_PATH); 
        } 
 
        if (file_exists($diiaSertFilePath)) { 
            $this->diiaDefSert = file_get_contents($diiaSertFilePath, FILE_USE_INCLUDE_PATH); 
        } 
    } 
 
    /** 
     * Transform the items of the collection to the given class. 
     * 
     * @param array $collection 
     * @param string $class 
     * @param array $extraData 
     * @return array 
     */ 
    public function transformCollection(array $collection, $class, $extraData = []): array 
    { 
        return array_map(fn($data) => new $class($data + $extraData, $this), $collection); 
    } 
 
    public function getCredentials(Dealer $dealer) 
    { 
        if (!file_exists($this->diiaCredentialsPath)) 
            return false; 
 
        $credFileContent = Yaml::parseFile($this->diiaCredentialsPath); 
        $credentials = []; 
 
        if ($credFileContent && isset($credFileContent[$dealer->getUniqueId()])){ 
            $credentials = $credFileContent[$dealer->getUniqueId()]; 
        } else { 
            return false; 
        } 
 
        if (file_exists($credentials['vidiPrivateKey'])) { 
            $credentials['vidiPrivateKey'] = file_get_contents($credentials['vidiPrivateKey'], FILE_USE_INCLUDE_PATH); 
        } 
        if (file_exists($credentials['vidiPrivateKeyPassword'])) { 
            $credentials['vidiPrivateKeyPassword'] = file_get_contents($credentials['vidiPrivateKeyPassword'], FILE_USE_INCLUDE_PATH); 
        } 
 
        return $credentials; 
    } 
 
    public function setCredentials(Dealer $dealer, $testMode = false) 
    { 
        $credentials = self::getCredentials($dealer); 
 
 
        if ($credentials){ 
                    $this->acquirerToken = $credentials['acquirerToken']; 
                    if ($testMode == true && $dealer->getId() == 14){ 
                        $this->testingMode = true; 
                        $this->acquirerToken = 'vidielite_test_token_byw932'; 
 
                    } 
                    $this->vidiPrivateKey = $credentials['vidiPrivateKey']; 
                    $this->vidiPrivateKeyPassword = $credentials['vidiPrivateKeyPassword']; 
                    $this->diiaSert = $this->diiaDefSert; 
                    $this->initGuzzle(null); 
                    $this->obtainSessionToken($this->acquirerToken, $credentials['auth_acquirer_token'], $dealer->getId()); 
        } else { 
            $this->acquirerToken = $this->acquirerDefToken; 
            $this->vidiPrivateKey = $this->vidiDefPrivateKey; 
            $this->vidiPrivateKeyPassword = $this->vidiDefPrivateKeyPassword; 
            $this->diiaSert = $this->diiaDefSert; 
            $this->initGuzzle(null); 
            $this->obtainSessionToken($this->acquirerToken); 
        } 
    } 
 
 
    /** 
     * Transform the items of the collection to the given class. 
     * 
     * @return void 
     * @throws HandlerNotFoundException 
     */ 
    public function invalidateSessionToken() 
    { 
        $this->handlerProvider->getSessionKeyHandler($this->getMode()); 
    } 
 
    public function decryptData($encodedData) 
    { 
        $res =$this->eusphpe->developBankIdData($this->vidiPrivateKey, $this->vidiPrivateKeyPassword, $encodedData, null); 
        $this->logger->info('decryptData', $res); 
        return $res; 
    } 
 
    /** 
     * Obtain session token, using provided acquirer token/ 
     * 
     * @param string $acquirerToken 
     * @throws HandlerNotFoundException 
     */ 
    protected function obtainSessionToken($acquirerToken, $auth_acquirer_token = self::DEF_AUTH_ACQUIRER_TOKEN, $dealerId) 
    { 
        $sessionKeyHandler = $this->handlerProvider->getSessionKeyHandler($this->getMode()); 
 
        try { 
            if (!$this->sessionToken = $sessionKeyHandler->handle($dealerId)) { 
                $this->applyDefaultOptions(['headers' => ['Authorization' => "Basic ". $auth_acquirer_token]]); 
                $this->sessionToken = $this->get("v1/auth/acquirer/{$acquirerToken}")["token"]; 
                //https://docs.google.com/document/d/1lM7Yd954GwtR1PRfo3afTR89YmC8k8_MrjyWhlZx4xw/edit#heading=h.4enep6lpiym1 
                //Set session token  який був отриманий не раніше, ніж 2 години тому 
                $sessionKeyHandler->setToken($this->sessionToken, $dealerId); 
            } 
        } catch (ResponseErrorException $e) { 
            $this->logger->critical($e->getMessage()); 
        } 
 
        //Для оновлення токена. Проблема в applyDefaultOptions (array_merge_recursive) 
        if (isset($this->guzzleCurrentOptions['headers']['Authorization'])){ 
            unset($this->guzzleCurrentOptions['headers']['Authorization']); 
        } 
 
        $this->applyDefaultOptions(['headers' => ['Authorization' => "Bearer {$this->sessionToken}"]]); 
    } 
 
    public function hashFiles($files) 
    { 
        $hashFiles = []; 
 
        foreach ($files as $file){ 
            $hashFiles[] = [ 
                'fileName' => $file['name'], 
                'fileHash' => $this->eusphpe->hashFile($file['path'], true) 
            ]; 
        } 
 
        return $hashFiles; 
    } 
 
    public function hashData($data) 
    { 
        $hashFiles = []; 
 
        foreach ($data as $file){ 
            $hashFiles[] = [ 
                'fileName' => $file['name'], 
                'fileHash' => $this->eusphpe->hashFile($file['data']) 
            ]; 
        } 
 
        return $hashFiles; 
    } 
 
    public function checkSignature($signature, $hashData) 
    { 
        $verify = $this->eusphpe->verify($signature, $hashData); 
 
        return $verify; 
    } 
}