<?php

declare(strict_types=1);

namespace AmazonPHP\SellingPartner\Api\ServiceApi;

use AmazonPHP\SellingPartner\AccessToken;
use AmazonPHP\SellingPartner\Configuration;
use AmazonPHP\SellingPartner\Exception\ApiException;
use AmazonPHP\SellingPartner\Exception\InvalidArgumentException;
use AmazonPHP\SellingPartner\HttpFactory;
use AmazonPHP\SellingPartner\HttpSignatureHeaders;
use AmazonPHP\SellingPartner\ObjectSerializer;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Log\LoggerInterface;

/**
 * Selling Partner API for Services.
 *
 * With the Services API, you can build applications that help service providers get and modify their service orders and manage their resources.
 *
 * The version of the OpenAPI document: v1
 *
 * This class was auto-generated by https://openapi-generator.tech
 * Do not change it, it will be overwritten with next execution of /bin/generate.sh
 */
final class ServicesSDK implements ServicesSDKInterface
{
    public function __construct(private readonly ClientInterface $client, private readonly HttpFactory $httpFactory, private readonly Configuration $configuration, private readonly LoggerInterface $logger)
    {
    }

    /**
     * Operation addAppointmentForServiceJobByServiceJobId.
     *
     * @param string $service_job_id An Amazon defined service job identifier. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\AddAppointmentRequest $body Add appointment operation input details. (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function addAppointmentForServiceJobByServiceJobId(AccessToken $accessToken, string $region, string $service_job_id, \AmazonPHP\SellingPartner\Model\Services\AddAppointmentRequest $body) : \AmazonPHP\SellingPartner\Model\Services\SetAppointmentResponse
    {
        $request = $this->addAppointmentForServiceJobByServiceJobIdRequest($accessToken, $region, $service_job_id, $body);

        $this->configuration->extensions()->preRequest('Services', 'addAppointmentForServiceJobByServiceJobId', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'addAppointmentForServiceJobByServiceJobId')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'addAppointmentForServiceJobByServiceJobId'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'addAppointmentForServiceJobByServiceJobId',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'addAppointmentForServiceJobByServiceJobId', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'addAppointmentForServiceJobByServiceJobId')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'addAppointmentForServiceJobByServiceJobId'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'addAppointmentForServiceJobByServiceJobId',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\SetAppointmentResponse',
            []
        );
    }

    /**
     * Create request for operation 'addAppointmentForServiceJobByServiceJobId'.
     *
     * @param string $service_job_id An Amazon defined service job identifier. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\AddAppointmentRequest $body Add appointment operation input details. (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function addAppointmentForServiceJobByServiceJobIdRequest(AccessToken $accessToken, string $region, string $service_job_id, \AmazonPHP\SellingPartner\Model\Services\AddAppointmentRequest $body) : RequestInterface
    {
        // verify the required parameter 'service_job_id' is set
        if ($service_job_id === null || (\is_array($service_job_id) && \count($service_job_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $service_job_id when calling addAppointmentForServiceJobByServiceJobId'
            );
        }

        if (\strlen($service_job_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.addAppointmentForServiceJobByServiceJobId, must be smaller than or equal to 100.');
        }

        if (\strlen($service_job_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.addAppointmentForServiceJobByServiceJobId, must be bigger than or equal to 1.');
        }

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

        $resourcePath = '/service/v1/serviceJobs/{serviceJobId}/appointments';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'POST',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation assignAppointmentResources.
     *
     * @param string $service_job_id An Amazon-defined service job identifier. Get this value by calling the &#x60;getServiceJobs&#x60; operation of the Services API. (required)
     * @param string $appointment_id An Amazon-defined identifier of active service job appointment. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\AssignAppointmentResourcesRequest $body body (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function assignAppointmentResources(AccessToken $accessToken, string $region, string $service_job_id, string $appointment_id, \AmazonPHP\SellingPartner\Model\Services\AssignAppointmentResourcesRequest $body) : \AmazonPHP\SellingPartner\Model\Services\AssignAppointmentResourcesResponse
    {
        $request = $this->assignAppointmentResourcesRequest($accessToken, $region, $service_job_id, $appointment_id, $body);

        $this->configuration->extensions()->preRequest('Services', 'assignAppointmentResources', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'assignAppointmentResources')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'assignAppointmentResources'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'assignAppointmentResources',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'assignAppointmentResources', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'assignAppointmentResources')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'assignAppointmentResources'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'assignAppointmentResources',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\AssignAppointmentResourcesResponse',
            []
        );
    }

    /**
     * Create request for operation 'assignAppointmentResources'.
     *
     * @param string $service_job_id An Amazon-defined service job identifier. Get this value by calling the &#x60;getServiceJobs&#x60; operation of the Services API. (required)
     * @param string $appointment_id An Amazon-defined identifier of active service job appointment. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\AssignAppointmentResourcesRequest $body (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function assignAppointmentResourcesRequest(AccessToken $accessToken, string $region, string $service_job_id, string $appointment_id, \AmazonPHP\SellingPartner\Model\Services\AssignAppointmentResourcesRequest $body) : RequestInterface
    {
        // verify the required parameter 'service_job_id' is set
        if ($service_job_id === null || (\is_array($service_job_id) && \count($service_job_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $service_job_id when calling assignAppointmentResources'
            );
        }

        if (\strlen($service_job_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.assignAppointmentResources, must be smaller than or equal to 100.');
        }

        if (\strlen($service_job_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.assignAppointmentResources, must be bigger than or equal to 1.');
        }

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

        if (\strlen($appointment_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$appointment_id" when calling ServiceApi.assignAppointmentResources, must be smaller than or equal to 100.');
        }

        if (\strlen($appointment_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$appointment_id" when calling ServiceApi.assignAppointmentResources, must be bigger than or equal to 1.');
        }

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

        $resourcePath = '/service/v1/serviceJobs/{serviceJobId}/appointments/{appointmentId}/resources';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

        // path params
        if ($service_job_id !== null) {
            $resourcePath = \str_replace(
                '{' . 'serviceJobId' . '}',
                ObjectSerializer::toPathValue($service_job_id),
                $resourcePath
            );
        }
        // path params
        if ($appointment_id !== null) {
            $resourcePath = \str_replace(
                '{' . 'appointmentId' . '}',
                ObjectSerializer::toPathValue($appointment_id),
                $resourcePath
            );
        }

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'PUT',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation cancelReservation.
     *
     * @param string $reservation_id Reservation Identifier (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function cancelReservation(AccessToken $accessToken, string $region, string $reservation_id, array $marketplace_ids) : \AmazonPHP\SellingPartner\Model\Services\CancelReservationResponse
    {
        $request = $this->cancelReservationRequest($accessToken, $region, $reservation_id, $marketplace_ids);

        $this->configuration->extensions()->preRequest('Services', 'cancelReservation', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'cancelReservation')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'cancelReservation'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'cancelReservation',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'cancelReservation', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'cancelReservation')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'cancelReservation'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'cancelReservation',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\CancelReservationResponse',
            []
        );
    }

    /**
     * Create request for operation 'cancelReservation'.
     *
     * @param string $reservation_id Reservation Identifier (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function cancelReservationRequest(AccessToken $accessToken, string $region, string $reservation_id, array $marketplace_ids) : RequestInterface
    {
        // verify the required parameter 'reservation_id' is set
        if ($reservation_id === null || (\is_array($reservation_id) && \count($reservation_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $reservation_id when calling cancelReservation'
            );
        }

        if (\strlen($reservation_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$reservation_id" when calling ServiceApi.cancelReservation, must be smaller than or equal to 100.');
        }

        if (\strlen($reservation_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$reservation_id" when calling ServiceApi.cancelReservation, must be bigger than or equal to 1.');
        }

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

        if (\count($marketplace_ids) > 1) {
            throw new InvalidArgumentException('invalid value for "$marketplace_ids" when calling ServiceApi.cancelReservation, number of items must be less than or equal to 1.');
        }

        $resourcePath = '/service/v1/reservation/{reservationId}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($marketplace_ids)) {
            $marketplace_ids = ObjectSerializer::serializeCollection($marketplace_ids, 'form', true);
        }

        if ($marketplace_ids !== null) {
            $queryParams['marketplaceIds'] = ObjectSerializer::toString($marketplace_ids);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'DELETE',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation cancelServiceJobByServiceJobId.
     *
     * @param string $service_job_id An Amazon defined service job identifier. (required)
     * @param string $cancellation_reason_code A cancel reason code that specifies the reason for cancelling a service job. (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function cancelServiceJobByServiceJobId(AccessToken $accessToken, string $region, string $service_job_id, string $cancellation_reason_code) : \AmazonPHP\SellingPartner\Model\Services\CancelServiceJobByServiceJobIdResponse
    {
        $request = $this->cancelServiceJobByServiceJobIdRequest($accessToken, $region, $service_job_id, $cancellation_reason_code);

        $this->configuration->extensions()->preRequest('Services', 'cancelServiceJobByServiceJobId', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'cancelServiceJobByServiceJobId')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'cancelServiceJobByServiceJobId'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'cancelServiceJobByServiceJobId',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'cancelServiceJobByServiceJobId', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'cancelServiceJobByServiceJobId')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'cancelServiceJobByServiceJobId'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'cancelServiceJobByServiceJobId',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\CancelServiceJobByServiceJobIdResponse',
            []
        );
    }

    /**
     * Create request for operation 'cancelServiceJobByServiceJobId'.
     *
     * @param string $service_job_id An Amazon defined service job identifier. (required)
     * @param string $cancellation_reason_code A cancel reason code that specifies the reason for cancelling a service job. (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function cancelServiceJobByServiceJobIdRequest(AccessToken $accessToken, string $region, string $service_job_id, string $cancellation_reason_code) : RequestInterface
    {
        // verify the required parameter 'service_job_id' is set
        if ($service_job_id === null || (\is_array($service_job_id) && \count($service_job_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $service_job_id when calling cancelServiceJobByServiceJobId'
            );
        }

        if (\strlen($service_job_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.cancelServiceJobByServiceJobId, must be smaller than or equal to 100.');
        }

        if (\strlen($service_job_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.cancelServiceJobByServiceJobId, must be bigger than or equal to 1.');
        }

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

        if (\strlen($cancellation_reason_code) > 100) {
            throw new InvalidArgumentException('invalid length for "$cancellation_reason_code" when calling ServiceApi.cancelServiceJobByServiceJobId, must be smaller than or equal to 100.');
        }

        if (\strlen($cancellation_reason_code) < 1) {
            throw new InvalidArgumentException('invalid length for "$cancellation_reason_code" when calling ServiceApi.cancelServiceJobByServiceJobId, must be bigger than or equal to 1.');
        }

        if (!\preg_match('/^[A-Z0-9_]*$/', $cancellation_reason_code)) {
            throw new InvalidArgumentException('invalid value for "cancellation_reason_code" when calling ServiceApi.cancelServiceJobByServiceJobId, must conform to the pattern /^[A-Z0-9_]*$/.');
        }

        $resourcePath = '/service/v1/serviceJobs/{serviceJobId}/cancellations';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($cancellation_reason_code)) {
            $cancellation_reason_code = ObjectSerializer::serializeCollection($cancellation_reason_code, '', true);
        }

        if ($cancellation_reason_code !== null) {
            $queryParams['cancellationReasonCode'] = ObjectSerializer::toString($cancellation_reason_code);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'PUT',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation completeServiceJobByServiceJobId.
     *
     * @param string $service_job_id An Amazon defined service job identifier. (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function completeServiceJobByServiceJobId(AccessToken $accessToken, string $region, string $service_job_id) : \AmazonPHP\SellingPartner\Model\Services\CompleteServiceJobByServiceJobIdResponse
    {
        $request = $this->completeServiceJobByServiceJobIdRequest($accessToken, $region, $service_job_id);

        $this->configuration->extensions()->preRequest('Services', 'completeServiceJobByServiceJobId', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'completeServiceJobByServiceJobId')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'completeServiceJobByServiceJobId'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'completeServiceJobByServiceJobId',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'completeServiceJobByServiceJobId', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'completeServiceJobByServiceJobId')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'completeServiceJobByServiceJobId'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'completeServiceJobByServiceJobId',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\CompleteServiceJobByServiceJobIdResponse',
            []
        );
    }

    /**
     * Create request for operation 'completeServiceJobByServiceJobId'.
     *
     * @param string $service_job_id An Amazon defined service job identifier. (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function completeServiceJobByServiceJobIdRequest(AccessToken $accessToken, string $region, string $service_job_id) : RequestInterface
    {
        // verify the required parameter 'service_job_id' is set
        if ($service_job_id === null || (\is_array($service_job_id) && \count($service_job_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $service_job_id when calling completeServiceJobByServiceJobId'
            );
        }

        if (\strlen($service_job_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.completeServiceJobByServiceJobId, must be smaller than or equal to 100.');
        }

        if (\strlen($service_job_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.completeServiceJobByServiceJobId, must be bigger than or equal to 1.');
        }

        $resourcePath = '/service/v1/serviceJobs/{serviceJobId}/completions';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'PUT',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation createReservation.
     *
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\CreateReservationRequest $body Reservation details (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function createReservation(AccessToken $accessToken, string $region, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\CreateReservationRequest $body) : \AmazonPHP\SellingPartner\Model\Services\CreateReservationResponse
    {
        $request = $this->createReservationRequest($accessToken, $region, $marketplace_ids, $body);

        $this->configuration->extensions()->preRequest('Services', 'createReservation', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'createReservation')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'createReservation'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'createReservation',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'createReservation', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'createReservation')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'createReservation'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'createReservation',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\CreateReservationResponse',
            []
        );
    }

    /**
     * Create request for operation 'createReservation'.
     *
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\CreateReservationRequest $body Reservation details (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function createReservationRequest(AccessToken $accessToken, string $region, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\CreateReservationRequest $body) : RequestInterface
    {
        // verify the required parameter 'marketplace_ids' is set
        if ($marketplace_ids === null || (\is_array($marketplace_ids) && \count($marketplace_ids) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $marketplace_ids when calling createReservation'
            );
        }

        if (\count($marketplace_ids) > 1) {
            throw new InvalidArgumentException('invalid value for "$marketplace_ids" when calling ServiceApi.createReservation, number of items must be less than or equal to 1.');
        }

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

        $resourcePath = '/service/v1/reservation';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($marketplace_ids)) {
            $marketplace_ids = ObjectSerializer::serializeCollection($marketplace_ids, 'form', true);
        }

        if ($marketplace_ids !== null) {
            $queryParams['marketplaceIds'] = ObjectSerializer::toString($marketplace_ids);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'POST',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation createServiceDocumentUploadDestination.
     *
     * @param \AmazonPHP\SellingPartner\Model\Services\ServiceUploadDocument $body Upload document operation input details. (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function createServiceDocumentUploadDestination(AccessToken $accessToken, string $region, \AmazonPHP\SellingPartner\Model\Services\ServiceUploadDocument $body) : \AmazonPHP\SellingPartner\Model\Services\CreateServiceDocumentUploadDestination
    {
        $request = $this->createServiceDocumentUploadDestinationRequest($accessToken, $region, $body);

        $this->configuration->extensions()->preRequest('Services', 'createServiceDocumentUploadDestination', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'createServiceDocumentUploadDestination')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'createServiceDocumentUploadDestination'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'createServiceDocumentUploadDestination',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'createServiceDocumentUploadDestination', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'createServiceDocumentUploadDestination')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'createServiceDocumentUploadDestination'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'createServiceDocumentUploadDestination',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\CreateServiceDocumentUploadDestination',
            []
        );
    }

    /**
     * Create request for operation 'createServiceDocumentUploadDestination'.
     *
     * @param \AmazonPHP\SellingPartner\Model\Services\ServiceUploadDocument $body Upload document operation input details. (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function createServiceDocumentUploadDestinationRequest(AccessToken $accessToken, string $region, \AmazonPHP\SellingPartner\Model\Services\ServiceUploadDocument $body) : RequestInterface
    {
        // verify the required parameter 'body' is set
        if ($body === null || (\is_array($body) && \count($body) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $body when calling createServiceDocumentUploadDestination'
            );
        }

        $resourcePath = '/service/v1/documents';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'POST',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation getAppointmentSlots.
     *
     * @param string $asin ASIN associated with the service. (required)
     * @param string $store_id Store identifier defining the region scope to retrive appointment slots. (required)
     * @param string[] $marketplace_ids An identifier for the marketplace for which appointment slots are queried (required)
     * @param null|string $start_time A time from which the appointment slots will be retrieved. The specified time must be in ISO 8601 format. If &#x60;startTime&#x60; is provided, &#x60;endTime&#x60; should also be provided. Default value is as per business configuration. (optional)
     * @param null|string $end_time A time up to which the appointment slots will be retrieved. The specified time must be in ISO 8601 format. If &#x60;endTime&#x60; is provided, &#x60;startTime&#x60; should also be provided. Default value is as per business configuration. Maximum range of appointment slots can be 90 days. (optional)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function getAppointmentSlots(AccessToken $accessToken, string $region, string $asin, string $store_id, array $marketplace_ids, ?string $start_time = null, ?string $end_time = null) : \AmazonPHP\SellingPartner\Model\Services\GetAppointmentSlotsResponse
    {
        $request = $this->getAppointmentSlotsRequest($accessToken, $region, $asin, $store_id, $marketplace_ids, $start_time, $end_time);

        $this->configuration->extensions()->preRequest('Services', 'getAppointmentSlots', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'getAppointmentSlots')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getAppointmentSlots'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'getAppointmentSlots',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'getAppointmentSlots', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'getAppointmentSlots')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getAppointmentSlots'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'getAppointmentSlots',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\GetAppointmentSlotsResponse',
            []
        );
    }

    /**
     * Create request for operation 'getAppointmentSlots'.
     *
     * @param string $asin ASIN associated with the service. (required)
     * @param string $store_id Store identifier defining the region scope to retrive appointment slots. (required)
     * @param string[] $marketplace_ids An identifier for the marketplace for which appointment slots are queried (required)
     * @param null|string $start_time A time from which the appointment slots will be retrieved. The specified time must be in ISO 8601 format. If &#x60;startTime&#x60; is provided, &#x60;endTime&#x60; should also be provided. Default value is as per business configuration. (optional)
     * @param null|string $end_time A time up to which the appointment slots will be retrieved. The specified time must be in ISO 8601 format. If &#x60;endTime&#x60; is provided, &#x60;startTime&#x60; should also be provided. Default value is as per business configuration. Maximum range of appointment slots can be 90 days. (optional)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function getAppointmentSlotsRequest(AccessToken $accessToken, string $region, string $asin, string $store_id, array $marketplace_ids, ?string $start_time = null, ?string $end_time = null) : RequestInterface
    {
        // verify the required parameter 'asin' is set
        if ($asin === null || (\is_array($asin) && \count($asin) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $asin when calling getAppointmentSlots'
            );
        }
        // verify the required parameter 'store_id' is set
        if ($store_id === null || (\is_array($store_id) && \count($store_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $store_id when calling getAppointmentSlots'
            );
        }

        if (\strlen($store_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$store_id" when calling ServiceApi.getAppointmentSlots, must be smaller than or equal to 100.');
        }

        if (\strlen($store_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$store_id" when calling ServiceApi.getAppointmentSlots, must be bigger than or equal to 1.');
        }

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

        if (\count($marketplace_ids) > 1) {
            throw new InvalidArgumentException('invalid value for "$marketplace_ids" when calling ServiceApi.getAppointmentSlots, number of items must be less than or equal to 1.');
        }

        $resourcePath = '/service/v1/appointmentSlots';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($asin)) {
            $asin = ObjectSerializer::serializeCollection($asin, '', true);
        }

        if ($asin !== null) {
            $queryParams['asin'] = ObjectSerializer::toString($asin);
        }
        // query params
        if (\is_array($store_id)) {
            $store_id = ObjectSerializer::serializeCollection($store_id, '', true);
        }

        if ($store_id !== null) {
            $queryParams['storeId'] = ObjectSerializer::toString($store_id);
        }
        // query params
        if (\is_array($marketplace_ids)) {
            $marketplace_ids = ObjectSerializer::serializeCollection($marketplace_ids, 'form', true);
        }

        if ($marketplace_ids !== null) {
            $queryParams['marketplaceIds'] = ObjectSerializer::toString($marketplace_ids);
        }
        // query params
        if (\is_array($start_time)) {
            $start_time = ObjectSerializer::serializeCollection($start_time, '', true);
        }

        if ($start_time !== null) {
            $queryParams['startTime'] = ObjectSerializer::toString($start_time);
        }
        // query params
        if (\is_array($end_time)) {
            $end_time = ObjectSerializer::serializeCollection($end_time, '', true);
        }

        if ($end_time !== null) {
            $queryParams['endTime'] = ObjectSerializer::toString($end_time);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'GET',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation getAppointmmentSlotsByJobId.
     *
     * @param string $service_job_id A service job identifier to retrive appointment slots for associated service. (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param null|string $start_time A time from which the appointment slots will be retrieved. The specified time must be in ISO 8601 format. If &#x60;startTime&#x60; is provided, &#x60;endTime&#x60; should also be provided. Default value is as per business configuration. (optional)
     * @param null|string $end_time A time up to which the appointment slots will be retrieved. The specified time must be in ISO 8601 format. If &#x60;endTime&#x60; is provided, &#x60;startTime&#x60; should also be provided. Default value is as per business configuration. Maximum range of appointment slots can be 90 days. (optional)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function getAppointmmentSlotsByJobId(AccessToken $accessToken, string $region, string $service_job_id, array $marketplace_ids, ?string $start_time = null, ?string $end_time = null) : \AmazonPHP\SellingPartner\Model\Services\GetAppointmentSlotsResponse
    {
        $request = $this->getAppointmmentSlotsByJobIdRequest($accessToken, $region, $service_job_id, $marketplace_ids, $start_time, $end_time);

        $this->configuration->extensions()->preRequest('Services', 'getAppointmmentSlotsByJobId', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'getAppointmmentSlotsByJobId')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getAppointmmentSlotsByJobId'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'getAppointmmentSlotsByJobId',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'getAppointmmentSlotsByJobId', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'getAppointmmentSlotsByJobId')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getAppointmmentSlotsByJobId'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'getAppointmmentSlotsByJobId',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\GetAppointmentSlotsResponse',
            []
        );
    }

    /**
     * Create request for operation 'getAppointmmentSlotsByJobId'.
     *
     * @param string $service_job_id A service job identifier to retrive appointment slots for associated service. (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param null|string $start_time A time from which the appointment slots will be retrieved. The specified time must be in ISO 8601 format. If &#x60;startTime&#x60; is provided, &#x60;endTime&#x60; should also be provided. Default value is as per business configuration. (optional)
     * @param null|string $end_time A time up to which the appointment slots will be retrieved. The specified time must be in ISO 8601 format. If &#x60;endTime&#x60; is provided, &#x60;startTime&#x60; should also be provided. Default value is as per business configuration. Maximum range of appointment slots can be 90 days. (optional)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function getAppointmmentSlotsByJobIdRequest(AccessToken $accessToken, string $region, string $service_job_id, array $marketplace_ids, ?string $start_time = null, ?string $end_time = null) : RequestInterface
    {
        // verify the required parameter 'service_job_id' is set
        if ($service_job_id === null || (\is_array($service_job_id) && \count($service_job_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $service_job_id when calling getAppointmmentSlotsByJobId'
            );
        }

        if (\strlen($service_job_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.getAppointmmentSlotsByJobId, must be smaller than or equal to 100.');
        }

        if (\strlen($service_job_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.getAppointmmentSlotsByJobId, must be bigger than or equal to 1.');
        }

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

        if (\count($marketplace_ids) > 1) {
            throw new InvalidArgumentException('invalid value for "$marketplace_ids" when calling ServiceApi.getAppointmmentSlotsByJobId, number of items must be less than or equal to 1.');
        }

        $resourcePath = '/service/v1/serviceJobs/{serviceJobId}/appointmentSlots';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($marketplace_ids)) {
            $marketplace_ids = ObjectSerializer::serializeCollection($marketplace_ids, 'form', true);
        }

        if ($marketplace_ids !== null) {
            $queryParams['marketplaceIds'] = ObjectSerializer::toString($marketplace_ids);
        }
        // query params
        if (\is_array($start_time)) {
            $start_time = ObjectSerializer::serializeCollection($start_time, '', true);
        }

        if ($start_time !== null) {
            $queryParams['startTime'] = ObjectSerializer::toString($start_time);
        }
        // query params
        if (\is_array($end_time)) {
            $end_time = ObjectSerializer::serializeCollection($end_time, '', true);
        }

        if ($end_time !== null) {
            $queryParams['endTime'] = ObjectSerializer::toString($end_time);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'GET',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation getFixedSlotCapacity.
     *
     * @param string $resource_id Resource Identifier. (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\FixedSlotCapacityQuery $body Request body. (required)
     * @param null|string $next_page_token Next page token returned in the response of your previous request. (optional)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function getFixedSlotCapacity(AccessToken $accessToken, string $region, string $resource_id, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\FixedSlotCapacityQuery $body, ?string $next_page_token = null) : \AmazonPHP\SellingPartner\Model\Services\FixedSlotCapacity
    {
        $request = $this->getFixedSlotCapacityRequest($accessToken, $region, $resource_id, $marketplace_ids, $body, $next_page_token);

        $this->configuration->extensions()->preRequest('Services', 'getFixedSlotCapacity', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'getFixedSlotCapacity')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getFixedSlotCapacity'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'getFixedSlotCapacity',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'getFixedSlotCapacity', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'getFixedSlotCapacity')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getFixedSlotCapacity'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'getFixedSlotCapacity',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\FixedSlotCapacity',
            []
        );
    }

    /**
     * Create request for operation 'getFixedSlotCapacity'.
     *
     * @param string $resource_id Resource Identifier. (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\FixedSlotCapacityQuery $body Request body. (required)
     * @param null|string $next_page_token Next page token returned in the response of your previous request. (optional)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function getFixedSlotCapacityRequest(AccessToken $accessToken, string $region, string $resource_id, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\FixedSlotCapacityQuery $body, ?string $next_page_token = null) : RequestInterface
    {
        // verify the required parameter 'resource_id' is set
        if ($resource_id === null || (\is_array($resource_id) && \count($resource_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $resource_id when calling getFixedSlotCapacity'
            );
        }

        if (\strlen($resource_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$resource_id" when calling ServiceApi.getFixedSlotCapacity, must be smaller than or equal to 100.');
        }

        if (\strlen($resource_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$resource_id" when calling ServiceApi.getFixedSlotCapacity, must be bigger than or equal to 1.');
        }

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

        if (\count($marketplace_ids) > 1) {
            throw new InvalidArgumentException('invalid value for "$marketplace_ids" when calling ServiceApi.getFixedSlotCapacity, number of items must be less than or equal to 1.');
        }

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

        $resourcePath = '/service/v1/serviceResources/{resourceId}/capacity/fixed';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($marketplace_ids)) {
            $marketplace_ids = ObjectSerializer::serializeCollection($marketplace_ids, 'form', true);
        }

        if ($marketplace_ids !== null) {
            $queryParams['marketplaceIds'] = ObjectSerializer::toString($marketplace_ids);
        }
        // query params
        if (\is_array($next_page_token)) {
            $next_page_token = ObjectSerializer::serializeCollection($next_page_token, '', true);
        }

        if ($next_page_token !== null) {
            $queryParams['nextPageToken'] = ObjectSerializer::toString($next_page_token);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'POST',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation getRangeSlotCapacity.
     *
     * @param string $resource_id Resource Identifier. (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\RangeSlotCapacityQuery $body Request body. (required)
     * @param null|string $next_page_token Next page token returned in the response of your previous request. (optional)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function getRangeSlotCapacity(AccessToken $accessToken, string $region, string $resource_id, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\RangeSlotCapacityQuery $body, ?string $next_page_token = null) : \AmazonPHP\SellingPartner\Model\Services\RangeSlotCapacity
    {
        $request = $this->getRangeSlotCapacityRequest($accessToken, $region, $resource_id, $marketplace_ids, $body, $next_page_token);

        $this->configuration->extensions()->preRequest('Services', 'getRangeSlotCapacity', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'getRangeSlotCapacity')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getRangeSlotCapacity'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'getRangeSlotCapacity',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'getRangeSlotCapacity', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'getRangeSlotCapacity')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getRangeSlotCapacity'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'getRangeSlotCapacity',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\RangeSlotCapacity',
            []
        );
    }

    /**
     * Create request for operation 'getRangeSlotCapacity'.
     *
     * @param string $resource_id Resource Identifier. (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\RangeSlotCapacityQuery $body Request body. (required)
     * @param null|string $next_page_token Next page token returned in the response of your previous request. (optional)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function getRangeSlotCapacityRequest(AccessToken $accessToken, string $region, string $resource_id, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\RangeSlotCapacityQuery $body, ?string $next_page_token = null) : RequestInterface
    {
        // verify the required parameter 'resource_id' is set
        if ($resource_id === null || (\is_array($resource_id) && \count($resource_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $resource_id when calling getRangeSlotCapacity'
            );
        }

        if (\strlen($resource_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$resource_id" when calling ServiceApi.getRangeSlotCapacity, must be smaller than or equal to 100.');
        }

        if (\strlen($resource_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$resource_id" when calling ServiceApi.getRangeSlotCapacity, must be bigger than or equal to 1.');
        }

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

        if (\count($marketplace_ids) > 1) {
            throw new InvalidArgumentException('invalid value for "$marketplace_ids" when calling ServiceApi.getRangeSlotCapacity, number of items must be less than or equal to 1.');
        }

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

        $resourcePath = '/service/v1/serviceResources/{resourceId}/capacity/range';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($marketplace_ids)) {
            $marketplace_ids = ObjectSerializer::serializeCollection($marketplace_ids, 'form', true);
        }

        if ($marketplace_ids !== null) {
            $queryParams['marketplaceIds'] = ObjectSerializer::toString($marketplace_ids);
        }
        // query params
        if (\is_array($next_page_token)) {
            $next_page_token = ObjectSerializer::serializeCollection($next_page_token, '', true);
        }

        if ($next_page_token !== null) {
            $queryParams['nextPageToken'] = ObjectSerializer::toString($next_page_token);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'POST',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation getServiceJobByServiceJobId.
     *
     * @param string $service_job_id A service job identifier. (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function getServiceJobByServiceJobId(AccessToken $accessToken, string $region, string $service_job_id) : \AmazonPHP\SellingPartner\Model\Services\GetServiceJobByServiceJobIdResponse
    {
        $request = $this->getServiceJobByServiceJobIdRequest($accessToken, $region, $service_job_id);

        $this->configuration->extensions()->preRequest('Services', 'getServiceJobByServiceJobId', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'getServiceJobByServiceJobId')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getServiceJobByServiceJobId'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'getServiceJobByServiceJobId',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'getServiceJobByServiceJobId', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'getServiceJobByServiceJobId')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getServiceJobByServiceJobId'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'getServiceJobByServiceJobId',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\GetServiceJobByServiceJobIdResponse',
            []
        );
    }

    /**
     * Create request for operation 'getServiceJobByServiceJobId'.
     *
     * @param string $service_job_id A service job identifier. (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function getServiceJobByServiceJobIdRequest(AccessToken $accessToken, string $region, string $service_job_id) : RequestInterface
    {
        // verify the required parameter 'service_job_id' is set
        if ($service_job_id === null || (\is_array($service_job_id) && \count($service_job_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $service_job_id when calling getServiceJobByServiceJobId'
            );
        }

        if (\strlen($service_job_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.getServiceJobByServiceJobId, must be smaller than or equal to 100.');
        }

        if (\strlen($service_job_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.getServiceJobByServiceJobId, must be bigger than or equal to 1.');
        }

        $resourcePath = '/service/v1/serviceJobs/{serviceJobId}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'GET',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation getServiceJobs.
     *
     * @param string[] $marketplace_ids Used to select jobs that were placed in the specified marketplaces. (required)
     * @param null|string[] $service_order_ids List of service order ids for the query you want to perform.Max values supported 20. (optional)
     * @param null|string[] $service_job_status A list of one or more job status by which to filter the list of jobs. (optional)
     * @param null|string $page_token String returned in the response of your previous request. (optional)
     * @param int $page_size A non-negative integer that indicates the maximum number of jobs to return in the list, Value must be 1 - 20. Default 20. (optional, default to 20)
     * @param null|string $sort_field Sort fields on which you want to sort the output. (optional)
     * @param null|string $sort_order Sort order for the query you want to perform. (optional)
     * @param null|string $created_after A date used for selecting jobs created at or after a specified time. Must be in ISO 8601 format. Required if &#x60;LastUpdatedAfter&#x60; is not specified. Specifying both &#x60;CreatedAfter&#x60; and &#x60;LastUpdatedAfter&#x60; returns an error. (optional)
     * @param null|string $created_before A date used for selecting jobs created at or before a specified time. Must be in ISO 8601 format. (optional)
     * @param null|string $last_updated_after A date used for selecting jobs updated at or after a specified time. Must be in ISO 8601 format. Required if &#x60;createdAfter&#x60; is not specified. Specifying both &#x60;CreatedAfter&#x60; and &#x60;LastUpdatedAfter&#x60; returns an error. (optional)
     * @param null|string $last_updated_before A date used for selecting jobs updated at or before a specified time. Must be in ISO 8601 format. (optional)
     * @param null|string $schedule_start_date A date used for filtering jobs schedules at or after a specified time. Must be in ISO 8601 format. Schedule end date should not be earlier than schedule start date. (optional)
     * @param null|string $schedule_end_date A date used for filtering jobs schedules at or before a specified time. Must be in ISO 8601 format. Schedule end date should not be earlier than schedule start date. (optional)
     * @param null|string[] $asins List of Amazon Standard Identification Numbers (ASIN) of the items. Max values supported is 20. (optional)
     * @param null|string[] $required_skills A defined set of related knowledge, skills, experience, tools, materials, and work processes common to service delivery for a set of products and/or service scenarios. Max values supported is 20. (optional)
     * @param null|string[] $store_ids List of Amazon-defined identifiers for the region scope. Max values supported is 50. (optional)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function getServiceJobs(AccessToken $accessToken, string $region, array $marketplace_ids, ?array $service_order_ids = null, ?array $service_job_status = null, ?string $page_token = null, int $page_size = 20, ?string $sort_field = null, ?string $sort_order = null, ?string $created_after = null, ?string $created_before = null, ?string $last_updated_after = null, ?string $last_updated_before = null, ?string $schedule_start_date = null, ?string $schedule_end_date = null, ?array $asins = null, ?array $required_skills = null, ?array $store_ids = null) : \AmazonPHP\SellingPartner\Model\Services\GetServiceJobsResponse
    {
        $request = $this->getServiceJobsRequest($accessToken, $region, $marketplace_ids, $service_order_ids, $service_job_status, $page_token, $page_size, $sort_field, $sort_order, $created_after, $created_before, $last_updated_after, $last_updated_before, $schedule_start_date, $schedule_end_date, $asins, $required_skills, $store_ids);

        $this->configuration->extensions()->preRequest('Services', 'getServiceJobs', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'getServiceJobs')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getServiceJobs'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'getServiceJobs',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'getServiceJobs', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'getServiceJobs')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'getServiceJobs'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'getServiceJobs',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\GetServiceJobsResponse',
            []
        );
    }

    /**
     * Create request for operation 'getServiceJobs'.
     *
     * @param string[] $marketplace_ids Used to select jobs that were placed in the specified marketplaces. (required)
     * @param null|string[] $service_order_ids List of service order ids for the query you want to perform.Max values supported 20. (optional)
     * @param null|string[] $service_job_status A list of one or more job status by which to filter the list of jobs. (optional)
     * @param null|string $page_token String returned in the response of your previous request. (optional)
     * @param int $page_size A non-negative integer that indicates the maximum number of jobs to return in the list, Value must be 1 - 20. Default 20. (optional, default to 20)
     * @param null|string $sort_field Sort fields on which you want to sort the output. (optional)
     * @param null|string $sort_order Sort order for the query you want to perform. (optional)
     * @param null|string $created_after A date used for selecting jobs created at or after a specified time. Must be in ISO 8601 format. Required if &#x60;LastUpdatedAfter&#x60; is not specified. Specifying both &#x60;CreatedAfter&#x60; and &#x60;LastUpdatedAfter&#x60; returns an error. (optional)
     * @param null|string $created_before A date used for selecting jobs created at or before a specified time. Must be in ISO 8601 format. (optional)
     * @param null|string $last_updated_after A date used for selecting jobs updated at or after a specified time. Must be in ISO 8601 format. Required if &#x60;createdAfter&#x60; is not specified. Specifying both &#x60;CreatedAfter&#x60; and &#x60;LastUpdatedAfter&#x60; returns an error. (optional)
     * @param null|string $last_updated_before A date used for selecting jobs updated at or before a specified time. Must be in ISO 8601 format. (optional)
     * @param null|string $schedule_start_date A date used for filtering jobs schedules at or after a specified time. Must be in ISO 8601 format. Schedule end date should not be earlier than schedule start date. (optional)
     * @param null|string $schedule_end_date A date used for filtering jobs schedules at or before a specified time. Must be in ISO 8601 format. Schedule end date should not be earlier than schedule start date. (optional)
     * @param null|string[] $asins List of Amazon Standard Identification Numbers (ASIN) of the items. Max values supported is 20. (optional)
     * @param null|string[] $required_skills A defined set of related knowledge, skills, experience, tools, materials, and work processes common to service delivery for a set of products and/or service scenarios. Max values supported is 20. (optional)
     * @param null|string[] $store_ids List of Amazon-defined identifiers for the region scope. Max values supported is 50. (optional)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function getServiceJobsRequest(AccessToken $accessToken, string $region, array $marketplace_ids, ?array $service_order_ids = null, ?array $service_job_status = null, ?string $page_token = null, int $page_size = 20, ?string $sort_field = null, ?string $sort_order = null, ?string $created_after = null, ?string $created_before = null, ?string $last_updated_after = null, ?string $last_updated_before = null, ?string $schedule_start_date = null, ?string $schedule_end_date = null, ?array $asins = null, ?array $required_skills = null, ?array $store_ids = null) : RequestInterface
    {
        // verify the required parameter 'marketplace_ids' is set
        if ($marketplace_ids === null || (\is_array($marketplace_ids) && \count($marketplace_ids) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $marketplace_ids when calling getServiceJobs'
            );
        }

        if (\count($marketplace_ids) > 1) {
            throw new InvalidArgumentException('invalid value for "$marketplace_ids" when calling ServiceApi.getServiceJobs, number of items must be less than or equal to 1.');
        }

        if ($service_order_ids !== null && \count($service_order_ids) > 20) {
            throw new InvalidArgumentException('invalid value for "$service_order_ids" when calling ServiceApi.getServiceJobs, number of items must be less than or equal to 20.');
        }

        if ($service_order_ids !== null && \count($service_order_ids) < 1) {
            throw new InvalidArgumentException('invalid value for "$service_order_ids" when calling ServiceApi.getServiceJobs, number of items must be greater than or equal to 1.');
        }

        if ($page_size !== null && $page_size > 20) {
            throw new InvalidArgumentException('invalid value for "$page_size" when calling ServiceApi.getServiceJobs, must be smaller than or equal to 20.');
        }

        if ($page_size !== null && $page_size < 1) {
            throw new InvalidArgumentException('invalid value for "$page_size" when calling ServiceApi.getServiceJobs, must be bigger than or equal to 1.');
        }

        if ($asins !== null && \count($asins) > 20) {
            throw new InvalidArgumentException('invalid value for "$asins" when calling ServiceApi.getServiceJobs, number of items must be less than or equal to 20.');
        }

        if ($asins !== null && \count($asins) < 1) {
            throw new InvalidArgumentException('invalid value for "$asins" when calling ServiceApi.getServiceJobs, number of items must be greater than or equal to 1.');
        }

        if ($required_skills !== null && \count($required_skills) > 20) {
            throw new InvalidArgumentException('invalid value for "$required_skills" when calling ServiceApi.getServiceJobs, number of items must be less than or equal to 20.');
        }

        if ($required_skills !== null && \count($required_skills) < 1) {
            throw new InvalidArgumentException('invalid value for "$required_skills" when calling ServiceApi.getServiceJobs, number of items must be greater than or equal to 1.');
        }

        if ($store_ids !== null && \count($store_ids) > 50) {
            throw new InvalidArgumentException('invalid value for "$store_ids" when calling ServiceApi.getServiceJobs, number of items must be less than or equal to 50.');
        }

        if ($store_ids !== null && \count($store_ids) < 1) {
            throw new InvalidArgumentException('invalid value for "$store_ids" when calling ServiceApi.getServiceJobs, number of items must be greater than or equal to 1.');
        }

        $resourcePath = '/service/v1/serviceJobs';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($service_order_ids)) {
            $service_order_ids = ObjectSerializer::serializeCollection($service_order_ids, 'form', true);
        }

        if ($service_order_ids !== null) {
            $queryParams['serviceOrderIds'] = ObjectSerializer::toString($service_order_ids);
        }
        // query params
        if (\is_array($service_job_status)) {
            $service_job_status = ObjectSerializer::serializeCollection($service_job_status, 'form', true);
        }

        if ($service_job_status !== null) {
            $queryParams['serviceJobStatus'] = ObjectSerializer::toString($service_job_status);
        }
        // query params
        if (\is_array($page_token)) {
            $page_token = ObjectSerializer::serializeCollection($page_token, '', true);
        }

        if ($page_token !== null) {
            $queryParams['pageToken'] = ObjectSerializer::toString($page_token);
        }
        // query params
        if (\is_array($page_size)) {
            $page_size = ObjectSerializer::serializeCollection($page_size, '', true);
        }

        if ($page_size !== null) {
            $queryParams['pageSize'] = ObjectSerializer::toString($page_size);
        }
        // query params
        if (\is_array($sort_field)) {
            $sort_field = ObjectSerializer::serializeCollection($sort_field, '', true);
        }

        if ($sort_field !== null) {
            $queryParams['sortField'] = ObjectSerializer::toString($sort_field);
        }
        // query params
        if (\is_array($sort_order)) {
            $sort_order = ObjectSerializer::serializeCollection($sort_order, '', true);
        }

        if ($sort_order !== null) {
            $queryParams['sortOrder'] = ObjectSerializer::toString($sort_order);
        }
        // query params
        if (\is_array($created_after)) {
            $created_after = ObjectSerializer::serializeCollection($created_after, '', true);
        }

        if ($created_after !== null) {
            $queryParams['createdAfter'] = ObjectSerializer::toString($created_after);
        }
        // query params
        if (\is_array($created_before)) {
            $created_before = ObjectSerializer::serializeCollection($created_before, '', true);
        }

        if ($created_before !== null) {
            $queryParams['createdBefore'] = ObjectSerializer::toString($created_before);
        }
        // query params
        if (\is_array($last_updated_after)) {
            $last_updated_after = ObjectSerializer::serializeCollection($last_updated_after, '', true);
        }

        if ($last_updated_after !== null) {
            $queryParams['lastUpdatedAfter'] = ObjectSerializer::toString($last_updated_after);
        }
        // query params
        if (\is_array($last_updated_before)) {
            $last_updated_before = ObjectSerializer::serializeCollection($last_updated_before, '', true);
        }

        if ($last_updated_before !== null) {
            $queryParams['lastUpdatedBefore'] = ObjectSerializer::toString($last_updated_before);
        }
        // query params
        if (\is_array($schedule_start_date)) {
            $schedule_start_date = ObjectSerializer::serializeCollection($schedule_start_date, '', true);
        }

        if ($schedule_start_date !== null) {
            $queryParams['scheduleStartDate'] = ObjectSerializer::toString($schedule_start_date);
        }
        // query params
        if (\is_array($schedule_end_date)) {
            $schedule_end_date = ObjectSerializer::serializeCollection($schedule_end_date, '', true);
        }

        if ($schedule_end_date !== null) {
            $queryParams['scheduleEndDate'] = ObjectSerializer::toString($schedule_end_date);
        }
        // query params
        if (\is_array($marketplace_ids)) {
            $marketplace_ids = ObjectSerializer::serializeCollection($marketplace_ids, 'form', true);
        }

        if ($marketplace_ids !== null) {
            $queryParams['marketplaceIds'] = ObjectSerializer::toString($marketplace_ids);
        }
        // query params
        if (\is_array($asins)) {
            $asins = ObjectSerializer::serializeCollection($asins, 'form', true);
        }

        if ($asins !== null) {
            $queryParams['asins'] = ObjectSerializer::toString($asins);
        }
        // query params
        if (\is_array($required_skills)) {
            $required_skills = ObjectSerializer::serializeCollection($required_skills, 'form', true);
        }

        if ($required_skills !== null) {
            $queryParams['requiredSkills'] = ObjectSerializer::toString($required_skills);
        }
        // query params
        if (\is_array($store_ids)) {
            $store_ids = ObjectSerializer::serializeCollection($store_ids, 'form', true);
        }

        if ($store_ids !== null) {
            $queryParams['storeIds'] = ObjectSerializer::toString($store_ids);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'GET',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation rescheduleAppointmentForServiceJobByServiceJobId.
     *
     * @param string $service_job_id An Amazon defined service job identifier. (required)
     * @param string $appointment_id An existing appointment identifier for the Service Job. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\RescheduleAppointmentRequest $body Reschedule appointment operation input details. (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function rescheduleAppointmentForServiceJobByServiceJobId(AccessToken $accessToken, string $region, string $service_job_id, string $appointment_id, \AmazonPHP\SellingPartner\Model\Services\RescheduleAppointmentRequest $body) : \AmazonPHP\SellingPartner\Model\Services\SetAppointmentResponse
    {
        $request = $this->rescheduleAppointmentForServiceJobByServiceJobIdRequest($accessToken, $region, $service_job_id, $appointment_id, $body);

        $this->configuration->extensions()->preRequest('Services', 'rescheduleAppointmentForServiceJobByServiceJobId', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'rescheduleAppointmentForServiceJobByServiceJobId')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'rescheduleAppointmentForServiceJobByServiceJobId'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'rescheduleAppointmentForServiceJobByServiceJobId',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'rescheduleAppointmentForServiceJobByServiceJobId', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'rescheduleAppointmentForServiceJobByServiceJobId')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'rescheduleAppointmentForServiceJobByServiceJobId'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'rescheduleAppointmentForServiceJobByServiceJobId',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\SetAppointmentResponse',
            []
        );
    }

    /**
     * Create request for operation 'rescheduleAppointmentForServiceJobByServiceJobId'.
     *
     * @param string $service_job_id An Amazon defined service job identifier. (required)
     * @param string $appointment_id An existing appointment identifier for the Service Job. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\RescheduleAppointmentRequest $body Reschedule appointment operation input details. (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function rescheduleAppointmentForServiceJobByServiceJobIdRequest(AccessToken $accessToken, string $region, string $service_job_id, string $appointment_id, \AmazonPHP\SellingPartner\Model\Services\RescheduleAppointmentRequest $body) : RequestInterface
    {
        // verify the required parameter 'service_job_id' is set
        if ($service_job_id === null || (\is_array($service_job_id) && \count($service_job_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $service_job_id when calling rescheduleAppointmentForServiceJobByServiceJobId'
            );
        }

        if (\strlen($service_job_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.rescheduleAppointmentForServiceJobByServiceJobId, must be smaller than or equal to 100.');
        }

        if (\strlen($service_job_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.rescheduleAppointmentForServiceJobByServiceJobId, must be bigger than or equal to 1.');
        }

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

        if (\strlen($appointment_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$appointment_id" when calling ServiceApi.rescheduleAppointmentForServiceJobByServiceJobId, must be smaller than or equal to 100.');
        }

        if (\strlen($appointment_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$appointment_id" when calling ServiceApi.rescheduleAppointmentForServiceJobByServiceJobId, must be bigger than or equal to 1.');
        }

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

        $resourcePath = '/service/v1/serviceJobs/{serviceJobId}/appointments/{appointmentId}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

        // path params
        if ($service_job_id !== null) {
            $resourcePath = \str_replace(
                '{' . 'serviceJobId' . '}',
                ObjectSerializer::toPathValue($service_job_id),
                $resourcePath
            );
        }
        // path params
        if ($appointment_id !== null) {
            $resourcePath = \str_replace(
                '{' . 'appointmentId' . '}',
                ObjectSerializer::toPathValue($appointment_id),
                $resourcePath
            );
        }

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'POST',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation setAppointmentFulfillmentData.
     *
     * @param string $service_job_id An Amazon-defined service job identifier. Get this value by calling the &#x60;getServiceJobs&#x60; operation of the Services API. (required)
     * @param string $appointment_id An Amazon-defined identifier of active service job appointment. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\SetAppointmentFulfillmentDataRequest $body Appointment fulfillment data collection details. (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function setAppointmentFulfillmentData(AccessToken $accessToken, string $region, string $service_job_id, string $appointment_id, \AmazonPHP\SellingPartner\Model\Services\SetAppointmentFulfillmentDataRequest $body) : string
    {
        $request = $this->setAppointmentFulfillmentDataRequest($accessToken, $region, $service_job_id, $appointment_id, $body);

        $this->configuration->extensions()->preRequest('Services', 'setAppointmentFulfillmentData', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'setAppointmentFulfillmentData')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'setAppointmentFulfillmentData'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'setAppointmentFulfillmentData',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'setAppointmentFulfillmentData', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'setAppointmentFulfillmentData')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'setAppointmentFulfillmentData'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'setAppointmentFulfillmentData',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            'string',
            []
        );
    }

    /**
     * Create request for operation 'setAppointmentFulfillmentData'.
     *
     * @param string $service_job_id An Amazon-defined service job identifier. Get this value by calling the &#x60;getServiceJobs&#x60; operation of the Services API. (required)
     * @param string $appointment_id An Amazon-defined identifier of active service job appointment. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\SetAppointmentFulfillmentDataRequest $body Appointment fulfillment data collection details. (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function setAppointmentFulfillmentDataRequest(AccessToken $accessToken, string $region, string $service_job_id, string $appointment_id, \AmazonPHP\SellingPartner\Model\Services\SetAppointmentFulfillmentDataRequest $body) : RequestInterface
    {
        // verify the required parameter 'service_job_id' is set
        if ($service_job_id === null || (\is_array($service_job_id) && \count($service_job_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $service_job_id when calling setAppointmentFulfillmentData'
            );
        }

        if (\strlen($service_job_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.setAppointmentFulfillmentData, must be smaller than or equal to 100.');
        }

        if (\strlen($service_job_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$service_job_id" when calling ServiceApi.setAppointmentFulfillmentData, must be bigger than or equal to 1.');
        }

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

        if (\strlen($appointment_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$appointment_id" when calling ServiceApi.setAppointmentFulfillmentData, must be smaller than or equal to 100.');
        }

        if (\strlen($appointment_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$appointment_id" when calling ServiceApi.setAppointmentFulfillmentData, must be bigger than or equal to 1.');
        }

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

        $resourcePath = '/service/v1/serviceJobs/{serviceJobId}/appointments/{appointmentId}/fulfillment';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

        // path params
        if ($service_job_id !== null) {
            $resourcePath = \str_replace(
                '{' . 'serviceJobId' . '}',
                ObjectSerializer::toPathValue($service_job_id),
                $resourcePath
            );
        }
        // path params
        if ($appointment_id !== null) {
            $resourcePath = \str_replace(
                '{' . 'appointmentId' . '}',
                ObjectSerializer::toPathValue($appointment_id),
                $resourcePath
            );
        }

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'PUT',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation updateReservation.
     *
     * @param string $reservation_id Reservation Identifier (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\UpdateReservationRequest $body Reservation details (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function updateReservation(AccessToken $accessToken, string $region, string $reservation_id, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\UpdateReservationRequest $body) : \AmazonPHP\SellingPartner\Model\Services\UpdateReservationResponse
    {
        $request = $this->updateReservationRequest($accessToken, $region, $reservation_id, $marketplace_ids, $body);

        $this->configuration->extensions()->preRequest('Services', 'updateReservation', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'updateReservation')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'updateReservation'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'updateReservation',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'updateReservation', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'updateReservation')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'updateReservation'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'updateReservation',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\UpdateReservationResponse',
            []
        );
    }

    /**
     * Create request for operation 'updateReservation'.
     *
     * @param string $reservation_id Reservation Identifier (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\UpdateReservationRequest $body Reservation details (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function updateReservationRequest(AccessToken $accessToken, string $region, string $reservation_id, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\UpdateReservationRequest $body) : RequestInterface
    {
        // verify the required parameter 'reservation_id' is set
        if ($reservation_id === null || (\is_array($reservation_id) && \count($reservation_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $reservation_id when calling updateReservation'
            );
        }

        if (\strlen($reservation_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$reservation_id" when calling ServiceApi.updateReservation, must be smaller than or equal to 100.');
        }

        if (\strlen($reservation_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$reservation_id" when calling ServiceApi.updateReservation, must be bigger than or equal to 1.');
        }

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

        if (\count($marketplace_ids) > 1) {
            throw new InvalidArgumentException('invalid value for "$marketplace_ids" when calling ServiceApi.updateReservation, number of items must be less than or equal to 1.');
        }

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

        $resourcePath = '/service/v1/reservation/{reservationId}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($marketplace_ids)) {
            $marketplace_ids = ObjectSerializer::serializeCollection($marketplace_ids, 'form', true);
        }

        if ($marketplace_ids !== null) {
            $queryParams['marketplaceIds'] = ObjectSerializer::toString($marketplace_ids);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'PUT',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }

    /**
     * Operation updateSchedule.
     *
     * @param string $resource_id Resource (store) Identifier (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\UpdateScheduleRequest $body Schedule details (required)
     *
     * @throws ApiException on non-2xx response
     * @throws InvalidArgumentException
     */
    public function updateSchedule(AccessToken $accessToken, string $region, string $resource_id, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\UpdateScheduleRequest $body) : \AmazonPHP\SellingPartner\Model\Services\UpdateScheduleResponse
    {
        $request = $this->updateScheduleRequest($accessToken, $region, $resource_id, $marketplace_ids, $body);

        $this->configuration->extensions()->preRequest('Services', 'updateSchedule', $request);

        try {
            $correlationId = $this->configuration->idGenerator()->generate();

            if ($this->configuration->loggingEnabled('Services', 'updateSchedule')) {
                $sanitizedRequest = $request;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedRequest = $sanitizedRequest->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'updateSchedule'),
                    'Amazon Selling Partner API pre request',
                    [
                        'api' => 'Services',
                        'operation' => 'updateSchedule',
                        'request_correlation_id' => $correlationId,
                        'request_body' => (string) $sanitizedRequest->getBody(),
                        'request_headers' => $sanitizedRequest->getHeaders(),
                        'request_uri' => (string) $sanitizedRequest->getUri(),
                    ]
                );
            }

            $response = $this->client->sendRequest($request);

            $this->configuration->extensions()->postRequest('Services', 'updateSchedule', $request, $response);

            if ($this->configuration->loggingEnabled('Services', 'updateSchedule')) {
                $sanitizedResponse = $response;

                foreach ($this->configuration->loggingSkipHeaders() as $sensitiveHeader) {
                    $sanitizedResponse = $sanitizedResponse->withoutHeader($sensitiveHeader);
                }

                $this->logger->log(
                    $this->configuration->logLevel('Services', 'updateSchedule'),
                    'Amazon Selling Partner API post request',
                    [
                        'api' => 'Services',
                        'operation' => 'updateSchedule',
                        'response_correlation_id' => $correlationId,
                        'response_body' => (string) $sanitizedResponse->getBody(),
                        'response_headers' => $sanitizedResponse->getHeaders(),
                        'response_status_code' => $sanitizedResponse->getStatusCode(),
                    ]
                );
            }
        } catch (ClientExceptionInterface $e) {
            throw new ApiException(
                "[{$e->getCode()}] {$e->getMessage()}",
                (int) $e->getCode(),
                null,
                null,
                $e
            );
        }

        $statusCode = $response->getStatusCode();

        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 ObjectSerializer::deserialize(
            $this->configuration,
            (string) $response->getBody(),
            '\AmazonPHP\SellingPartner\Model\Services\UpdateScheduleResponse',
            []
        );
    }

    /**
     * Create request for operation 'updateSchedule'.
     *
     * @param string $resource_id Resource (store) Identifier (required)
     * @param string[] $marketplace_ids An identifier for the marketplace in which the resource operates. (required)
     * @param \AmazonPHP\SellingPartner\Model\Services\UpdateScheduleRequest $body Schedule details (required)
     *
     * @throws \AmazonPHP\SellingPartner\Exception\InvalidArgumentException
     */
    public function updateScheduleRequest(AccessToken $accessToken, string $region, string $resource_id, array $marketplace_ids, \AmazonPHP\SellingPartner\Model\Services\UpdateScheduleRequest $body) : RequestInterface
    {
        // verify the required parameter 'resource_id' is set
        if ($resource_id === null || (\is_array($resource_id) && \count($resource_id) === 0)) {
            throw new InvalidArgumentException(
                'Missing the required parameter $resource_id when calling updateSchedule'
            );
        }

        if (\strlen($resource_id) > 100) {
            throw new InvalidArgumentException('invalid length for "$resource_id" when calling ServiceApi.updateSchedule, must be smaller than or equal to 100.');
        }

        if (\strlen($resource_id) < 1) {
            throw new InvalidArgumentException('invalid length for "$resource_id" when calling ServiceApi.updateSchedule, must be bigger than or equal to 1.');
        }

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

        if (\count($marketplace_ids) > 1) {
            throw new InvalidArgumentException('invalid value for "$marketplace_ids" when calling ServiceApi.updateSchedule, number of items must be less than or equal to 1.');
        }

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

        $resourcePath = '/service/v1/serviceResources/{resourceId}/schedules';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $multipart = false;
        $query = '';

        // query params
        if (\is_array($marketplace_ids)) {
            $marketplace_ids = ObjectSerializer::serializeCollection($marketplace_ids, 'form', true);
        }

        if ($marketplace_ids !== null) {
            $queryParams['marketplaceIds'] = ObjectSerializer::toString($marketplace_ids);
        }

        if (\count($queryParams)) {
            $query = \http_build_query($queryParams);
        }

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

        if ($multipart) {
            $headers = [
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        } else {
            $headers = [
                'content-type' => ['application/json'],
                'accept' => ['application/json'],
                'host' => [$this->configuration->apiHost($region)],
                'user-agent' => [$this->configuration->userAgent()],
            ];
        }

        $request = $this->httpFactory->createRequest(
            'PUT',
            $this->configuration->apiURL($region) . $resourcePath . '?' . $query
        );

        // for model (json/xml)
        if (isset($body)) {
            if ($headers['content-type'] === ['application/json']) {
                $httpBody = \json_encode(ObjectSerializer::sanitizeForSerialization($body), JSON_THROW_ON_ERROR);
            } else {
                $httpBody = $body;
            }

            $request = $request->withBody($this->httpFactory->createStreamFromString($httpBody));
        } 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,
                        ];
                    }
                }
                $request = $request->withParsedBody($multipartContents);
            } elseif ($headers['content-type'] === ['application/json']) {
                $request = $request->withBody($this->httpFactory->createStreamFromString(\json_encode($formParams, JSON_THROW_ON_ERROR)));
            } else {
                $request = $request->withParsedBody($formParams);
            }
        }

        foreach (\array_merge($headerParams, $headers) as $name => $header) {
            $request = $request->withHeader($name, $header);
        }

        return HttpSignatureHeaders::forConfig(
            $this->configuration,
            $accessToken,
            $region,
            $request
        );
    }
}
