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

import json
import typing
from json.decoder import JSONDecodeError

from .. import core
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.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..errors.bad_request_error import BadRequestError
from ..errors.forbidden_error import ForbiddenError
from ..errors.not_found_error import NotFoundError
from ..errors.unsupported_media_type_error import UnsupportedMediaTypeError
from ..types.bad_request_error_body import BadRequestErrorBody
from ..types.chunking_strategy import ChunkingStrategy
from ..types.corpus_key import CorpusKey
from ..types.document import Document
from ..types.error import Error
from ..types.not_found_error_body import NotFoundErrorBody
from ..types.table_extraction_config import TableExtractionConfig

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


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

    def file(
        self,
        corpus_key: CorpusKey,
        *,
        file: core.File,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        chunking_strategy: typing.Optional[ChunkingStrategy] = OMIT,
        table_extraction_config: typing.Optional[TableExtractionConfig] = OMIT,
        filename: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Document]:
        """
        Upload files such as PDFs and Word Documents for automatic text extraction and metadata parsing.
        The request expects a `multipart/form-data` format containing the following parts:
        * `metadata` - Optionally specifies a JSON object representing any additional metadata to be associated with the extracted document. For example, `'metadata={"key": "value"};type=application/json'`
        * `chunking_strategy` - If provided, specifies the chunking strategy for the platform to use. If you do not set this option, the platform uses the default strategy, which creates one chunk per sentence. You can explicitly set sentence chunking with `'chunking_strategy={"type":"sentence_chunking_strategy"};type=application/json'` or use max chars chunking with `'chunking_strategy={"type":"max_chars_chunking_strategy","max_chars_per_chunk":200};type=application/json'`
        * `table_extraction_config` - You can optionally specify whether to extract table data from the uploaded file. If you do not set this option, the platform does not extract tables from PDF files. Example config, `'table_extraction_config={"extract_tables":true};type=application/json'`
        * `file` - Specifies the file that you want to upload.
        * `filename` - Specified as part of the file field with the file name that you want to associate with the uploaded file. For a curl example, use the following syntax: `'file=@/path/to/file/file.pdf;filename=desired_filename.pdf'`

        For more detailed information, see this [File Upload API guide.](https://docs.vectara.com/docs/api-reference/indexing-apis/file-upload/file-upload)

        Parameters
        ----------
        corpus_key : CorpusKey
            The unique key identifying the corpus of which to upload the file.

        file : core.File
            See core.File for more documentation

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            Arbitrary object that will be attached as document metadata to the extracted document.

        chunking_strategy : typing.Optional[ChunkingStrategy]

        table_extraction_config : typing.Optional[TableExtractionConfig]

        filename : typing.Optional[str]
            Optional multipart section to override the filename.

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

        Returns
        -------
        HttpResponse[Document]
            The extracted document has been parsed and added to the corpus.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/corpora/{jsonable_encoder(corpus_key)}/upload_file",
            base_url=self._client_wrapper.get_environment().default,
            method="POST",
            data={},
            files={
                **(
                    {"metadata": (None, json.dumps(jsonable_encoder(metadata)), "application/json")}
                    if metadata is not OMIT
                    else {}
                ),
                **(
                    {"chunking_strategy": (None, json.dumps(jsonable_encoder(chunking_strategy)), "application/json")}
                    if chunking_strategy is not OMIT
                    else {}
                ),
                **(
                    {
                        "table_extraction_config": (
                            None,
                            json.dumps(jsonable_encoder(table_extraction_config)),
                            "application/json",
                        )
                    }
                    if table_extraction_config is not OMIT
                    else {}
                ),
                **({"filename": (None, jsonable_encoder(filename), "text/plain")} if filename is not OMIT else {}),
                "file": core.with_content_type(file=file, default_content_type="application/octet-stream"),
            },
            headers={
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Document,
                    parse_obj_as(
                        type_=Document,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        BadRequestErrorBody,
                        parse_obj_as(
                            type_=BadRequestErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 415:
                raise UnsupportedMediaTypeError(
                    typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


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

    async def file(
        self,
        corpus_key: CorpusKey,
        *,
        file: core.File,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        chunking_strategy: typing.Optional[ChunkingStrategy] = OMIT,
        table_extraction_config: typing.Optional[TableExtractionConfig] = OMIT,
        filename: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Document]:
        """
        Upload files such as PDFs and Word Documents for automatic text extraction and metadata parsing.
        The request expects a `multipart/form-data` format containing the following parts:
        * `metadata` - Optionally specifies a JSON object representing any additional metadata to be associated with the extracted document. For example, `'metadata={"key": "value"};type=application/json'`
        * `chunking_strategy` - If provided, specifies the chunking strategy for the platform to use. If you do not set this option, the platform uses the default strategy, which creates one chunk per sentence. You can explicitly set sentence chunking with `'chunking_strategy={"type":"sentence_chunking_strategy"};type=application/json'` or use max chars chunking with `'chunking_strategy={"type":"max_chars_chunking_strategy","max_chars_per_chunk":200};type=application/json'`
        * `table_extraction_config` - You can optionally specify whether to extract table data from the uploaded file. If you do not set this option, the platform does not extract tables from PDF files. Example config, `'table_extraction_config={"extract_tables":true};type=application/json'`
        * `file` - Specifies the file that you want to upload.
        * `filename` - Specified as part of the file field with the file name that you want to associate with the uploaded file. For a curl example, use the following syntax: `'file=@/path/to/file/file.pdf;filename=desired_filename.pdf'`

        For more detailed information, see this [File Upload API guide.](https://docs.vectara.com/docs/api-reference/indexing-apis/file-upload/file-upload)

        Parameters
        ----------
        corpus_key : CorpusKey
            The unique key identifying the corpus of which to upload the file.

        file : core.File
            See core.File for more documentation

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            Arbitrary object that will be attached as document metadata to the extracted document.

        chunking_strategy : typing.Optional[ChunkingStrategy]

        table_extraction_config : typing.Optional[TableExtractionConfig]

        filename : typing.Optional[str]
            Optional multipart section to override the filename.

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

        Returns
        -------
        AsyncHttpResponse[Document]
            The extracted document has been parsed and added to the corpus.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/corpora/{jsonable_encoder(corpus_key)}/upload_file",
            base_url=self._client_wrapper.get_environment().default,
            method="POST",
            data={},
            files={
                **(
                    {"metadata": (None, json.dumps(jsonable_encoder(metadata)), "application/json")}
                    if metadata is not OMIT
                    else {}
                ),
                **(
                    {"chunking_strategy": (None, json.dumps(jsonable_encoder(chunking_strategy)), "application/json")}
                    if chunking_strategy is not OMIT
                    else {}
                ),
                **(
                    {
                        "table_extraction_config": (
                            None,
                            json.dumps(jsonable_encoder(table_extraction_config)),
                            "application/json",
                        )
                    }
                    if table_extraction_config is not OMIT
                    else {}
                ),
                **({"filename": (None, jsonable_encoder(filename), "text/plain")} if filename is not OMIT else {}),
                "file": core.with_content_type(file=file, default_content_type="application/octet-stream"),
            },
            headers={
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Document,
                    parse_obj_as(
                        type_=Document,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        BadRequestErrorBody,
                        parse_obj_as(
                            type_=BadRequestErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 415:
                raise UnsupportedMediaTypeError(
                    typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
