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

/**
 * Tax Classes
 *
 * Manage tax calculations applied to sales. Tax classes are used to apply different tax rates for specific types of products and orders. This API is read only. Classes must be set using the [Control Panel](https://forum.bigcommerce.com/s/article/Taxes-Video#).
 *
 * The version of the OpenAPI document: 
 * Generated by: https://openapi-generator.tech
 * Generator version: 7.13.0
 */

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

namespace Bigcommerce\TaxClassesV2\Api;

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

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

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

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

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

    /** @var string[] $contentTypes **/
    public const contentTypes = [
        'getATaxClass' => [
            'application/json',
        ],
        'getAllTaxClasses' => [
            'application/json',
        ],
    ];

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

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

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

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

    /**
     * Operation getATaxClass
     *
     * Get a Tax Class
     *
     * @param  int $id Id of the tax class. (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getATaxClass'] to see the possible values for this operation
     *
     * @throws \Bigcommerce\TaxClassesV2\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \Bigcommerce\TaxClassesV2\Model\TaxClassFull
     */
    public function getATaxClass($id, string $contentType = self::contentTypes['getATaxClass'][0])
    {
        list($response) = $this->getATaxClassWithHttpInfo($id, $contentType);
        return $response;
    }

    /**
     * Operation getATaxClassWithHttpInfo
     *
     * Get a Tax Class
     *
     * @param  int $id Id of the tax class. (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getATaxClass'] to see the possible values for this operation
     *
     * @throws \Bigcommerce\TaxClassesV2\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \Bigcommerce\TaxClassesV2\Model\TaxClassFull, HTTP status code, HTTP response headers (array of strings)
     */
    public function getATaxClassWithHttpInfo($id, string $contentType = self::contentTypes['getATaxClass'][0])
    {
        $request = $this->getATaxClassRequest($id, $contentType);

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

            $statusCode = $response->getStatusCode();


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

            

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

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

            throw $e;
        }
    }

    /**
     * Operation getATaxClassAsync
     *
     * Get a Tax Class
     *
     * @param  int $id Id of the tax class. (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getATaxClass'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getATaxClassAsync($id, string $contentType = self::contentTypes['getATaxClass'][0])
    {
        return $this->getATaxClassAsyncWithHttpInfo($id, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation getATaxClassAsyncWithHttpInfo
     *
     * Get a Tax Class
     *
     * @param  int $id Id of the tax class. (required)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getATaxClass'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getATaxClassAsyncWithHttpInfo($id, string $contentType = self::contentTypes['getATaxClass'][0])
    {
        $returnType = '\Bigcommerce\TaxClassesV2\Model\TaxClassFull';
        $request = $this->getATaxClassRequest($id, $contentType);

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

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

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

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


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



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


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

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

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

        // this endpoint requires API key authentication
        $apiKey = $this->config->getApiKeyWithPrefix('X-Auth-Token');
        if ($apiKey !== null) {
            $headers['X-Auth-Token'] = $apiKey;
        }

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

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

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

    /**
     * Operation getAllTaxClasses
     *
     * Get All Tax Classes
     *
     * @param  float|null $page Optional filter param. Number of pages. (optional)
     * @param  float|null $limit Optional filter param. Number of items per page (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getAllTaxClasses'] to see the possible values for this operation
     *
     * @throws \Bigcommerce\TaxClassesV2\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \Bigcommerce\TaxClassesV2\Model\TaxClassFull[]
     */
    public function getAllTaxClasses($page = null, $limit = null, string $contentType = self::contentTypes['getAllTaxClasses'][0])
    {
        list($response) = $this->getAllTaxClassesWithHttpInfo($page, $limit, $contentType);
        return $response;
    }

    /**
     * Operation getAllTaxClassesWithHttpInfo
     *
     * Get All Tax Classes
     *
     * @param  float|null $page Optional filter param. Number of pages. (optional)
     * @param  float|null $limit Optional filter param. Number of items per page (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getAllTaxClasses'] to see the possible values for this operation
     *
     * @throws \Bigcommerce\TaxClassesV2\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \Bigcommerce\TaxClassesV2\Model\TaxClassFull[], HTTP status code, HTTP response headers (array of strings)
     */
    public function getAllTaxClassesWithHttpInfo($page = null, $limit = null, string $contentType = self::contentTypes['getAllTaxClasses'][0])
    {
        $request = $this->getAllTaxClassesRequest($page, $limit, $contentType);

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

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 200:
                    return $this->handleResponseWithDataType(
                        '\Bigcommerce\TaxClassesV2\Model\TaxClassFull[]',
                        $request,
                        $response,
                    );
            }

            

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

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

            throw $e;
        }
    }

    /**
     * Operation getAllTaxClassesAsync
     *
     * Get All Tax Classes
     *
     * @param  float|null $page Optional filter param. Number of pages. (optional)
     * @param  float|null $limit Optional filter param. Number of items per page (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getAllTaxClasses'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getAllTaxClassesAsync($page = null, $limit = null, string $contentType = self::contentTypes['getAllTaxClasses'][0])
    {
        return $this->getAllTaxClassesAsyncWithHttpInfo($page, $limit, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation getAllTaxClassesAsyncWithHttpInfo
     *
     * Get All Tax Classes
     *
     * @param  float|null $page Optional filter param. Number of pages. (optional)
     * @param  float|null $limit Optional filter param. Number of items per page (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getAllTaxClasses'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getAllTaxClassesAsyncWithHttpInfo($page = null, $limit = null, string $contentType = self::contentTypes['getAllTaxClasses'][0])
    {
        $returnType = '\Bigcommerce\TaxClassesV2\Model\TaxClassFull[]';
        $request = $this->getAllTaxClassesRequest($page, $limit, $contentType);

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

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

    /**
     * Create request for operation 'getAllTaxClasses'
     *
     * @param  float|null $page Optional filter param. Number of pages. (optional)
     * @param  float|null $limit Optional filter param. Number of items per page (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getAllTaxClasses'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function getAllTaxClassesRequest($page = null, $limit = null, string $contentType = self::contentTypes['getAllTaxClasses'][0])
    {

        if ($page !== null && $page > 50) {
            throw new \InvalidArgumentException('invalid value for "$page" when calling TaxesApi.getAllTaxClasses, must be smaller than or equal to 50.');
        }
        
        if ($limit !== null && $limit > 250) {
            throw new \InvalidArgumentException('invalid value for "$limit" when calling TaxesApi.getAllTaxClasses, must be smaller than or equal to 250.');
        }
        

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

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $page,
            'page', // param base name
            'number', // openApiType
            '', // style
            false, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $limit,
            'limit', // param base name
            'number', // openApiType
            '', // style
            false, // explode
            false // required
        ) ?? []);




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

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

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

        // this endpoint requires API key authentication
        $apiKey = $this->config->getApiKeyWithPrefix('X-Auth-Token');
        if ($apiKey !== null) {
            $headers['X-Auth-Token'] = $apiKey;
        }

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

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

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

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

        return $options;
    }

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

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

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

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