<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magento\Dhl\Test\Unit\Model;

use Magento\Dhl\Model\Carrier;
use Magento\Dhl\Model\Validator\XmlValidator;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\ProductMetadataInterface;
use Magento\Framework\Filesystem\Directory\Read;
use Magento\Framework\Filesystem\Directory\ReadFactory;
use Magento\Framework\HTTP\ZendClient;
use Magento\Framework\HTTP\ZendClientFactory;
use Magento\Framework\Locale\ResolverInterface;
use Magento\Framework\Module\Dir\Reader;
use Magento\Framework\Stdlib\DateTime\DateTime;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Framework\Xml\Security;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Quote\Model\Quote\Address\RateResult\Error;
use Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory;
use Magento\Quote\Model\Quote\Address\RateResult\Method;
use Magento\Quote\Model\Quote\Address\RateResult\MethodFactory;
use Magento\Sales\Model\Order;
use Magento\Shipping\Helper\Carrier as CarrierHelper;
use Magento\Shipping\Model\Rate\Result;
use Magento\Shipping\Model\Rate\ResultFactory;
use Magento\Shipping\Model\Shipment\Request;
use Magento\Shipping\Model\Simplexml\Element;
use Magento\Shipping\Model\Simplexml\ElementFactory;
use Magento\Store\Model\StoreManager;
use Magento\Store\Model\Website;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
use Psr\Log\LoggerInterface;
use Magento\Store\Model\ScopeInterface;

/**
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class CarrierTest extends \PHPUnit\Framework\TestCase
{
    /**
     * @var ObjectManager
     */
    private $objectManager;

    /**
     * @var \Zend_Http_Response|MockObject
     */
    private $httpResponse;

    /**
     * @var Carrier
     */
    private $model;

    /**
     * @var Error|MockObject
     */
    private $error;

    /**
     * @var ErrorFactory|MockObject
     */
    private $errorFactory;

    /**
     * @var ScopeConfigInterface|MockObject
     */
    private $scope;

    /**
     * @var ZendClient|MockObject
     */
    private $httpClient;

    /**
     * @var XmlValidator|MockObject
     */
    private $xmlValidator;

    /**
     * @var Request|MockObject
     */
    private $request;

    /**
     * @var LoggerInterface|MockObject
     */
    private $logger;

    /**
     * @var DateTime|MockObject
     */
    private $coreDateMock;

    /**
     * @var ProductMetadataInterface
     */
    private $productMetadataMock;

    /**
     * @inheritdoc
     */
    protected function setUp()
    {
        $this->objectManager = new ObjectManager($this);

        $this->request = $this->getMockBuilder(Request::class)
            ->disableOriginalConstructor()
            ->setMethods(
                [
                    'getPackages',
                    'getOrigCountryId',
                    'setPackages',
                    'setPackageWeight',
                    'setPackageValue',
                    'setValueWithDiscount',
                    'setPackageCustomsValue',
                    'setFreeMethodWeight',
                    'getPackageWeight',
                    'getFreeMethodWeight',
                    'getOrderShipment',
                ]
            )
            ->getMock();

        $this->scope = $this->getMockForAbstractClass(ScopeConfigInterface::class);

        $this->error = $this->getMockBuilder(Error::class)
            ->setMethods(['setCarrier', 'setCarrierTitle', 'setErrorMessage'])
            ->getMock();
        $this->errorFactory = $this->getMockBuilder(ErrorFactory::class)
            ->disableOriginalConstructor()
            ->setMethods(['create'])
            ->getMock();
        $this->errorFactory->method('create')
            ->willReturn($this->error);

        $this->xmlValidator = $this->getMockBuilder(XmlValidator::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->logger = $this->getMockForAbstractClass(LoggerInterface::class);

        $this->coreDateMock = $this->getMockBuilder(DateTime::class)
            ->disableOriginalConstructor()
            ->getMock();
        $this->coreDateMock->method('date')
            ->willReturn('currentTime');

        $this->productMetadataMock = $this->getMockBuilder(ProductMetadataInterface::class)
            ->disableOriginalConstructor()
            ->getMock();
        $this->productMetadataMock->method('getName')
            ->willReturn('Software_Product_Name_30_Char_123456789');
        $this->productMetadataMock->method('getVersion')
            ->willReturn('10Char_Ver123456789');

        $this->model = $this->objectManager->getObject(
            Carrier::class,
            [
                'scopeConfig' => $this->scope,
                'rateErrorFactory' => $this->errorFactory,
                'logger' => $this->logger,
                'xmlSecurity' => new Security(),
                'xmlElFactory' => $this->getXmlFactory(),
                'rateFactory' => $this->getRateFactory(),
                'rateMethodFactory' => $this->getRateMethodFactory(),
                'carrierHelper' => $this->getCarrierHelper(),
                'configReader' => $this->getConfigReader(),
                'storeManager' => $this->getStoreManager(),
                'readFactory' => $this->getReadFactory(),
                'httpClientFactory' => $this->getHttpClientFactory(),
                'data' => ['id' => 'dhl', 'store' => '1'],
                'xmlValidator' => $this->xmlValidator,
                'coreDate' => $this->coreDateMock,
                'productMetadata' => $this->productMetadataMock
            ]
        );
    }

    /**
     * Emulates the config's `getValue` method.
     *
     * @param string $path
     * @return string|null
     */
    public function scopeConfigGetValue($path)
    {
        $pathMap = [
            'carriers/dhl/shipment_days' => 'Mon,Tue,Wed,Thu,Fri,Sat',
            'carriers/dhl/intl_shipment_days' => 'Mon,Tue,Wed,Thu,Fri,Sat',
            'carriers/dhl/allowed_methods' => 'IE',
            'carriers/dhl/international_searvice' => 'IE',
            'carriers/dhl/gateway_url' => 'https://xmlpi-ea.dhl.com/XMLShippingServlet',
            'carriers/dhl/id' => 'some ID',
            'carriers/dhl/password' => 'some password',
            'carriers/dhl/content_type' => 'N',
            'carriers/dhl/nondoc_methods' => '1,3,4,8,P,Q,E,F,H,J,M,V,Y',
            'carriers/dhl/showmethod' => 1,
            'carriers/dhl/title' => 'DHL Title',
            'carriers/dhl/specificerrmsg' => 'dhl error message',
            'carriers/dhl/unit_of_measure' => 'K',
            'carriers/dhl/size' => '1',
            'carriers/dhl/height' => '1.6',
            'carriers/dhl/width' => '1.6',
            'carriers/dhl/depth' => '1.6',
            'carriers/dhl/debug' => 1,
            'shipping/origin/country_id' => 'GB'
        ];
        return isset($pathMap[$path]) ? $pathMap[$path] : null;
    }

    public function testPrepareShippingLabelContent()
    {
        $xml = simplexml_load_file(
            __DIR__ . '/_files/response_shipping_label.xml'
        );
        $result = $this->_invokePrepareShippingLabelContent($xml);
        $this->assertEquals(1111, $result->getTrackingNumber());
        $this->assertEquals(base64_decode('OutputImageContent'), $result->getShippingLabelContent());
    }

    /**
     * @dataProvider prepareShippingLabelContentExceptionDataProvider
     * @expectedException \Magento\Framework\Exception\LocalizedException
     * @expectedExceptionMessage Unable to retrieve shipping label
     */
    public function testPrepareShippingLabelContentException(\SimpleXMLElement $xml)
    {
        $this->_invokePrepareShippingLabelContent($xml);
    }

    /**
     * @return array
     */
    public function prepareShippingLabelContentExceptionDataProvider()
    {
        $filesPath = __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR;
        $empty = $billingNumberOnly = $outputImageOnly = simplexml_load_file(
            $filesPath . 'response_shipping_label.xml'
        );
        unset(
            $empty->{'AirwayBillNumber'},
            $empty->{'LabelImage'},
            $billingNumberOnly->{'LabelImage'},
            $outputImageOnly->{'AirwayBillNumber'}
        );

        return [[$empty], [$billingNumberOnly], [$outputImageOnly]];
    }

    /**
     * @param \SimpleXMLElement $xml
     * @return \Magento\Framework\DataObject
     */
    protected function _invokePrepareShippingLabelContent(\SimpleXMLElement $xml)
    {
        $model = $this->objectManager->getObject(Carrier::class);
        $method = new \ReflectionMethod($model, '_prepareShippingLabelContent');
        $method->setAccessible(true);
        return $method->invoke($model, $xml);
    }

    /**
     * Tests that valid rates are returned when sending a quotes request.
     */
    public function testCollectRates()
    {
        $requestData = require __DIR__ . '/_files/dhl_quote_request_data.php';
        $responseXml = file_get_contents(__DIR__ . '/_files/dhl_quote_response.xml');

        $this->scope->method('getValue')
            ->willReturnCallback([$this, 'scopeConfigGetValue']);

        $this->scope->method('isSetFlag')
            ->willReturn(true);

        $this->httpResponse->method('getBody')
            ->willReturn($responseXml);

        $this->coreDateMock->method('date')
           ->willReturnCallback(function () {
               return date(\DATE_RFC3339);
           });

        $request = $this->objectManager->getObject(RateRequest::class, $requestData);

        $reflectionClass = new \ReflectionObject($this->httpClient);
        $rawPostData = $reflectionClass->getProperty('raw_post_data');
        $rawPostData->setAccessible(true);

        $this->logger->expects($this->once())
            ->method('debug')
            ->with($this->stringContains('<SiteID>****</SiteID><Password>****</Password>'));

        $expectedRates = require __DIR__ . '/_files/dhl_quote_response_rates.php';
        $actualRates = $this->model->collectRates($request)->getAllRates();

        self::assertEquals(count($expectedRates), count($actualRates));

        foreach ($actualRates as $i => $actualRate) {
            $actualRate = $actualRate->getData();
            unset($actualRate['method_title']);
            self::assertEquals($expectedRates[$i], $actualRate);
        }

        $requestXml = $rawPostData->getValue($this->httpClient);
        self::assertContains('<Weight>18.223</Weight>', $requestXml);
        self::assertContains('<Height>0.630</Height>', $requestXml);
        self::assertContains('<Width>0.630</Width>', $requestXml);
        self::assertContains('<Depth>0.630</Depth>', $requestXml);
    }

    /**
     * Tests that an error is returned when attempting to collect rates for an inactive shipping method.
     */
    public function testCollectRatesErrorMessage()
    {
        $this->scope->method('getValue')
            ->willReturnCallback([$this, 'scopeConfigGetValue']);

        $this->scope->expects($this->once())->method('isSetFlag')->willReturn(false);

        $this->error->expects($this->once())->method('setCarrier')->with('dhl');
        $this->error->expects($this->once())->method('setCarrierTitle');
        $this->error->expects($this->once())->method('setErrorMessage');

        $request = new RateRequest();
        $request->setPackageWeight(1);

        $this->assertSame($this->error, $this->model->collectRates($request));
    }

    /**
     * Test request to shipment sends valid xml values.
     *
     * @param string $origCountryId
     * @param string $expectedRegionCode
     * @dataProvider requestToShipmentDataProvider
     */
    public function testRequestToShipment(string $origCountryId, string $expectedRegionCode)
    {
        $expectedRequestXml = file_get_contents(__DIR__ . '/_files/shipment_request.xml');
        $scopeConfigValueMap = [
            ['carriers/dhl/account', 'store', null, '1234567890'],
            ['carriers/dhl/gateway_url', 'store', null, 'https://xmlpi-ea.dhl.com/XMLShippingServlet'],
            ['carriers/dhl/id', 'store', null, 'some ID'],
            ['carriers/dhl/password', 'store', null, 'some password'],
            ['carriers/dhl/content_type', 'store', null, 'N'],
            ['carriers/dhl/nondoc_methods', 'store', null, '1,3,4,8,P,Q,E,F,H,J,M,V,Y'],
            ['shipping/origin/country_id', 'store', null, $origCountryId],
        ];

        $this->scope->method('getValue')
            ->willReturnMap($scopeConfigValueMap);

        $this->httpResponse->method('getBody')
            ->willReturn(utf8_encode(file_get_contents(__DIR__ . '/_files/response_shipping_label.xml')));

        $packages = [
            'package' => [
                'params' => [
                    'width' => '3',
                    'length' => '3',
                    'height' => '3',
                    'dimension_units' => 'INCH',
                    'weight_units' => 'POUND',
                    'weight' => '0.454000000001',
                    'customs_value' => '10.00',
                    'container' => Carrier::DHL_CONTENT_TYPE_NON_DOC,
                ],
                'items' => [
                    'item1' => [
                        'name' => 'item_name',
                    ],
                ],
            ],
        ];

        $order = $this->getMockBuilder(Order::class)
            ->disableOriginalConstructor()
            ->getMock();
        $order->method('getSubtotal')
            ->willReturn('10.00');

        $shipment = $this->getMockBuilder(Order\Shipment::class)
            ->disableOriginalConstructor()
            ->getMock();
        $shipment->method('getOrder')
            ->willReturn($order);

        $this->request->method('getPackages')
            ->willReturn($packages);
        $this->request->method('getOrigCountryId')
            ->willReturn($origCountryId);
        $this->request->method('setPackages')
            ->willReturnSelf();
        $this->request->method('setPackageWeight')
            ->willReturnSelf();
        $this->request->method('setPackageValue')
            ->willReturnSelf();
        $this->request->method('setValueWithDiscount')
            ->willReturnSelf();
        $this->request->method('setPackageCustomsValue')
            ->willReturnSelf();
        $this->request->method('setFreeMethodWeight')
            ->willReturnSelf();
        $this->request->method('getPackageWeight')
            ->willReturn('0.454000000001');
        $this->request->method('getFreeMethodWeight')
            ->willReturn('0.454000000001');
        $this->request->method('getOrderShipment')
            ->willReturn($shipment);

        $this->logger->method('debug')
            ->with($this->stringContains('<SiteID>****</SiteID><Password>****</Password>'));

        $result = $this->model->requestToShipment($this->request);

        $reflectionClass = new \ReflectionObject($this->httpClient);
        $rawPostData = $reflectionClass->getProperty('raw_post_data');
        $rawPostData->setAccessible(true);

        $this->assertNotNull($result);
        $requestXml = $rawPostData->getValue($this->httpClient);
        $requestElement = new Element($requestXml);
        $this->assertEquals($expectedRegionCode, $requestElement->RegionCode->__toString());
        $requestElement->RegionCode = 'Checked';
        $messageReference = $requestElement->Request->ServiceHeader->MessageReference->__toString();
        $this->assertStringStartsWith('MAGE_SHIP_', $messageReference);
        $this->assertGreaterThanOrEqual(28, strlen($messageReference));
        $this->assertLessThanOrEqual(32, strlen($messageReference));
        $requestElement->Request->ServiceHeader->MessageReference = 'MAGE_SHIP_28TO32_Char_CHECKED';
        $expectedRequestElement = new Element($expectedRequestXml);
        $this->assertXmlStringEqualsXmlString($expectedRequestElement->asXML(), $requestElement->asXML());
    }

    /**
     * Data provider to testRequestToShipment
     *
     * @return array
     */
    public function requestToShipmentDataProvider()
    {
        return [
            [
                'GB', 'EU'
            ],
            [
                'SG', 'AP'
            ]
        ];
    }

    /**
     * @dataProvider dhlProductsDataProvider
     *
     * @param string $docType
     * @param array $products
     */
    public function testGetDhlProducts(string $docType, array $products)
    {
        $this->assertEquals($products, $this->model->getDhlProducts($docType));
    }

    /**
     * @return array
     */
    public function dhlProductsDataProvider() : array
    {
        return [
            'doc' => [
                'docType' => Carrier::DHL_CONTENT_TYPE_DOC,
                'products' => [
                    '2' => 'Easy shop',
                    '5' => 'Sprintline',
                    '6' => 'Secureline',
                    '7' => 'Express easy',
                    '9' => 'Europack',
                    'B' => 'Break bulk express',
                    'C' => 'Medical express',
                    'D' => 'Express worldwide',
                    'U' => 'Express worldwide',
                    'K' => 'Express 9:00',
                    'L' => 'Express 10:30',
                    'G' => 'Domestic economy select',
                    'W' => 'Economy select',
                    'I' => 'Domestic express 9:00',
                    'N' => 'Domestic express',
                    'O' => 'Others',
                    'R' => 'Globalmail business',
                    'S' => 'Same day',
                    'T' => 'Express 12:00',
                    'X' => 'Express envelope',
                ],
            ],
            'non-doc' => [
                'docType' => Carrier::DHL_CONTENT_TYPE_NON_DOC,
                'products' => [
                    '1' => 'Domestic express 12:00',
                    '3' => 'Easy shop',
                    '4' => 'Jetline',
                    '8' => 'Express easy',
                    'P' => 'Express worldwide',
                    'Q' => 'Medical express',
                    'E' => 'Express 9:00',
                    'F' => 'Freight worldwide',
                    'H' => 'Economy select',
                    'J' => 'Jumbo box',
                    'M' => 'Express 10:30',
                    'V' => 'Europack',
                    'Y' => 'Express 12:00',
                ],
            ],
        ];
    }

    /**
     * Tests that the built MessageReference string is of the appropriate format.
     *
     * @dataProvider buildMessageReferenceDataProvider
     * @param $servicePrefix
     * @throws \ReflectionException
     */
    public function testBuildMessageReference($servicePrefix)
    {
        $method = new \ReflectionMethod($this->model, 'buildMessageReference');
        $method->setAccessible(true);

        $messageReference = $method->invoke($this->model, $servicePrefix);
        $this->assertGreaterThanOrEqual(28, strlen($messageReference));
        $this->assertLessThanOrEqual(32, strlen($messageReference));
    }

    /**
     * @return array
     */
    public function buildMessageReferenceDataProvider()
    {
        return [
            'quote_prefix' => ['QUOT'],
            'shipval_prefix' => ['SHIP'],
            'tracking_prefix' => ['TRCK']
        ];
    }

    /**
     * Tests that an exception is thrown when an invalid service prefix is provided.
     *
     * @expectedException \Magento\Framework\Exception\LocalizedException
     * @expectedExceptionMessage Invalid service prefix
     */
    public function testBuildMessageReferenceInvalidPrefix()
    {
        $method = new \ReflectionMethod($this->model, 'buildMessageReference');
        $method->setAccessible(true);

        $method->invoke($this->model, 'INVALID');
    }

    /**
     * Tests that the built software name string is of the appropriate format.
     *
     * @dataProvider buildSoftwareNameDataProvider
     * @param $productName
     * @throws \ReflectionException
     */
    public function testBuildSoftwareName($productName)
    {
        $method = new \ReflectionMethod($this->model, 'buildSoftwareName');
        $method->setAccessible(true);

        $this->productMetadataMock->method('getName')->willReturn($productName);

        $softwareName = $method->invoke($this->model);
        $this->assertLessThanOrEqual(30, strlen($softwareName));
    }

    /**
     * @return array
     */
    public function buildSoftwareNameDataProvider()
    {
        return [
            'valid_length' => ['Magento'],
            'exceeds_length' => ['Product_Name_Longer_Than_30_Char']
        ];
    }

    /**
     * Tests that the built software version string is of the appropriate format.
     *
     * @dataProvider buildSoftwareVersionProvider
     * @param $productVersion
     * @throws \ReflectionException
     */
    public function testBuildSoftwareVersion($productVersion)
    {
        $method = new \ReflectionMethod($this->model, 'buildSoftwareVersion');
        $method->setAccessible(true);

        $this->productMetadataMock->method('getVersion')->willReturn($productVersion);

        $softwareVersion = $method->invoke($this->model);
        $this->assertLessThanOrEqual(10, strlen($softwareVersion));
    }

    /**
     * @return array
     */
    public function buildSoftwareVersionProvider()
    {
        return [
            'valid_length' => ['2.3.1'],
            'exceeds_length' => ['dev-MC-1000']
        ];
    }

    /**
     * Creates mock for XML factory.
     *
     * @return ElementFactory|MockObject
     */
    private function getXmlFactory(): MockObject
    {
        $xmlElFactory = $this->getMockBuilder(ElementFactory::class)
            ->disableOriginalConstructor()
            ->setMethods(['create'])
            ->getMock();
        $xmlElFactory->method('create')
            ->willReturnCallback(
                function ($data) {
                    $helper = new ObjectManager($this);

                    return $helper->getObject(
                        Element::class,
                        ['data' => $data['data']]
                    );
                }
            );

        return $xmlElFactory;
    }

    /**
     * Creates mock for rate factory.
     *
     * @return ResultFactory|MockObject
     */
    private function getRateFactory(): MockObject
    {
        $rateFactory = $this->getMockBuilder(ResultFactory::class)
            ->disableOriginalConstructor()
            ->setMethods(['create'])
            ->getMock();
        $rateResult = $this->getMockBuilder(Result::class)
            ->disableOriginalConstructor()
            ->setMethods(null)
            ->getMock();
        $rateFactory->method('create')
            ->willReturn($rateResult);

        return $rateFactory;
    }

    /**
     * Creates mock for rate method factory.
     *
     * @return MethodFactory|MockObject
     */
    private function getRateMethodFactory(): MockObject
    {
        $rateMethodFactory = $this->getMockBuilder(MethodFactory::class)
            ->disableOriginalConstructor()
            ->setMethods(['create'])
            ->getMock();

        $rateMethodFactory->method('create')
            ->willReturnCallback(function () {
                $rateMethod = $this->getMockBuilder(Method::class)
                    ->disableOriginalConstructor()
                    ->setMethods(['setPrice'])
                    ->getMock();
                $rateMethod->method('setPrice')
                    ->willReturnSelf();

                return $rateMethod;
            });

        return $rateMethodFactory;
    }

    /**
     * @return MockObject
     */
    private function getConfigReader(): MockObject
    {
        $configReader = $this->getMockBuilder(Reader::class)
            ->disableOriginalConstructor()
            ->getMock();
        $configReader->method('getModuleDir')
            ->willReturn('/etc/path');

        return $configReader;
    }

    /**
     * @return MockObject
     */
    private function getReadFactory(): MockObject
    {
        $modulesDirectory = $this->getMockBuilder(Read::class)
            ->disableOriginalConstructor()
            ->setMethods(['getRelativePath', 'readFile'])
            ->getMock();
        $modulesDirectory->method('readFile')
            ->willReturn(file_get_contents(__DIR__ . '/_files/countries.xml'));
        $readFactory = $this->createMock(ReadFactory::class);
        $readFactory->method('create')
            ->willReturn($modulesDirectory);

        return $readFactory;
    }

    /**
     * @return MockObject
     */
    private function getStoreManager(): MockObject
    {
        $storeManager = $this->getMockBuilder(StoreManager::class)
            ->disableOriginalConstructor()
            ->setMethods(['getWebsite'])
            ->getMock();
        $website = $this->getMockBuilder(Website::class)
            ->disableOriginalConstructor()
            ->setMethods(['getBaseCurrencyCode', '__wakeup'])
            ->getMock();
        $website->method('getBaseCurrencyCode')
            ->willReturn('USD');
        $storeManager->method('getWebsite')
            ->willReturn($website);

        return $storeManager;
    }

    /**
     * @return CarrierHelper
     */
    private function getCarrierHelper(): CarrierHelper
    {
        $localeResolver = $this->getMockForAbstractClass(ResolverInterface::class);
        $localeResolver->method('getLocale')
            ->willReturn('fr_FR');
        $carrierHelper = $this->objectManager->getObject(
            CarrierHelper::class,
            [
                'localeResolver' => $localeResolver,
            ]
        );

        return $carrierHelper;
    }

    /**
     * @return MockObject
     */
    private function getHttpClientFactory(): MockObject
    {
        $this->httpResponse = $this->getMockBuilder(\Zend_Http_Response::class)
            ->disableOriginalConstructor()
            ->getMock();
        $this->httpClient = $this->getMockBuilder(ZendClient::class)
            ->disableOriginalConstructor()
            ->setMethods(['request'])
            ->getMock();
        $this->httpClient->method('request')
            ->willReturn($this->httpResponse);
        $httpClientFactory = $this->getMockBuilder(ZendClientFactory::class)
            ->disableOriginalConstructor()
            ->getMock();
        $httpClientFactory->method('create')
            ->willReturn($this->httpClient);

        return $httpClientFactory;
    }
}