<?php
/**
 * ProductsApi
 * PHP version 8.1
 *
 * @category Class
 * @package  Vend
 * @author   OpenAPI Generator team
 * @link     https://openapi-generator.tech
 */

/**
 * API 2026-07
 *
 * Lightspeed Retail (X-Series) API.
 *
 * The version of the OpenAPI document: 2026-07
 * Contact: x-series.api@lightspeedhq.com
 * Generated by: https://openapi-generator.tech
 * Generator version: 7.23.0
 */

/**
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

namespace Vend\Api;

use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Vend\ApiException;
use Vend\Configuration;
use Vend\FormDataProcessor;
use Vend\HeaderSelector;
use Vend\ObjectSerializer;

/**
 * ProductsApi Class Doc Comment
 *
 * @category Class
 * @package  Vend
 * @author   OpenAPI Generator team
 * @link     https://openapi-generator.tech
 */
class ProductsApi
{
    /**
     * @var ClientInterface
     */
    protected $client;

    /**
     * @var Configuration
     */
    protected $config;

    /**
     * @var HeaderSelector
     */
    protected $headerSelector;

    /**
     * @var int Host index
     */
    protected $hostIndex;

    /** @var string[] $contentTypes **/
    public const contentTypes = [
        'createProduct' => [
            'application/json',
        ],
        'deleteProduct' => [
            'application/json',
        ],
        'deleteProductFamily' => [
            'application/json',
        ],
        'getPriceBooksForProduct' => [
            'application/json',
        ],
        'getProductByID' => [
            'application/json',
        ],
        'listProducts' => [
            'application/json',
        ],
        'updateProduct' => [
            'application/json',
        ],
        'uploadImage' => [
            'application/octet-stream',
        ],
    ];

    /**
     * @param ClientInterface $client
     * @param Configuration   $config
     * @param HeaderSelector  $selector
     * @param int             $hostIndex (Optional) host index to select the list of hosts if defined in the OpenAPI spec
     */
    public function __construct(
        ?ClientInterface $client = null,
        ?Configuration $config = null,
        ?HeaderSelector $selector = null,
        int $hostIndex = 0
    ) {
        $this->client = $client ?: new Client();
        $this->config = $config ?: Configuration::getDefaultConfiguration();
        $this->headerSelector = $selector ?: new HeaderSelector();
        $this->hostIndex = $hostIndex;
    }

    /**
     * Set the host index
     *
     * @param int $hostIndex Host index (required)
     */
    public function setHostIndex($hostIndex): void
    {
        $this->hostIndex = $hostIndex;
    }

    /**
     * Get the host index
     *
     * @return int Host index
     */
    public function getHostIndex()
    {
        return $this->hostIndex;
    }

    /**
     * @return Configuration
     */
    public function getConfig()
    {
        return $this->config;
    }

    /**
     * Operation createProduct
     *
     * Create product
     *
     * @param  \Vend\Model\ProductCreateBody $product_create_body **Note**: You cannot include both &#x60;price_including_tax&#x60; and &#x60;price_excluding_tax&#x60;. (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['createProduct'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return void
     */
    public function createProduct($product_create_body, string $contentType = self::contentTypes['createProduct'][0])
    {
        $this->createProductWithHttpInfo($product_create_body, $contentType);
    }

    /**
     * Operation createProductWithHttpInfo
     *
     * Create product
     *
     * @param  \Vend\Model\ProductCreateBody $product_create_body **Note**: You cannot include both &#x60;price_including_tax&#x60; and &#x60;price_excluding_tax&#x60;. (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['createProduct'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of null, HTTP status code, HTTP response headers (array of strings)
     */
    public function createProductWithHttpInfo($product_create_body, string $contentType = self::contentTypes['createProduct'][0])
    {
        $request = $this->createProductRequest($product_create_body, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            return [null, $statusCode, $response->getHeaders()];
        } catch (ApiException $e) {
            switch ($e->getCode()) {
            }
        

            throw $e;
        }
    }

    /**
     * Operation createProductAsync
     *
     * Create product
     *
     * @param  \Vend\Model\ProductCreateBody $product_create_body **Note**: You cannot include both &#x60;price_including_tax&#x60; and &#x60;price_excluding_tax&#x60;. (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['createProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function createProductAsync($product_create_body, string $contentType = self::contentTypes['createProduct'][0])
    {
        return $this->createProductAsyncWithHttpInfo($product_create_body, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation createProductAsyncWithHttpInfo
     *
     * Create product
     *
     * @param  \Vend\Model\ProductCreateBody $product_create_body **Note**: You cannot include both &#x60;price_including_tax&#x60; and &#x60;price_excluding_tax&#x60;. (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['createProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function createProductAsyncWithHttpInfo($product_create_body, string $contentType = self::contentTypes['createProduct'][0])
    {
        $returnType = '';
        $request = $this->createProductRequest($product_create_body, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    return [null, $response->getStatusCode(), $response->getHeaders()];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'createProduct'
     *
     * @param  \Vend\Model\ProductCreateBody $product_create_body **Note**: You cannot include both &#x60;price_including_tax&#x60; and &#x60;price_excluding_tax&#x60;. (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['createProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function createProductRequest($product_create_body, string $contentType = self::contentTypes['createProduct'][0])
    {

        // verify the required parameter 'product_create_body' is set
        if ($product_create_body === null || (is_array($product_create_body) && count($product_create_body) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $product_create_body when calling createProduct'
            );
        }


        $resourcePath = '/products';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;





        $headers = $this->headerSelector->selectHeaders(
            ['Example', 'application/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (isset($product_create_body)) {
            if (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the body
                $httpBody = \GuzzleHttp\Utils::jsonEncode(ObjectSerializer::sanitizeForSerialization($product_create_body));
            } else {
                $httpBody = $product_create_body;
            }
        } elseif (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires Bearer (JWT) authentication (access token)
        if (!empty($this->config->getAccessToken())) {
            $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken();
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'POST',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation deleteProduct
     *
     * Delete a single product
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProduct'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return void
     */
    public function deleteProduct($product_id, string $contentType = self::contentTypes['deleteProduct'][0])
    {
        $this->deleteProductWithHttpInfo($product_id, $contentType);
    }

    /**
     * Operation deleteProductWithHttpInfo
     *
     * Delete a single product
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProduct'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of null, HTTP status code, HTTP response headers (array of strings)
     */
    public function deleteProductWithHttpInfo($product_id, string $contentType = self::contentTypes['deleteProduct'][0])
    {
        $request = $this->deleteProductRequest($product_id, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            return [null, $statusCode, $response->getHeaders()];
        } catch (ApiException $e) {
            switch ($e->getCode()) {
            }
        

            throw $e;
        }
    }

    /**
     * Operation deleteProductAsync
     *
     * Delete a single product
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function deleteProductAsync($product_id, string $contentType = self::contentTypes['deleteProduct'][0])
    {
        return $this->deleteProductAsyncWithHttpInfo($product_id, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation deleteProductAsyncWithHttpInfo
     *
     * Delete a single product
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function deleteProductAsyncWithHttpInfo($product_id, string $contentType = self::contentTypes['deleteProduct'][0])
    {
        $returnType = '';
        $request = $this->deleteProductRequest($product_id, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    return [null, $response->getStatusCode(), $response->getHeaders()];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'deleteProduct'
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function deleteProductRequest($product_id, string $contentType = self::contentTypes['deleteProduct'][0])
    {

        // verify the required parameter 'product_id' is set
        if ($product_id === null || (is_array($product_id) && count($product_id) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $product_id when calling deleteProduct'
            );
        }


        $resourcePath = '/products/{product_id}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;



        // path params
        if ($product_id !== null) {
            $resourcePath = str_replace(
                '{product_id}',
                ObjectSerializer::toPathValue($product_id),
                $resourcePath
            );
        }


        $headers = $this->headerSelector->selectHeaders(
            [],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires Bearer (JWT) authentication (access token)
        if (!empty($this->config->getAccessToken())) {
            $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken();
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'DELETE',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation deleteProductFamily
     *
     * Delete a product family
     *
     * @param  string $product_id The product id of a family member (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProductFamily'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return void
     */
    public function deleteProductFamily($product_id, string $contentType = self::contentTypes['deleteProductFamily'][0])
    {
        $this->deleteProductFamilyWithHttpInfo($product_id, $contentType);
    }

    /**
     * Operation deleteProductFamilyWithHttpInfo
     *
     * Delete a product family
     *
     * @param  string $product_id The product id of a family member (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProductFamily'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of null, HTTP status code, HTTP response headers (array of strings)
     */
    public function deleteProductFamilyWithHttpInfo($product_id, string $contentType = self::contentTypes['deleteProductFamily'][0])
    {
        $request = $this->deleteProductFamilyRequest($product_id, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            return [null, $statusCode, $response->getHeaders()];
        } catch (ApiException $e) {
            switch ($e->getCode()) {
            }
        

            throw $e;
        }
    }

    /**
     * Operation deleteProductFamilyAsync
     *
     * Delete a product family
     *
     * @param  string $product_id The product id of a family member (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProductFamily'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function deleteProductFamilyAsync($product_id, string $contentType = self::contentTypes['deleteProductFamily'][0])
    {
        return $this->deleteProductFamilyAsyncWithHttpInfo($product_id, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation deleteProductFamilyAsyncWithHttpInfo
     *
     * Delete a product family
     *
     * @param  string $product_id The product id of a family member (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProductFamily'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function deleteProductFamilyAsyncWithHttpInfo($product_id, string $contentType = self::contentTypes['deleteProductFamily'][0])
    {
        $returnType = '';
        $request = $this->deleteProductFamilyRequest($product_id, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    return [null, $response->getStatusCode(), $response->getHeaders()];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'deleteProductFamily'
     *
     * @param  string $product_id The product id of a family member (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['deleteProductFamily'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function deleteProductFamilyRequest($product_id, string $contentType = self::contentTypes['deleteProductFamily'][0])
    {

        // verify the required parameter 'product_id' is set
        if ($product_id === null || (is_array($product_id) && count($product_id) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $product_id when calling deleteProductFamily'
            );
        }


        $resourcePath = '/products/{product_id}/all';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;



        // path params
        if ($product_id !== null) {
            $resourcePath = str_replace(
                '{product_id}',
                ObjectSerializer::toPathValue($product_id),
                $resourcePath
            );
        }


        $headers = $this->headerSelector->selectHeaders(
            [],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires Bearer (JWT) authentication (access token)
        if (!empty($this->config->getAccessToken())) {
            $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken();
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'DELETE',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation getPriceBooksForProduct
     *
     * Get a list of price books the given product is in
     *
     * @param  string $product_id The product id to find in the Price Books (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getPriceBooksForProduct'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \Vend\Model\PriceBookProductCollection
     */
    public function getPriceBooksForProduct($product_id, string $contentType = self::contentTypes['getPriceBooksForProduct'][0])
    {
        list($response) = $this->getPriceBooksForProductWithHttpInfo($product_id, $contentType);
        return $response;
    }

    /**
     * Operation getPriceBooksForProductWithHttpInfo
     *
     * Get a list of price books the given product is in
     *
     * @param  string $product_id The product id to find in the Price Books (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getPriceBooksForProduct'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \Vend\Model\PriceBookProductCollection, HTTP status code, HTTP response headers (array of strings)
     */
    public function getPriceBooksForProductWithHttpInfo($product_id, string $contentType = self::contentTypes['getPriceBooksForProduct'][0])
    {
        $request = $this->getPriceBooksForProductRequest($product_id, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 200:
                    return $this->handleResponseWithDataType(
                        '\Vend\Model\PriceBookProductCollection',
                        $request,
                        $response,
                    );
            }

            

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }

            return $this->handleResponseWithDataType(
                '\Vend\Model\PriceBookProductCollection',
                $request,
                $response,
            );
        } catch (ApiException $e) {
            switch ($e->getCode()) {
                case 200:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        '\Vend\Model\PriceBookProductCollection',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
            }
        

            throw $e;
        }
    }

    /**
     * Operation getPriceBooksForProductAsync
     *
     * Get a list of price books the given product is in
     *
     * @param  string $product_id The product id to find in the Price Books (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getPriceBooksForProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getPriceBooksForProductAsync($product_id, string $contentType = self::contentTypes['getPriceBooksForProduct'][0])
    {
        return $this->getPriceBooksForProductAsyncWithHttpInfo($product_id, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation getPriceBooksForProductAsyncWithHttpInfo
     *
     * Get a list of price books the given product is in
     *
     * @param  string $product_id The product id to find in the Price Books (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getPriceBooksForProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getPriceBooksForProductAsyncWithHttpInfo($product_id, string $contentType = self::contentTypes['getPriceBooksForProduct'][0])
    {
        $returnType = '\Vend\Model\PriceBookProductCollection';
        $request = $this->getPriceBooksForProductRequest($product_id, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ($returnType === '\SplFileObject') {
                        $content = $response->getBody(); //stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'getPriceBooksForProduct'
     *
     * @param  string $product_id The product id to find in the Price Books (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getPriceBooksForProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function getPriceBooksForProductRequest($product_id, string $contentType = self::contentTypes['getPriceBooksForProduct'][0])
    {

        // verify the required parameter 'product_id' is set
        if ($product_id === null || (is_array($product_id) && count($product_id) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $product_id when calling getPriceBooksForProduct'
            );
        }


        $resourcePath = '/products/{product_id}/price_book_products';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;



        // path params
        if ($product_id !== null) {
            $resourcePath = str_replace(
                '{product_id}',
                ObjectSerializer::toPathValue($product_id),
                $resourcePath
            );
        }


        $headers = $this->headerSelector->selectHeaders(
            ['application/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires Bearer (JWT) authentication (access token)
        if (!empty($this->config->getAccessToken())) {
            $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken();
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'GET',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation getProductByID
     *
     * Get a single product
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getProductByID'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \Vend\Model\ProductResponse
     */
    public function getProductByID($product_id, string $contentType = self::contentTypes['getProductByID'][0])
    {
        list($response) = $this->getProductByIDWithHttpInfo($product_id, $contentType);
        return $response;
    }

    /**
     * Operation getProductByIDWithHttpInfo
     *
     * Get a single product
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getProductByID'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \Vend\Model\ProductResponse, HTTP status code, HTTP response headers (array of strings)
     */
    public function getProductByIDWithHttpInfo($product_id, string $contentType = self::contentTypes['getProductByID'][0])
    {
        $request = $this->getProductByIDRequest($product_id, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 200:
                    return $this->handleResponseWithDataType(
                        '\Vend\Model\ProductResponse',
                        $request,
                        $response,
                    );
            }

            

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }

            return $this->handleResponseWithDataType(
                '\Vend\Model\ProductResponse',
                $request,
                $response,
            );
        } catch (ApiException $e) {
            switch ($e->getCode()) {
                case 200:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        '\Vend\Model\ProductResponse',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
            }
        

            throw $e;
        }
    }

    /**
     * Operation getProductByIDAsync
     *
     * Get a single product
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getProductByID'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getProductByIDAsync($product_id, string $contentType = self::contentTypes['getProductByID'][0])
    {
        return $this->getProductByIDAsyncWithHttpInfo($product_id, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation getProductByIDAsyncWithHttpInfo
     *
     * Get a single product
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getProductByID'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getProductByIDAsyncWithHttpInfo($product_id, string $contentType = self::contentTypes['getProductByID'][0])
    {
        $returnType = '\Vend\Model\ProductResponse';
        $request = $this->getProductByIDRequest($product_id, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ($returnType === '\SplFileObject') {
                        $content = $response->getBody(); //stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'getProductByID'
     *
     * @param  string $product_id The product id (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getProductByID'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function getProductByIDRequest($product_id, string $contentType = self::contentTypes['getProductByID'][0])
    {

        // verify the required parameter 'product_id' is set
        if ($product_id === null || (is_array($product_id) && count($product_id) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $product_id when calling getProductByID'
            );
        }


        $resourcePath = '/products/{product_id}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;



        // path params
        if ($product_id !== null) {
            $resourcePath = str_replace(
                '{product_id}',
                ObjectSerializer::toPathValue($product_id),
                $resourcePath
            );
        }


        $headers = $this->headerSelector->selectHeaders(
            ['application/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires Bearer (JWT) authentication (access token)
        if (!empty($this->config->getAccessToken())) {
            $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken();
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'GET',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation listProducts
     *
     * List products
     *
     * @param  int|null $after The lower limit for the version numbers to be included in the response. (optional)
     * @param  int|null $before The upper limit for the version numbers to be included in the response. (optional)
     * @param  bool|null $deleted Indicates whether deleted items should be included in the response. (optional)
     * @param  int|null $page_size The maximum number of items to be returned in the response. (optional)
     * @param  string|null $sku Allows loading a product by one of its SKUs. Note that all other query params are ignored if this is provided. (optional)
     * @param  string|null $name Allows loading products with the name provided in this parameter. This query typically retrieves all products from the product family with the provided name. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string|null $family_name Alias for &#39;name&#39;. Allows loading products that belong to the family with the name provided in this parameter. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string[]|null $includes Side-load related entities. Supported value &#39;composite_products&#39;. (optional)
     * @param  bool|null $include_images Whether to include product image fields in the response. Defaults to true. (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['listProducts'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \Vend\Model\ProductCollection
     */
    public function listProducts($after = null, $before = null, $deleted = null, $page_size = null, $sku = null, $name = null, $family_name = null, $includes = null, $include_images = null, string $contentType = self::contentTypes['listProducts'][0])
    {
        list($response) = $this->listProductsWithHttpInfo($after, $before, $deleted, $page_size, $sku, $name, $family_name, $includes, $include_images, $contentType);
        return $response;
    }

    /**
     * Operation listProductsWithHttpInfo
     *
     * List products
     *
     * @param  int|null $after The lower limit for the version numbers to be included in the response. (optional)
     * @param  int|null $before The upper limit for the version numbers to be included in the response. (optional)
     * @param  bool|null $deleted Indicates whether deleted items should be included in the response. (optional)
     * @param  int|null $page_size The maximum number of items to be returned in the response. (optional)
     * @param  string|null $sku Allows loading a product by one of its SKUs. Note that all other query params are ignored if this is provided. (optional)
     * @param  string|null $name Allows loading products with the name provided in this parameter. This query typically retrieves all products from the product family with the provided name. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string|null $family_name Alias for &#39;name&#39;. Allows loading products that belong to the family with the name provided in this parameter. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string[]|null $includes Side-load related entities. Supported value &#39;composite_products&#39;. (optional)
     * @param  bool|null $include_images Whether to include product image fields in the response. Defaults to true. (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['listProducts'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \Vend\Model\ProductCollection, HTTP status code, HTTP response headers (array of strings)
     */
    public function listProductsWithHttpInfo($after = null, $before = null, $deleted = null, $page_size = null, $sku = null, $name = null, $family_name = null, $includes = null, $include_images = null, string $contentType = self::contentTypes['listProducts'][0])
    {
        $request = $this->listProductsRequest($after, $before, $deleted, $page_size, $sku, $name, $family_name, $includes, $include_images, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 200:
                    return $this->handleResponseWithDataType(
                        '\Vend\Model\ProductCollection',
                        $request,
                        $response,
                    );
            }

            

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }

            return $this->handleResponseWithDataType(
                '\Vend\Model\ProductCollection',
                $request,
                $response,
            );
        } catch (ApiException $e) {
            switch ($e->getCode()) {
                case 200:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        '\Vend\Model\ProductCollection',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
            }
        

            throw $e;
        }
    }

    /**
     * Operation listProductsAsync
     *
     * List products
     *
     * @param  int|null $after The lower limit for the version numbers to be included in the response. (optional)
     * @param  int|null $before The upper limit for the version numbers to be included in the response. (optional)
     * @param  bool|null $deleted Indicates whether deleted items should be included in the response. (optional)
     * @param  int|null $page_size The maximum number of items to be returned in the response. (optional)
     * @param  string|null $sku Allows loading a product by one of its SKUs. Note that all other query params are ignored if this is provided. (optional)
     * @param  string|null $name Allows loading products with the name provided in this parameter. This query typically retrieves all products from the product family with the provided name. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string|null $family_name Alias for &#39;name&#39;. Allows loading products that belong to the family with the name provided in this parameter. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string[]|null $includes Side-load related entities. Supported value &#39;composite_products&#39;. (optional)
     * @param  bool|null $include_images Whether to include product image fields in the response. Defaults to true. (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['listProducts'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function listProductsAsync($after = null, $before = null, $deleted = null, $page_size = null, $sku = null, $name = null, $family_name = null, $includes = null, $include_images = null, string $contentType = self::contentTypes['listProducts'][0])
    {
        return $this->listProductsAsyncWithHttpInfo($after, $before, $deleted, $page_size, $sku, $name, $family_name, $includes, $include_images, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation listProductsAsyncWithHttpInfo
     *
     * List products
     *
     * @param  int|null $after The lower limit for the version numbers to be included in the response. (optional)
     * @param  int|null $before The upper limit for the version numbers to be included in the response. (optional)
     * @param  bool|null $deleted Indicates whether deleted items should be included in the response. (optional)
     * @param  int|null $page_size The maximum number of items to be returned in the response. (optional)
     * @param  string|null $sku Allows loading a product by one of its SKUs. Note that all other query params are ignored if this is provided. (optional)
     * @param  string|null $name Allows loading products with the name provided in this parameter. This query typically retrieves all products from the product family with the provided name. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string|null $family_name Alias for &#39;name&#39;. Allows loading products that belong to the family with the name provided in this parameter. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string[]|null $includes Side-load related entities. Supported value &#39;composite_products&#39;. (optional)
     * @param  bool|null $include_images Whether to include product image fields in the response. Defaults to true. (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['listProducts'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function listProductsAsyncWithHttpInfo($after = null, $before = null, $deleted = null, $page_size = null, $sku = null, $name = null, $family_name = null, $includes = null, $include_images = null, string $contentType = self::contentTypes['listProducts'][0])
    {
        $returnType = '\Vend\Model\ProductCollection';
        $request = $this->listProductsRequest($after, $before, $deleted, $page_size, $sku, $name, $family_name, $includes, $include_images, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ($returnType === '\SplFileObject') {
                        $content = $response->getBody(); //stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'listProducts'
     *
     * @param  int|null $after The lower limit for the version numbers to be included in the response. (optional)
     * @param  int|null $before The upper limit for the version numbers to be included in the response. (optional)
     * @param  bool|null $deleted Indicates whether deleted items should be included in the response. (optional)
     * @param  int|null $page_size The maximum number of items to be returned in the response. (optional)
     * @param  string|null $sku Allows loading a product by one of its SKUs. Note that all other query params are ignored if this is provided. (optional)
     * @param  string|null $name Allows loading products with the name provided in this parameter. This query typically retrieves all products from the product family with the provided name. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string|null $family_name Alias for &#39;name&#39;. Allows loading products that belong to the family with the name provided in this parameter. Note that all other query parameters are ignored if this is provided. (optional)
     * @param  string[]|null $includes Side-load related entities. Supported value &#39;composite_products&#39;. (optional)
     * @param  bool|null $include_images Whether to include product image fields in the response. Defaults to true. (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['listProducts'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function listProductsRequest($after = null, $before = null, $deleted = null, $page_size = null, $sku = null, $name = null, $family_name = null, $includes = null, $include_images = null, string $contentType = self::contentTypes['listProducts'][0])
    {











        $resourcePath = '/products';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $after,
            'after', // param base name
            'integer', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $before,
            'before', // param base name
            'integer', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $deleted,
            'deleted', // param base name
            'boolean', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $page_size,
            'page_size', // param base name
            'integer', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $sku,
            'sku', // param base name
            'string', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $name,
            'name', // param base name
            'string', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $family_name,
            'family_name', // param base name
            'string', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $includes,
            'includes[]', // param base name
            'array', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $include_images,
            'include_images', // param base name
            'boolean', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);




        $headers = $this->headerSelector->selectHeaders(
            ['application/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires Bearer (JWT) authentication (access token)
        if (!empty($this->config->getAccessToken())) {
            $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken();
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'GET',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation updateProduct
     *
     * Update a product
     *
     * @param  string $product_id The object identifier of the Product to update. (required)
     * @param  \Vend\Model\ProductUpdate21Request $product_update21_request product_update21_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['updateProduct'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return object|object|object
     */
    public function updateProduct($product_id, $product_update21_request, string $contentType = self::contentTypes['updateProduct'][0])
    {
        list($response) = $this->updateProductWithHttpInfo($product_id, $product_update21_request, $contentType);
        return $response;
    }

    /**
     * Operation updateProductWithHttpInfo
     *
     * Update a product
     *
     * @param  string $product_id The object identifier of the Product to update. (required)
     * @param  \Vend\Model\ProductUpdate21Request $product_update21_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['updateProduct'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of object|object|object, HTTP status code, HTTP response headers (array of strings)
     */
    public function updateProductWithHttpInfo($product_id, $product_update21_request, string $contentType = self::contentTypes['updateProduct'][0])
    {
        $request = $this->updateProductRequest($product_id, $product_update21_request, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 200:
                    return $this->handleResponseWithDataType(
                        'object',
                        $request,
                        $response,
                    );
                case 404:
                    return $this->handleResponseWithDataType(
                        'object',
                        $request,
                        $response,
                    );
                case 422:
                    return $this->handleResponseWithDataType(
                        'object',
                        $request,
                        $response,
                    );
            }

            

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }

            return $this->handleResponseWithDataType(
                'object',
                $request,
                $response,
            );
        } catch (ApiException $e) {
            switch ($e->getCode()) {
                case 200:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        'object',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
                case 404:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        'object',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
                case 422:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        'object',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
            }
        

            throw $e;
        }
    }

    /**
     * Operation updateProductAsync
     *
     * Update a product
     *
     * @param  string $product_id The object identifier of the Product to update. (required)
     * @param  \Vend\Model\ProductUpdate21Request $product_update21_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['updateProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function updateProductAsync($product_id, $product_update21_request, string $contentType = self::contentTypes['updateProduct'][0])
    {
        return $this->updateProductAsyncWithHttpInfo($product_id, $product_update21_request, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation updateProductAsyncWithHttpInfo
     *
     * Update a product
     *
     * @param  string $product_id The object identifier of the Product to update. (required)
     * @param  \Vend\Model\ProductUpdate21Request $product_update21_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['updateProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function updateProductAsyncWithHttpInfo($product_id, $product_update21_request, string $contentType = self::contentTypes['updateProduct'][0])
    {
        $returnType = 'object';
        $request = $this->updateProductRequest($product_id, $product_update21_request, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ($returnType === '\SplFileObject') {
                        $content = $response->getBody(); //stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'updateProduct'
     *
     * @param  string $product_id The object identifier of the Product to update. (required)
     * @param  \Vend\Model\ProductUpdate21Request $product_update21_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['updateProduct'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function updateProductRequest($product_id, $product_update21_request, string $contentType = self::contentTypes['updateProduct'][0])
    {

        // verify the required parameter 'product_id' is set
        if ($product_id === null || (is_array($product_id) && count($product_id) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $product_id when calling updateProduct'
            );
        }

        // verify the required parameter 'product_update21_request' is set
        if ($product_update21_request === null || (is_array($product_update21_request) && count($product_update21_request) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $product_update21_request when calling updateProduct'
            );
        }


        $resourcePath = '/products/{product_id}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;



        // path params
        if ($product_id !== null) {
            $resourcePath = str_replace(
                '{product_id}',
                ObjectSerializer::toPathValue($product_id),
                $resourcePath
            );
        }


        $headers = $this->headerSelector->selectHeaders(
            ['application/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (isset($product_update21_request)) {
            if (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the body
                $httpBody = \GuzzleHttp\Utils::jsonEncode(ObjectSerializer::sanitizeForSerialization($product_update21_request));
            } else {
                $httpBody = $product_update21_request;
            }
        } elseif (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires Bearer (JWT) authentication (access token)
        if (!empty($this->config->getAccessToken())) {
            $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken();
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'PUT',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation uploadImage
     *
     * Upload an image
     *
     * @param  string $product_id The product id (required)
     * @param  \Vend\Model\UploadImageRequest $upload_image_request upload_image_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImage'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \Vend\Model\ImageResponse
     */
    public function uploadImage($product_id, $upload_image_request, string $contentType = self::contentTypes['uploadImage'][0])
    {
        list($response) = $this->uploadImageWithHttpInfo($product_id, $upload_image_request, $contentType);
        return $response;
    }

    /**
     * Operation uploadImageWithHttpInfo
     *
     * Upload an image
     *
     * @param  string $product_id The product id (required)
     * @param  \Vend\Model\UploadImageRequest $upload_image_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImage'] to see the possible values for this operation
     *
     * @throws \Vend\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \Vend\Model\ImageResponse, HTTP status code, HTTP response headers (array of strings)
     */
    public function uploadImageWithHttpInfo($product_id, $upload_image_request, string $contentType = self::contentTypes['uploadImage'][0])
    {
        $request = $this->uploadImageRequest($product_id, $upload_image_request, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 201:
                    return $this->handleResponseWithDataType(
                        '\Vend\Model\ImageResponse',
                        $request,
                        $response,
                    );
            }

            

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }

            return $this->handleResponseWithDataType(
                '\Vend\Model\ImageResponse',
                $request,
                $response,
            );
        } catch (ApiException $e) {
            switch ($e->getCode()) {
                case 201:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        '\Vend\Model\ImageResponse',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
            }
        

            throw $e;
        }
    }

    /**
     * Operation uploadImageAsync
     *
     * Upload an image
     *
     * @param  string $product_id The product id (required)
     * @param  \Vend\Model\UploadImageRequest $upload_image_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImage'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function uploadImageAsync($product_id, $upload_image_request, string $contentType = self::contentTypes['uploadImage'][0])
    {
        return $this->uploadImageAsyncWithHttpInfo($product_id, $upload_image_request, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation uploadImageAsyncWithHttpInfo
     *
     * Upload an image
     *
     * @param  string $product_id The product id (required)
     * @param  \Vend\Model\UploadImageRequest $upload_image_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImage'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function uploadImageAsyncWithHttpInfo($product_id, $upload_image_request, string $contentType = self::contentTypes['uploadImage'][0])
    {
        $returnType = '\Vend\Model\ImageResponse';
        $request = $this->uploadImageRequest($product_id, $upload_image_request, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ($returnType === '\SplFileObject') {
                        $content = $response->getBody(); //stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'uploadImage'
     *
     * @param  string $product_id The product id (required)
     * @param  \Vend\Model\UploadImageRequest $upload_image_request (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImage'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function uploadImageRequest($product_id, $upload_image_request, string $contentType = self::contentTypes['uploadImage'][0])
    {

        // verify the required parameter 'product_id' is set
        if ($product_id === null || (is_array($product_id) && count($product_id) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $product_id when calling uploadImage'
            );
        }

        // verify the required parameter 'upload_image_request' is set
        if ($upload_image_request === null || (is_array($upload_image_request) && count($upload_image_request) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $upload_image_request when calling uploadImage'
            );
        }


        $resourcePath = '/products/{product_id}/actions/image_upload';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;



        // path params
        if ($product_id !== null) {
            $resourcePath = str_replace(
                '{product_id}',
                ObjectSerializer::toPathValue($product_id),
                $resourcePath
            );
        }


        $headers = $this->headerSelector->selectHeaders(
            ['application/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (isset($upload_image_request)) {
            if (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the body
                $httpBody = \GuzzleHttp\Utils::jsonEncode(ObjectSerializer::sanitizeForSerialization($upload_image_request));
            } else {
                $httpBody = $upload_image_request;
            }
        } elseif (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires Bearer (JWT) authentication (access token)
        if (!empty($this->config->getAccessToken())) {
            $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken();
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'POST',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Create http client option
     *
     * @throws \RuntimeException on file opening failure
     * @return array of http client options
     */
    protected function createHttpClientOption()
    {
        $options = [];
        if ($this->config->getDebug()) {
            $options[RequestOptions::DEBUG] = fopen($this->config->getDebugFile(), 'a');
            if (!$options[RequestOptions::DEBUG]) {
                throw new \RuntimeException('Failed to open the debug file: ' . $this->config->getDebugFile());
            }
        }

        if ($this->config->getCertFile()) {
            $options[RequestOptions::CERT] = $this->config->getCertFile();
        }

        if ($this->config->getKeyFile()) {
            $options[RequestOptions::SSL_KEY] = $this->config->getKeyFile();
        }

        return $options;
    }

    private function handleResponseWithDataType(
        string $dataType,
        RequestInterface $request,
        ResponseInterface $response
    ): array {
        if ($dataType === '\SplFileObject') {
            $content = $response->getBody(); //stream goes to serializer
        } else {
            $content = (string) $response->getBody();
            if ($dataType !== 'string') {
                try {
                    $content = json_decode($content, false, 512, JSON_THROW_ON_ERROR);
                } catch (\JsonException $exception) {
                    throw new ApiException(
                        sprintf(
                            'Error JSON decoding server response (%s)',
                            $request->getUri()
                        ),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                        $content
                    );
                }
            }
        }

        return [
            ObjectSerializer::deserialize($content, $dataType, []),
            $response->getStatusCode(),
            $response->getHeaders()
        ];
    }

    private function responseWithinRangeCode(
        string $rangeCode,
        int $statusCode
    ): bool {
        $left = (int) ($rangeCode[0].'00');
        $right = (int) ($rangeCode[0].'99');

        return $statusCode >= $left && $statusCode <= $right;
    }
}
