"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""

from .basesdk import BaseSDK
from ship24 import errors, models, utils
from ship24._hooks import HookContext
from ship24.types import BaseModel, OptionalNullable, UNSET
from ship24.utils import get_security_from_env
from typing import Any, Mapping, Optional, Union, cast


class APIForPerCallPlans(BaseSDK):
    r"""The **Tracking API (Per-call Plans)** is a specific product and associated endpoint on which usage is measured per API Call made. Each API call is synchronously fetching data from couriers which make it slower and more depend on courier's system availability.

    Our standard \"Per-shipment\" product & plans remain the best choice as it offers more features, allow faster tracking information fetching with less dependency on courier's system availability at a lower cost overall.

    > ⚠ You need an active \"Per-call\" subscription to use this endpoint.
    """

    def get_tracking(
        self,
        *,
        request: Optional[
            Union[models.GetTrackingRequest, models.GetTrackingRequestTypedDict]
        ] = None,
        retries: OptionalNullable[utils.RetryConfig] = UNSET,
        server_url: Optional[str] = None,
        timeout_ms: Optional[int] = None,
        http_headers: Optional[Mapping[str, str]] = None,
    ) -> models.GetTrackingResponse:
        r"""Get tracking results by tracking number

        This endpoint will return the `tracking` corresponding to the tracking number provided as a parameter.

        The `tracking` object is detailed in the [SCHEMAS](/schemas/tracking) section.

        For better accuracy, we strongly advise to provide extra information such as the origin country, destination postcode & country, and the shipping date.

        > 🛑 You need an active \"Per-call\" subscription to use this endpoint. Our standard \"Per-shipment\" product & plans remain the best choice as it offers more features, allow faster tracking information fetching with less dependency on courier's system availability at a lower cost overall.


        > 🛑 As this endpoint is synchronously fetching tracking results from couriers, **response time may be up to 1 minute, and results depend on the courier's system availability** at the time of the call.

        :param request: The request object to send.
        :param retries: Override the default retry configuration for this method
        :param server_url: Override the default server URL for this method
        :param timeout_ms: Override the default request timeout configuration for this method in milliseconds
        :param http_headers: Additional headers to set or replace on requests.
        """
        base_url = None
        url_variables = None
        if timeout_ms is None:
            timeout_ms = self.sdk_configuration.timeout_ms

        if server_url is not None:
            base_url = server_url
        else:
            base_url = self._get_url(base_url, url_variables)

        if not isinstance(request, BaseModel):
            request = utils.unmarshal(request, Optional[models.GetTrackingRequest])
        request = cast(Optional[models.GetTrackingRequest], request)

        req = self._build_request(
            method="POST",
            path="/public/v1/tracking/search",
            base_url=base_url,
            url_variables=url_variables,
            request=request,
            request_body_required=False,
            request_has_path_params=False,
            request_has_query_params=True,
            user_agent_header="user-agent",
            accept_header_value="application/json",
            http_headers=http_headers,
            security=self.sdk_configuration.security,
            get_serialized_body=lambda: utils.serialize_request_body(
                request, False, True, "json", Optional[models.GetTrackingRequest]
            ),
            timeout_ms=timeout_ms,
        )

        if retries == UNSET:
            if self.sdk_configuration.retry_config is not UNSET:
                retries = self.sdk_configuration.retry_config

        retry_config = None
        if isinstance(retries, utils.RetryConfig):
            retry_config = (retries, ["429", "500", "502", "503", "504"])

        http_res = self.do_request(
            hook_ctx=HookContext(
                config=self.sdk_configuration,
                base_url=base_url or "",
                operation_id="get-tracking",
                oauth2_scopes=[],
                security_source=get_security_from_env(
                    self.sdk_configuration.security, models.Security
                ),
            ),
            request=req,
            error_status_codes=["400", "401", "403", "429", "4XX", "5XX"],
            retry_config=retry_config,
        )

        response_data: Any = None
        if utils.match_response(http_res, "201", "application/json"):
            return models.GetTrackingResponse(
                result=utils.unmarshal_json_response(
                    models.GetTrackingResponseBody, http_res
                ),
                headers={},
            )
        if utils.match_response(http_res, ["400", "401", "403"], "application/json"):
            response_data = utils.unmarshal_json_response(
                errors.ErrorResponseFormatData, http_res
            )
            raise errors.ErrorResponseFormat(response_data, http_res)
        if utils.match_response(http_res, "429", "*"):
            http_res_text = utils.stream_to_text(http_res)
            raise errors.APIError("API error occurred", http_res, http_res_text)
        if utils.match_response(http_res, "4XX", "*"):
            http_res_text = utils.stream_to_text(http_res)
            raise errors.APIError("API error occurred", http_res, http_res_text)
        if utils.match_response(http_res, "5XX", "*"):
            http_res_text = utils.stream_to_text(http_res)
            raise errors.APIError("API error occurred", http_res, http_res_text)

        raise errors.APIError("Unexpected response received", http_res)

    async def get_tracking_async(
        self,
        *,
        request: Optional[
            Union[models.GetTrackingRequest, models.GetTrackingRequestTypedDict]
        ] = None,
        retries: OptionalNullable[utils.RetryConfig] = UNSET,
        server_url: Optional[str] = None,
        timeout_ms: Optional[int] = None,
        http_headers: Optional[Mapping[str, str]] = None,
    ) -> models.GetTrackingResponse:
        r"""Get tracking results by tracking number

        This endpoint will return the `tracking` corresponding to the tracking number provided as a parameter.

        The `tracking` object is detailed in the [SCHEMAS](/schemas/tracking) section.

        For better accuracy, we strongly advise to provide extra information such as the origin country, destination postcode & country, and the shipping date.

        > 🛑 You need an active \"Per-call\" subscription to use this endpoint. Our standard \"Per-shipment\" product & plans remain the best choice as it offers more features, allow faster tracking information fetching with less dependency on courier's system availability at a lower cost overall.


        > 🛑 As this endpoint is synchronously fetching tracking results from couriers, **response time may be up to 1 minute, and results depend on the courier's system availability** at the time of the call.

        :param request: The request object to send.
        :param retries: Override the default retry configuration for this method
        :param server_url: Override the default server URL for this method
        :param timeout_ms: Override the default request timeout configuration for this method in milliseconds
        :param http_headers: Additional headers to set or replace on requests.
        """
        base_url = None
        url_variables = None
        if timeout_ms is None:
            timeout_ms = self.sdk_configuration.timeout_ms

        if server_url is not None:
            base_url = server_url
        else:
            base_url = self._get_url(base_url, url_variables)

        if not isinstance(request, BaseModel):
            request = utils.unmarshal(request, Optional[models.GetTrackingRequest])
        request = cast(Optional[models.GetTrackingRequest], request)

        req = self._build_request_async(
            method="POST",
            path="/public/v1/tracking/search",
            base_url=base_url,
            url_variables=url_variables,
            request=request,
            request_body_required=False,
            request_has_path_params=False,
            request_has_query_params=True,
            user_agent_header="user-agent",
            accept_header_value="application/json",
            http_headers=http_headers,
            security=self.sdk_configuration.security,
            get_serialized_body=lambda: utils.serialize_request_body(
                request, False, True, "json", Optional[models.GetTrackingRequest]
            ),
            timeout_ms=timeout_ms,
        )

        if retries == UNSET:
            if self.sdk_configuration.retry_config is not UNSET:
                retries = self.sdk_configuration.retry_config

        retry_config = None
        if isinstance(retries, utils.RetryConfig):
            retry_config = (retries, ["429", "500", "502", "503", "504"])

        http_res = await self.do_request_async(
            hook_ctx=HookContext(
                config=self.sdk_configuration,
                base_url=base_url or "",
                operation_id="get-tracking",
                oauth2_scopes=[],
                security_source=get_security_from_env(
                    self.sdk_configuration.security, models.Security
                ),
            ),
            request=req,
            error_status_codes=["400", "401", "403", "429", "4XX", "5XX"],
            retry_config=retry_config,
        )

        response_data: Any = None
        if utils.match_response(http_res, "201", "application/json"):
            return models.GetTrackingResponse(
                result=utils.unmarshal_json_response(
                    models.GetTrackingResponseBody, http_res
                ),
                headers={},
            )
        if utils.match_response(http_res, ["400", "401", "403"], "application/json"):
            response_data = utils.unmarshal_json_response(
                errors.ErrorResponseFormatData, http_res
            )
            raise errors.ErrorResponseFormat(response_data, http_res)
        if utils.match_response(http_res, "429", "*"):
            http_res_text = await utils.stream_to_text_async(http_res)
            raise errors.APIError("API error occurred", http_res, http_res_text)
        if utils.match_response(http_res, "4XX", "*"):
            http_res_text = await utils.stream_to_text_async(http_res)
            raise errors.APIError("API error occurred", http_res, http_res_text)
        if utils.match_response(http_res, "5XX", "*"):
            http_res_text = await utils.stream_to_text_async(http_res)
            raise errors.APIError("API error occurred", http_res, http_res_text)

        raise errors.APIError("Unexpected response received", http_res)
