# This file was auto-generated by Fern from our API Definition.

import typing
from json.decoder import JSONDecodeError

from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
from ..core.jsonable_encoder import jsonable_encoder
from ..core.pagination import AsyncPager, BaseHttpResponse, SyncPager
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..core.serialization import convert_and_respect_annotation_metadata
from ..errors.bad_request_error import BadRequestError
from ..errors.forbidden_error import ForbiddenError
from ..errors.internal_server_error import InternalServerError
from ..errors.not_found_error import NotFoundError
from ..types.chunk_info import ChunkInfo
from ..types.completed_chunk import CompletedChunk
from ..types.create_asset_upload_response import CreateAssetUploadResponse
from ..types.get_upload_status_response import GetUploadStatusResponse
from ..types.incomplete_upload_summary import IncompleteUploadSummary
from ..types.list_incomplete_uploads_response import ListIncompleteUploadsResponse
from ..types.report_chunk_batch_response import ReportChunkBatchResponse
from ..types.request_additional_presigned_ur_ls_response import RequestAdditionalPresignedUrLsResponse
from .types.create_asset_upload_request_type import CreateAssetUploadRequestType

# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)


class RawMultipartUploadClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    def list_incomplete_uploads(
        self,
        *,
        page: typing.Optional[int] = None,
        page_limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SyncPager[IncompleteUploadSummary]:
        """
        This method returns a list of all incomplete multipart upload sessions in your account.

        Parameters
        ----------
        page : typing.Optional[int]
            A number that identifies the page to retrieve.

            **Default**: `1`.

        page_limit : typing.Optional[int]
            The number of items to return on each page.

            **Default**: `10`.
            **Max**: `50`.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        SyncPager[IncompleteUploadSummary]
            The list of incomplete upload sessions has been successfully retrieved.
        """
        page = page if page is not None else 1

        _response = self._client_wrapper.httpx_client.request(
            "assets/multipart-uploads",
            method="GET",
            params={
                "page": page,
                "page_limit": page_limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListIncompleteUploadsResponse,
                    parse_obj_as(
                        type_=ListIncompleteUploadsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.data
                _has_next = True
                _get_next = lambda: self.list_incomplete_uploads(
                    page=page + 1,
                    page_limit=page_limit,
                    request_options=request_options,
                )
                return SyncPager(
                    has_next=_has_next, items=_items, get_next=_get_next, response=BaseHttpResponse(response=_response)
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def create(
        self,
        *,
        filename: str,
        type: CreateAssetUploadRequestType,
        total_size: int,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[CreateAssetUploadResponse]:
        """
        This method creates a multipart upload session.

        **Supported content**: Video and audio

        **File size**: 4GB maximum.

        **Additional requirements** depend on your workflow:
        - **Search**: [Marengo requirements](/v1.3/docs/concepts/models/marengo#video-file-requirements)
        - **Video analysis**: [Pegasus requirements](/v1.3/docs/concepts/models/pegasus#input-requirements)
        - **Create embeddings**: [Marengo requirements](/v1.3/docs/concepts/models/marengo#input-requirements)

        Parameters
        ----------
        filename : str
            The original file name of the asset.

        type : CreateAssetUploadRequestType
            The type of asset you want to upload.

        total_size : int
            The total size of the file in bytes. The platform uses this value to:
            - Calculate the optimal chunk size.
            - Determine the total number of chunks required
            - Generate the initial set of presigned URLs

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[CreateAssetUploadResponse]
            The multipart upload session has been successfully created.
        """
        _response = self._client_wrapper.httpx_client.request(
            "assets/multipart-uploads",
            method="POST",
            json={
                "filename": filename,
                "type": type,
                "total_size": total_size,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CreateAssetUploadResponse,
                    parse_obj_as(
                        type_=CreateAssetUploadResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_status(
        self,
        upload_id: str,
        *,
        page: typing.Optional[int] = None,
        page_limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SyncPager[ChunkInfo]:
        """
        This method provides information about an upload session, including its current status, chunk-level progress, and completion state.

        Use this method to:
        - Verify upload completion (`status` = `completed`)
        - Identify any failed chunks that require a retry
        - Monitor the upload progress by comparing `uploaded_size` with `total_size`
        - Determine if the session has expired
        - Retrieve the status information for each chunk

        You must call this method after reporting chunk completion to confirm the upload has transitioned to the `completed` status before using the asset.

        Parameters
        ----------
        upload_id : str
            The unique identifier of the upload session.

        page : typing.Optional[int]
            A number that identifies the page to retrieve.

            **Default**: `1`.

        page_limit : typing.Optional[int]
            The number of items to return on each page.

            **Default**: `10`.
            **Max**: `50`.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        SyncPager[ChunkInfo]
            The status of your upload session has been successfully retrieved.
        """
        page = page if page is not None else 1

        _response = self._client_wrapper.httpx_client.request(
            f"assets/multipart-uploads/{jsonable_encoder(upload_id)}",
            method="GET",
            params={
                "page": page,
                "page_limit": page_limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    GetUploadStatusResponse,
                    parse_obj_as(
                        type_=GetUploadStatusResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.uploaded_chunks
                _has_next = True
                _get_next = lambda: self.get_status(
                    upload_id,
                    page=page + 1,
                    page_limit=page_limit,
                    request_options=request_options,
                )
                return SyncPager(
                    has_next=_has_next, items=_items, get_next=_get_next, response=BaseHttpResponse(response=_response)
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def report_chunk_batch(
        self,
        upload_id: str,
        *,
        completed_chunks: typing.Sequence[CompletedChunk],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[ReportChunkBatchResponse]:
        """
        This method reports successfully uploaded chunks to the platform. The platform finalizes the upload after you report all chunks.


        For optimal performance, report chunks in batches and in any order.

        Parameters
        ----------
        upload_id : str
            The unique identifier of the upload session.

        completed_chunks : typing.Sequence[CompletedChunk]
            The list of chunks successfully uploaded that you're reporting to the platform. Report only after receiving an ETag.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[ReportChunkBatchResponse]
            The completion of this batch has been successfully reported.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"assets/multipart-uploads/{jsonable_encoder(upload_id)}",
            method="POST",
            json={
                "completed_chunks": convert_and_respect_annotation_metadata(
                    object_=completed_chunks, annotation=typing.Sequence[CompletedChunk], direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    ReportChunkBatchResponse,
                    parse_obj_as(
                        type_=ReportChunkBatchResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_additional_presigned_urls(
        self, upload_id: str, *, start: int, count: int, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[RequestAdditionalPresignedUrLsResponse]:
        """
        This method generates new presigned URLs for specific chunks that require uploading. Use this endpoint in the following situations:
        - Your initial URLs have expired (URLs expire after one hour).
        - The initial set of presigned URLs does not include URLs for all chunks.
        - You need to retry failed chunk uploads with new URLs.
        To specify which chunks need URLs, use the `start` and `count` parameters. For example, to generate URLs for chunks 21 to 30, use `start=21` and `count=10`.
        The response will provide new URLs, each with a fresh expiration time of one hour.

        Parameters
        ----------
        upload_id : str
            The unique identifier of the upload session.

        start : int
            The index of the first chunk number to generate URLs for. Chunks are numbered from 1.

        count : int
            The number of presigned URLs to generate starting from the index. You can request a maximum of 50 URLs in a single API call.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[RequestAdditionalPresignedUrLsResponse]
            Additional presigned URLs have been successfully generated.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"assets/multipart-uploads/{jsonable_encoder(upload_id)}/presigned-urls",
            method="POST",
            json={
                "start": start,
                "count": count,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RequestAdditionalPresignedUrLsResponse,
                    parse_obj_as(
                        type_=RequestAdditionalPresignedUrLsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)


class AsyncRawMultipartUploadClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def list_incomplete_uploads(
        self,
        *,
        page: typing.Optional[int] = None,
        page_limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncPager[IncompleteUploadSummary]:
        """
        This method returns a list of all incomplete multipart upload sessions in your account.

        Parameters
        ----------
        page : typing.Optional[int]
            A number that identifies the page to retrieve.

            **Default**: `1`.

        page_limit : typing.Optional[int]
            The number of items to return on each page.

            **Default**: `10`.
            **Max**: `50`.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncPager[IncompleteUploadSummary]
            The list of incomplete upload sessions has been successfully retrieved.
        """
        page = page if page is not None else 1

        _response = await self._client_wrapper.httpx_client.request(
            "assets/multipart-uploads",
            method="GET",
            params={
                "page": page,
                "page_limit": page_limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListIncompleteUploadsResponse,
                    parse_obj_as(
                        type_=ListIncompleteUploadsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.data
                _has_next = True

                async def _get_next():
                    return await self.list_incomplete_uploads(
                        page=page + 1,
                        page_limit=page_limit,
                        request_options=request_options,
                    )

                return AsyncPager(
                    has_next=_has_next, items=_items, get_next=_get_next, response=BaseHttpResponse(response=_response)
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def create(
        self,
        *,
        filename: str,
        type: CreateAssetUploadRequestType,
        total_size: int,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[CreateAssetUploadResponse]:
        """
        This method creates a multipart upload session.

        **Supported content**: Video and audio

        **File size**: 4GB maximum.

        **Additional requirements** depend on your workflow:
        - **Search**: [Marengo requirements](/v1.3/docs/concepts/models/marengo#video-file-requirements)
        - **Video analysis**: [Pegasus requirements](/v1.3/docs/concepts/models/pegasus#input-requirements)
        - **Create embeddings**: [Marengo requirements](/v1.3/docs/concepts/models/marengo#input-requirements)

        Parameters
        ----------
        filename : str
            The original file name of the asset.

        type : CreateAssetUploadRequestType
            The type of asset you want to upload.

        total_size : int
            The total size of the file in bytes. The platform uses this value to:
            - Calculate the optimal chunk size.
            - Determine the total number of chunks required
            - Generate the initial set of presigned URLs

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[CreateAssetUploadResponse]
            The multipart upload session has been successfully created.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "assets/multipart-uploads",
            method="POST",
            json={
                "filename": filename,
                "type": type,
                "total_size": total_size,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CreateAssetUploadResponse,
                    parse_obj_as(
                        type_=CreateAssetUploadResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_status(
        self,
        upload_id: str,
        *,
        page: typing.Optional[int] = None,
        page_limit: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncPager[ChunkInfo]:
        """
        This method provides information about an upload session, including its current status, chunk-level progress, and completion state.

        Use this method to:
        - Verify upload completion (`status` = `completed`)
        - Identify any failed chunks that require a retry
        - Monitor the upload progress by comparing `uploaded_size` with `total_size`
        - Determine if the session has expired
        - Retrieve the status information for each chunk

        You must call this method after reporting chunk completion to confirm the upload has transitioned to the `completed` status before using the asset.

        Parameters
        ----------
        upload_id : str
            The unique identifier of the upload session.

        page : typing.Optional[int]
            A number that identifies the page to retrieve.

            **Default**: `1`.

        page_limit : typing.Optional[int]
            The number of items to return on each page.

            **Default**: `10`.
            **Max**: `50`.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncPager[ChunkInfo]
            The status of your upload session has been successfully retrieved.
        """
        page = page if page is not None else 1

        _response = await self._client_wrapper.httpx_client.request(
            f"assets/multipart-uploads/{jsonable_encoder(upload_id)}",
            method="GET",
            params={
                "page": page,
                "page_limit": page_limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    GetUploadStatusResponse,
                    parse_obj_as(
                        type_=GetUploadStatusResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.uploaded_chunks
                _has_next = True

                async def _get_next():
                    return await self.get_status(
                        upload_id,
                        page=page + 1,
                        page_limit=page_limit,
                        request_options=request_options,
                    )

                return AsyncPager(
                    has_next=_has_next, items=_items, get_next=_get_next, response=BaseHttpResponse(response=_response)
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def report_chunk_batch(
        self,
        upload_id: str,
        *,
        completed_chunks: typing.Sequence[CompletedChunk],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[ReportChunkBatchResponse]:
        """
        This method reports successfully uploaded chunks to the platform. The platform finalizes the upload after you report all chunks.


        For optimal performance, report chunks in batches and in any order.

        Parameters
        ----------
        upload_id : str
            The unique identifier of the upload session.

        completed_chunks : typing.Sequence[CompletedChunk]
            The list of chunks successfully uploaded that you're reporting to the platform. Report only after receiving an ETag.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[ReportChunkBatchResponse]
            The completion of this batch has been successfully reported.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"assets/multipart-uploads/{jsonable_encoder(upload_id)}",
            method="POST",
            json={
                "completed_chunks": convert_and_respect_annotation_metadata(
                    object_=completed_chunks, annotation=typing.Sequence[CompletedChunk], direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    ReportChunkBatchResponse,
                    parse_obj_as(
                        type_=ReportChunkBatchResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_additional_presigned_urls(
        self, upload_id: str, *, start: int, count: int, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[RequestAdditionalPresignedUrLsResponse]:
        """
        This method generates new presigned URLs for specific chunks that require uploading. Use this endpoint in the following situations:
        - Your initial URLs have expired (URLs expire after one hour).
        - The initial set of presigned URLs does not include URLs for all chunks.
        - You need to retry failed chunk uploads with new URLs.
        To specify which chunks need URLs, use the `start` and `count` parameters. For example, to generate URLs for chunks 21 to 30, use `start=21` and `count=10`.
        The response will provide new URLs, each with a fresh expiration time of one hour.

        Parameters
        ----------
        upload_id : str
            The unique identifier of the upload session.

        start : int
            The index of the first chunk number to generate URLs for. Chunks are numbered from 1.

        count : int
            The number of presigned URLs to generate starting from the index. You can request a maximum of 50 URLs in a single API call.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[RequestAdditionalPresignedUrLsResponse]
            Additional presigned URLs have been successfully generated.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"assets/multipart-uploads/{jsonable_encoder(upload_id)}/presigned-urls",
            method="POST",
            json={
                "start": start,
                "count": count,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RequestAdditionalPresignedUrLsResponse,
                    parse_obj_as(
                        type_=RequestAdditionalPresignedUrLsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
