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

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.internal_server_error import InternalServerError
from ..errors.not_found_error import NotFoundError
from ..errors.unprocessable_entity_error import UnprocessableEntityError
from ..types.batch_extract_response import BatchExtractResponse
from ..types.document_extract_response import DocumentExtractResponse

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


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

    def extract_document(
        self,
        *,
        file: core.File,
        schema: str,
        organization_id: typing.Optional[str] = OMIT,
        prompt: typing.Optional[str] = OMIT,
        model: typing.Optional[str] = OMIT,
        vision_model: typing.Optional[str] = OMIT,
        sync: typing.Optional[bool] = OMIT,
        include_raw_text: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[DocumentExtractResponse]:
        """
        Extract structured data from uploaded document according to provided JSON schema.

            **Supported Document Types:**
            - PDF documents (application/pdf)
            - Word documents (application/vnd.openxmlformats-officedocument.wordprocessingml.document)
            - Excel spreadsheets (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
            - Images (image/jpeg, image/png, image/gif, image/bmp, image/tiff, image/webp)

            **Processing Strategy:**
            1. Try direct text extraction (PDF, DOCX, XLSX) - fast & cheap
            2. Fall back to Vision API for images/scanned docs - best quality
            3. Use Responses API for text-based extraction with JSON mode

            **Parameters:**
            - `file`: Document file to process (max 50MB)
            - `schema`: JSON schema defining extraction structure (as JSON string)
            - `organization_id`: Organization ID (org_ prefixed string)
            - `prompt`: Optional custom instructions to guide extraction behavior
            - `model`: Optional model selection (any LLM model - text or vision-capable)
            - `sync`: Process synchronously (true) or async (false, default)
            - `include_raw_text`: Include extracted text in response (default: false)

            **Using the `prompt` Parameter:**
            The `prompt` parameter allows you to provide specific instructions to improve extraction accuracy:

            Examples:
            - "Focus on extracting line items from the table. Ignore header and footer text."
            - "Extract dates in YYYY-MM-DD format. Convert any other date formats."
            - "For handwritten text, if unclear, mark the field as null rather than guessing."
            - "Calculate total hours by subtracting break time from the difference between start and end times."
            - "Extract currency amounts without symbols (e.g., 1250.00 instead of $1,250.00)."
            - "If multiple addresses are present, extract only the billing address."
            - "Round all decimal numbers to 2 decimal places."

            **Model Selection:**
            - **Text/JSON Model** (`model` parameter): Used for final JSON extraction from text (default: ftg-3.0)
              - Examples: ftg-3.0, gpt-4o-mini, gpt-4o, gpt-4-turbo
              - Must resolve to an OpenAI model
            - **Vision Model** (`vision_model` parameter): Used for image analysis (default: gpt-5)
              - Examples: gpt-5, gpt-4o, gpt-4o-mini, gpt-4-turbo
              - Must be an OpenAI vision model
            - **Extraction Flow**: Vision analysis + Text extraction → Combined text → JSON extraction with text model
            - **Universal JSON Mode**: Robust JSON extraction from any LLM response format

            **Billing:**
            - Direct extraction: ~$0.001 per document
            - Vision API: ~$0.01-0.05 per document (depends on pages and model)
            - Responses API: ~$0.001-0.01 per document

            **Response Headers:**
            - `X-Processing-Method`: direct_text, vision_api, responses_api
            - `X-Model-Used`: Actual model used for extraction
            - `X-Cost-CHF`: Total cost in CHF

            **Example Schema:**
            ```json
            {
                "invoice_number": "string",
                "date": "string",
                "total": "number",
                "items": [
                    {
                        "description": "string",
                        "quantity": "number",
                        "price": "number"
                    }
                ]
            }
            ```

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

        schema : str
            JSON schema defining extraction structure (as JSON string)

        organization_id : typing.Optional[str]
            Organization ID (org_ prefixed string). Optional for single-org API keys.

        prompt : typing.Optional[str]
            Optional custom extraction instructions

        model : typing.Optional[str]
            Text/JSON extraction model (default: ftg-3.0)

        vision_model : typing.Optional[str]
            Vision analysis model for images/PDFs (default: gpt-5)

        sync : typing.Optional[bool]
            Process synchronously (true) or async (false)

        include_raw_text : typing.Optional[bool]
            Include extracted text in response

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

        Returns
        -------
        HttpResponse[DocumentExtractResponse]
            Document extraction initiated or completed
        """
        _response = self._client_wrapper.httpx_client.request(
            "v1/documents/extract",
            method="POST",
            data={
                "schema": schema,
                "organization_id": organization_id,
                "prompt": prompt,
                "model": model,
                "vision_model": vision_model,
                "sync": sync,
                "include_raw_text": include_raw_text,
            },
            files={
                "file": file,
            },
            request_options=request_options,
            omit=OMIT,
            force_multipart=True,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DocumentExtractResponse,
                    parse_obj_as(
                        type_=DocumentExtractResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=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 extract_documents_batch(
        self,
        *,
        files: typing.List[core.File],
        schema: str,
        organization_id: typing.Optional[str] = OMIT,
        prompt: typing.Optional[str] = OMIT,
        model: typing.Optional[str] = OMIT,
        vision_model: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[BatchExtractResponse]:
        """
        Extract structured data from multiple documents using the same JSON schema.

            **Batch Processing:**
            - All documents processed asynchronously
            - Same schema applied to all documents
            - Parallel processing up to 5 documents
            - Returns batch_id and list of job_ids

            **Supported Document Types:**
            - PDF documents (application/pdf)
            - Word documents (application/vnd.openxmlformats-officedocument.wordprocessingml.document)
            - Excel spreadsheets (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
            - Images (image/jpeg, image/png, image/gif, image/bmp, image/tiff, image/webp)

            **Parameters:**
            - `files`: List of document files to process (max 50MB each)
            - `schema`: JSON schema defining extraction structure (as JSON string)
            - `organization_id`: Organization ID (org_ prefixed string)
            - `prompt`: Optional custom instructions applied to all documents
            - `model`: Optional model selection (gpt-4o, gpt-4o-mini) applied to all documents

            **Limitations:**
            - Maximum 50 documents per batch
            - Each file must be under 50MB
            - All files must be supported types

            **Response:**
            - Returns immediately with batch_id and list of job_ids
            - Poll individual jobs using GET /documents/jobs/{job_id} for status

            **Example Schema:**
            ```json
            {
                "invoice_number": "string",
                "date": "string",
                "total": "number",
                "items": [
                    {
                        "description": "string",
                        "quantity": "number",
                        "price": "number"
                    }
                ]
            }
            ```

        Parameters
        ----------
        files : typing.List[core.File]
            See core.File for more documentation

        schema : str
            JSON schema defining extraction structure (as JSON string)

        organization_id : typing.Optional[str]
            Organization ID (org_ prefixed string). Optional for single-org API keys.

        prompt : typing.Optional[str]
            Optional custom extraction instructions applied to all documents

        model : typing.Optional[str]
            Text/JSON extraction model applied to all documents (default: ftg-3.0)

        vision_model : typing.Optional[str]
            Vision analysis model for images/PDFs (default: gpt-5)

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

        Returns
        -------
        HttpResponse[BatchExtractResponse]
            Batch processing initiated
        """
        _response = self._client_wrapper.httpx_client.request(
            "v1/documents/extract/batch",
            method="POST",
            data={
                "schema": schema,
                "organization_id": organization_id,
                "prompt": prompt,
                "model": model,
                "vision_model": vision_model,
            },
            files={
                "files": files,
            },
            request_options=request_options,
            omit=OMIT,
            force_multipart=True,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BatchExtractResponse,
                    parse_obj_as(
                        type_=BatchExtractResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=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_job_status(
        self, job_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[DocumentExtractResponse]:
        """
        Get document extraction job status and results.

        **Status Values:**
        - `pending`: Job queued, not started
        - `processing`: Currently processing
        - `completed`: Successfully completed
        - `failed`: Processing failed
        - `cancelled`: Job was cancelled

        **Response includes:**
        - Job status and timestamps
        - Extracted data (if completed)
        - Confidence scores
        - Processing metadata (method, model, time)
        - Cost information (CHF, synapses, tokens)
        - Error message (if failed)

        **Access Control:**
        - User must be authenticated
        - User must have access to the job (created by user or in same organization)

        **Example Response (Completed):**
        ```json
        {
            "success": true,
            "job_id": "doc_abc123",
            "status": "completed",
            "extracted_data": {
                "invoice_number": "INV-2024-001",
                "date": "2024-01-15",
                "total": 1250.00
            },
            "confidence": 95.5,
            "processing_time": 2.3,
            "cost_chf": 0.015,
            "model_used": "gpt-4o-mini",
            "created_at": "2024-01-15T10:30:00Z",
            "completed_at": "2024-01-15T10:30:02Z"
        }
        ```

        **Example Response (Processing):**
        ```json
        {
            "success": true,
            "job_id": "doc_abc123",
            "status": "processing",
            "extracted_data": null,
            "confidence": null,
            "processing_time": null,
            "cost_chf": null,
            "model_used": null,
            "created_at": "2024-01-15T10:30:00Z",
            "completed_at": null
        }
        ```

        **Example Response (Failed):**
        ```json
        {
            "success": false,
            "job_id": "doc_abc123",
            "status": "failed",
            "extracted_data": null,
            "confidence": null,
            "processing_time": 1.5,
            "cost_chf": 0.005,
            "model_used": "gpt-4o-mini",
            "created_at": "2024-01-15T10:30:00Z",
            "completed_at": "2024-01-15T10:30:01Z"
        }
        ```

        Parameters
        ----------
        job_id : str

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

        Returns
        -------
        HttpResponse[DocumentExtractResponse]
            Job status retrieved successfully
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/documents/jobs/{jsonable_encoder(job_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DocumentExtractResponse,
                    parse_obj_as(
                        type_=DocumentExtractResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=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 AsyncRawDocumentExtractionClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def extract_document(
        self,
        *,
        file: core.File,
        schema: str,
        organization_id: typing.Optional[str] = OMIT,
        prompt: typing.Optional[str] = OMIT,
        model: typing.Optional[str] = OMIT,
        vision_model: typing.Optional[str] = OMIT,
        sync: typing.Optional[bool] = OMIT,
        include_raw_text: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[DocumentExtractResponse]:
        """
        Extract structured data from uploaded document according to provided JSON schema.

            **Supported Document Types:**
            - PDF documents (application/pdf)
            - Word documents (application/vnd.openxmlformats-officedocument.wordprocessingml.document)
            - Excel spreadsheets (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
            - Images (image/jpeg, image/png, image/gif, image/bmp, image/tiff, image/webp)

            **Processing Strategy:**
            1. Try direct text extraction (PDF, DOCX, XLSX) - fast & cheap
            2. Fall back to Vision API for images/scanned docs - best quality
            3. Use Responses API for text-based extraction with JSON mode

            **Parameters:**
            - `file`: Document file to process (max 50MB)
            - `schema`: JSON schema defining extraction structure (as JSON string)
            - `organization_id`: Organization ID (org_ prefixed string)
            - `prompt`: Optional custom instructions to guide extraction behavior
            - `model`: Optional model selection (any LLM model - text or vision-capable)
            - `sync`: Process synchronously (true) or async (false, default)
            - `include_raw_text`: Include extracted text in response (default: false)

            **Using the `prompt` Parameter:**
            The `prompt` parameter allows you to provide specific instructions to improve extraction accuracy:

            Examples:
            - "Focus on extracting line items from the table. Ignore header and footer text."
            - "Extract dates in YYYY-MM-DD format. Convert any other date formats."
            - "For handwritten text, if unclear, mark the field as null rather than guessing."
            - "Calculate total hours by subtracting break time from the difference between start and end times."
            - "Extract currency amounts without symbols (e.g., 1250.00 instead of $1,250.00)."
            - "If multiple addresses are present, extract only the billing address."
            - "Round all decimal numbers to 2 decimal places."

            **Model Selection:**
            - **Text/JSON Model** (`model` parameter): Used for final JSON extraction from text (default: ftg-3.0)
              - Examples: ftg-3.0, gpt-4o-mini, gpt-4o, gpt-4-turbo
              - Must resolve to an OpenAI model
            - **Vision Model** (`vision_model` parameter): Used for image analysis (default: gpt-5)
              - Examples: gpt-5, gpt-4o, gpt-4o-mini, gpt-4-turbo
              - Must be an OpenAI vision model
            - **Extraction Flow**: Vision analysis + Text extraction → Combined text → JSON extraction with text model
            - **Universal JSON Mode**: Robust JSON extraction from any LLM response format

            **Billing:**
            - Direct extraction: ~$0.001 per document
            - Vision API: ~$0.01-0.05 per document (depends on pages and model)
            - Responses API: ~$0.001-0.01 per document

            **Response Headers:**
            - `X-Processing-Method`: direct_text, vision_api, responses_api
            - `X-Model-Used`: Actual model used for extraction
            - `X-Cost-CHF`: Total cost in CHF

            **Example Schema:**
            ```json
            {
                "invoice_number": "string",
                "date": "string",
                "total": "number",
                "items": [
                    {
                        "description": "string",
                        "quantity": "number",
                        "price": "number"
                    }
                ]
            }
            ```

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

        schema : str
            JSON schema defining extraction structure (as JSON string)

        organization_id : typing.Optional[str]
            Organization ID (org_ prefixed string). Optional for single-org API keys.

        prompt : typing.Optional[str]
            Optional custom extraction instructions

        model : typing.Optional[str]
            Text/JSON extraction model (default: ftg-3.0)

        vision_model : typing.Optional[str]
            Vision analysis model for images/PDFs (default: gpt-5)

        sync : typing.Optional[bool]
            Process synchronously (true) or async (false)

        include_raw_text : typing.Optional[bool]
            Include extracted text in response

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

        Returns
        -------
        AsyncHttpResponse[DocumentExtractResponse]
            Document extraction initiated or completed
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v1/documents/extract",
            method="POST",
            data={
                "schema": schema,
                "organization_id": organization_id,
                "prompt": prompt,
                "model": model,
                "vision_model": vision_model,
                "sync": sync,
                "include_raw_text": include_raw_text,
            },
            files={
                "file": file,
            },
            request_options=request_options,
            omit=OMIT,
            force_multipart=True,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DocumentExtractResponse,
                    parse_obj_as(
                        type_=DocumentExtractResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=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 extract_documents_batch(
        self,
        *,
        files: typing.List[core.File],
        schema: str,
        organization_id: typing.Optional[str] = OMIT,
        prompt: typing.Optional[str] = OMIT,
        model: typing.Optional[str] = OMIT,
        vision_model: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[BatchExtractResponse]:
        """
        Extract structured data from multiple documents using the same JSON schema.

            **Batch Processing:**
            - All documents processed asynchronously
            - Same schema applied to all documents
            - Parallel processing up to 5 documents
            - Returns batch_id and list of job_ids

            **Supported Document Types:**
            - PDF documents (application/pdf)
            - Word documents (application/vnd.openxmlformats-officedocument.wordprocessingml.document)
            - Excel spreadsheets (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
            - Images (image/jpeg, image/png, image/gif, image/bmp, image/tiff, image/webp)

            **Parameters:**
            - `files`: List of document files to process (max 50MB each)
            - `schema`: JSON schema defining extraction structure (as JSON string)
            - `organization_id`: Organization ID (org_ prefixed string)
            - `prompt`: Optional custom instructions applied to all documents
            - `model`: Optional model selection (gpt-4o, gpt-4o-mini) applied to all documents

            **Limitations:**
            - Maximum 50 documents per batch
            - Each file must be under 50MB
            - All files must be supported types

            **Response:**
            - Returns immediately with batch_id and list of job_ids
            - Poll individual jobs using GET /documents/jobs/{job_id} for status

            **Example Schema:**
            ```json
            {
                "invoice_number": "string",
                "date": "string",
                "total": "number",
                "items": [
                    {
                        "description": "string",
                        "quantity": "number",
                        "price": "number"
                    }
                ]
            }
            ```

        Parameters
        ----------
        files : typing.List[core.File]
            See core.File for more documentation

        schema : str
            JSON schema defining extraction structure (as JSON string)

        organization_id : typing.Optional[str]
            Organization ID (org_ prefixed string). Optional for single-org API keys.

        prompt : typing.Optional[str]
            Optional custom extraction instructions applied to all documents

        model : typing.Optional[str]
            Text/JSON extraction model applied to all documents (default: ftg-3.0)

        vision_model : typing.Optional[str]
            Vision analysis model for images/PDFs (default: gpt-5)

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

        Returns
        -------
        AsyncHttpResponse[BatchExtractResponse]
            Batch processing initiated
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v1/documents/extract/batch",
            method="POST",
            data={
                "schema": schema,
                "organization_id": organization_id,
                "prompt": prompt,
                "model": model,
                "vision_model": vision_model,
            },
            files={
                "files": files,
            },
            request_options=request_options,
            omit=OMIT,
            force_multipart=True,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BatchExtractResponse,
                    parse_obj_as(
                        type_=BatchExtractResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=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_job_status(
        self, job_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[DocumentExtractResponse]:
        """
        Get document extraction job status and results.

        **Status Values:**
        - `pending`: Job queued, not started
        - `processing`: Currently processing
        - `completed`: Successfully completed
        - `failed`: Processing failed
        - `cancelled`: Job was cancelled

        **Response includes:**
        - Job status and timestamps
        - Extracted data (if completed)
        - Confidence scores
        - Processing metadata (method, model, time)
        - Cost information (CHF, synapses, tokens)
        - Error message (if failed)

        **Access Control:**
        - User must be authenticated
        - User must have access to the job (created by user or in same organization)

        **Example Response (Completed):**
        ```json
        {
            "success": true,
            "job_id": "doc_abc123",
            "status": "completed",
            "extracted_data": {
                "invoice_number": "INV-2024-001",
                "date": "2024-01-15",
                "total": 1250.00
            },
            "confidence": 95.5,
            "processing_time": 2.3,
            "cost_chf": 0.015,
            "model_used": "gpt-4o-mini",
            "created_at": "2024-01-15T10:30:00Z",
            "completed_at": "2024-01-15T10:30:02Z"
        }
        ```

        **Example Response (Processing):**
        ```json
        {
            "success": true,
            "job_id": "doc_abc123",
            "status": "processing",
            "extracted_data": null,
            "confidence": null,
            "processing_time": null,
            "cost_chf": null,
            "model_used": null,
            "created_at": "2024-01-15T10:30:00Z",
            "completed_at": null
        }
        ```

        **Example Response (Failed):**
        ```json
        {
            "success": false,
            "job_id": "doc_abc123",
            "status": "failed",
            "extracted_data": null,
            "confidence": null,
            "processing_time": 1.5,
            "cost_chf": 0.005,
            "model_used": "gpt-4o-mini",
            "created_at": "2024-01-15T10:30:00Z",
            "completed_at": "2024-01-15T10:30:01Z"
        }
        ```

        Parameters
        ----------
        job_id : str

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

        Returns
        -------
        AsyncHttpResponse[DocumentExtractResponse]
            Job status retrieved successfully
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/documents/jobs/{jsonable_encoder(job_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DocumentExtractResponse,
                    parse_obj_as(
                        type_=DocumentExtractResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=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)
