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

import datetime as dt
import typing
from json.decoder import JSONDecodeError

from .......core.api_error import ApiError
from .......core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from .......core.datetime_utils import serialize_datetime
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 ....common.errors.bad_request_error import BadRequestError
from ....common.errors.not_found_error import NotFoundError
from ....common.errors.version_conflict_error import VersionConflictError
from ....common.types.error_base_4_xx import ErrorBase4Xx
from ....common.types.external_provider import ExternalProvider
from ....common.types.page_token import PageToken
from ....common.types.patient_id import PatientId
from ....common.types.sort_direction import SortDirection
from ....common.types.version_conflict_error_body import VersionConflictErrorBody
from .types.mutable_patient import MutablePatient
from .types.mutable_patient_with_mrn import MutablePatientWithMrn
from .types.patient import Patient
from .types.patient_page import PatientPage
from .types.patient_sort_field import PatientSortField

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


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

    def create(
        self,
        *,
        request: MutablePatient,
        skip_duplicate_check: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Patient]:
        """
        Adds a patient.  VersionConflictError is returned when the patient's external ID is already in use.

        Parameters
        ----------
        request : MutablePatient

        skip_duplicate_check : typing.Optional[bool]

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

        Returns
        -------
        HttpResponse[Patient]
        """
        _response = self._client_wrapper.httpx_client.request(
            "patients/v1",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="POST",
            params={
                "skip_duplicate_check": skip_duplicate_check,
            },
            json=request,
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                Patient,
                parse_obj_as(
                    type_=Patient,  # type: ignore
                    object_=_response_json,
                ),
            )
            return HttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def create_with_mrn(
        self,
        *,
        request: MutablePatientWithMrn,
        skip_duplicate_check: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Patient]:
        """
        Adds a patient and hydrates their MRN with a pre-existing MRN.  Once this patient is created their MRN will not be editable. BadRequestError is returned when the MRN is greater than 20 characters. VersionConflictError is returned when the patient's external ID is already in use.

        Parameters
        ----------
        request : MutablePatientWithMrn

        skip_duplicate_check : typing.Optional[bool]

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

        Returns
        -------
        HttpResponse[Patient]
        """
        _response = self._client_wrapper.httpx_client.request(
            "patients/v1/with_mrn",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="POST",
            params={
                "skip_duplicate_check": skip_duplicate_check,
            },
            json=request,
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                Patient,
                parse_obj_as(
                    type_=Patient,  # type: ignore
                    object_=_response_json,
                ),
            )
            return HttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
            if _response_json["errorName"] == "BadRequestError":
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_multi(
        self,
        *,
        limit: typing.Optional[int] = None,
        mrn: typing.Optional[str] = None,
        page_token: typing.Optional[PageToken] = None,
        sort_field: typing.Optional[PatientSortField] = None,
        sort_direction: typing.Optional[SortDirection] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[PatientPage]:
        """
        Searches for patients that match the query parameters.

        Parameters
        ----------
        limit : typing.Optional[int]

        mrn : typing.Optional[str]

        page_token : typing.Optional[PageToken]

        sort_field : typing.Optional[PatientSortField]

        sort_direction : typing.Optional[SortDirection]
            Defaults to ascending.

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

        Returns
        -------
        HttpResponse[PatientPage]
        """
        _response = self._client_wrapper.httpx_client.request(
            "patients/v1/get_multi",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            params={
                "limit": limit,
                "mrn": mrn,
                "page_token": page_token,
                "sort_field": sort_field,
                "sort_direction": sort_direction,
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                PatientPage,
                parse_obj_as(
                    type_=PatientPage,  # type: ignore
                    object_=_response_json,
                ),
            )
            return HttpResponse(response=_response, data=_data)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def search_providers(
        self, *, search_criteria: str, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[typing.List[ExternalProvider]]:
        """
        Searches for referring providers that match the query parameters.  The search is case-insensitive, supports fuzzy matching, and matches against provider name and NPI. The search criteria must be an alphanumeric string, and the search is limited to the first 20 results.

        Parameters
        ----------
        search_criteria : str

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

        Returns
        -------
        HttpResponse[typing.List[ExternalProvider]]
        """
        _response = self._client_wrapper.httpx_client.request(
            "patients/v1/search_providers",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            params={
                "search_criteria": search_criteria,
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                typing.List[ExternalProvider],
                parse_obj_as(
                    type_=typing.List[ExternalProvider],  # type: ignore
                    object_=_response_json,
                ),
            )
            return HttpResponse(response=_response, data=_data)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get(self, id: PatientId, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Patient]:
        """
        Gets a patient.

        Parameters
        ----------
        id : PatientId

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

        Returns
        -------
        HttpResponse[Patient]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                Patient,
                parse_obj_as(
                    type_=Patient,  # type: ignore
                    object_=_response_json,
                ),
            )
            return HttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_history(
        self, id: PatientId, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[typing.List[Patient]]:
        """
        Gets a patient along with it's full history.  The return list is ordered by version ascending.

        Parameters
        ----------
        id : PatientId

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

        Returns
        -------
        HttpResponse[typing.List[Patient]]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}/history",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                typing.List[Patient],
                parse_obj_as(
                    type_=typing.List[Patient],  # type: ignore
                    object_=_response_json,
                ),
            )
            return HttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def update(
        self,
        id: PatientId,
        version: str,
        *,
        request: MutablePatient,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Patient]:
        """
        Updates a patient.  The path must contain the most recent version to prevent race conditions.  Updating historic versions is not supported.

        Parameters
        ----------
        id : PatientId

        version : str

        request : MutablePatient

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

        Returns
        -------
        HttpResponse[Patient]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}/{jsonable_encoder(version)}",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="PUT",
            json=request,
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                Patient,
                parse_obj_as(
                    type_=Patient,  # type: ignore
                    object_=_response_json,
                ),
            )
            return HttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def deactivate(
        self, id: PatientId, version: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[None]:
        """
        Sets a patient as deactivated.  The path must contain the most recent version plus 1 to prevent race conditions.  Deactivating historic versions is not supported.

        Parameters
        ----------
        id : PatientId

        version : str

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

        Returns
        -------
        HttpResponse[None]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}/{jsonable_encoder(version)}",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="DELETE",
            request_options=request_options,
        )
        if 200 <= _response.status_code < 300:
            return HttpResponse(response=_response, data=None)
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def reactivate(
        self, id: PatientId, version: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[None]:
        """
        Removes the deactivated flag for a patient.  The path must contain the most recent version plus 1 to prevent race conditions.  Reactivating historic versions is not supported.

        Parameters
        ----------
        id : PatientId

        version : str

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

        Returns
        -------
        HttpResponse[None]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}/{jsonable_encoder(version)}",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="PATCH",
            request_options=request_options,
        )
        if 200 <= _response.status_code < 300:
            return HttpResponse(response=_response, data=None)
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def search(
        self,
        *,
        mrn: typing.Optional[str] = None,
        similar_name_ordering: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[typing.List[Patient]]:
        """
        Returns a list of Patients based on the search criteria.

        Parameters
        ----------
        mrn : typing.Optional[str]

        similar_name_ordering : typing.Optional[str]
            A string that is used to order similar names in search results.

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

        Returns
        -------
        HttpResponse[typing.List[Patient]]
        """
        _response = self._client_wrapper.httpx_client.request(
            "patients/v1",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            params={
                "mrn": mrn,
                "similar_name_ordering": similar_name_ordering,
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                typing.List[Patient],
                parse_obj_as(
                    type_=typing.List[Patient],  # type: ignore
                    object_=_response_json,
                ),
            )
            return HttpResponse(response=_response, data=_data)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def scan(
        self, *, since: dt.datetime, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[typing.List[Patient]]:
        """
        Scans up to 100 patient updates.  The since query parameter is inclusive, and the result list is ordered by updatedAt ascending.

        Parameters
        ----------
        since : dt.datetime

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

        Returns
        -------
        HttpResponse[typing.List[Patient]]
        """
        _response = self._client_wrapper.httpx_client.request(
            "patients/v1/updates/scan",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            params={
                "since": serialize_datetime(since),
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                typing.List[Patient],
                parse_obj_as(
                    type_=typing.List[Patient],  # type: ignore
                    object_=_response_json,
                ),
            )
            return HttpResponse(response=_response, data=_data)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)


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

    async def create(
        self,
        *,
        request: MutablePatient,
        skip_duplicate_check: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Patient]:
        """
        Adds a patient.  VersionConflictError is returned when the patient's external ID is already in use.

        Parameters
        ----------
        request : MutablePatient

        skip_duplicate_check : typing.Optional[bool]

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

        Returns
        -------
        AsyncHttpResponse[Patient]
        """
        _response = await self._client_wrapper.httpx_client.request(
            "patients/v1",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="POST",
            params={
                "skip_duplicate_check": skip_duplicate_check,
            },
            json=request,
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                Patient,
                parse_obj_as(
                    type_=Patient,  # type: ignore
                    object_=_response_json,
                ),
            )
            return AsyncHttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def create_with_mrn(
        self,
        *,
        request: MutablePatientWithMrn,
        skip_duplicate_check: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Patient]:
        """
        Adds a patient and hydrates their MRN with a pre-existing MRN.  Once this patient is created their MRN will not be editable. BadRequestError is returned when the MRN is greater than 20 characters. VersionConflictError is returned when the patient's external ID is already in use.

        Parameters
        ----------
        request : MutablePatientWithMrn

        skip_duplicate_check : typing.Optional[bool]

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

        Returns
        -------
        AsyncHttpResponse[Patient]
        """
        _response = await self._client_wrapper.httpx_client.request(
            "patients/v1/with_mrn",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="POST",
            params={
                "skip_duplicate_check": skip_duplicate_check,
            },
            json=request,
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                Patient,
                parse_obj_as(
                    type_=Patient,  # type: ignore
                    object_=_response_json,
                ),
            )
            return AsyncHttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
            if _response_json["errorName"] == "BadRequestError":
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_multi(
        self,
        *,
        limit: typing.Optional[int] = None,
        mrn: typing.Optional[str] = None,
        page_token: typing.Optional[PageToken] = None,
        sort_field: typing.Optional[PatientSortField] = None,
        sort_direction: typing.Optional[SortDirection] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[PatientPage]:
        """
        Searches for patients that match the query parameters.

        Parameters
        ----------
        limit : typing.Optional[int]

        mrn : typing.Optional[str]

        page_token : typing.Optional[PageToken]

        sort_field : typing.Optional[PatientSortField]

        sort_direction : typing.Optional[SortDirection]
            Defaults to ascending.

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

        Returns
        -------
        AsyncHttpResponse[PatientPage]
        """
        _response = await self._client_wrapper.httpx_client.request(
            "patients/v1/get_multi",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            params={
                "limit": limit,
                "mrn": mrn,
                "page_token": page_token,
                "sort_field": sort_field,
                "sort_direction": sort_direction,
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                PatientPage,
                parse_obj_as(
                    type_=PatientPage,  # type: ignore
                    object_=_response_json,
                ),
            )
            return AsyncHttpResponse(response=_response, data=_data)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def search_providers(
        self, *, search_criteria: str, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[typing.List[ExternalProvider]]:
        """
        Searches for referring providers that match the query parameters.  The search is case-insensitive, supports fuzzy matching, and matches against provider name and NPI. The search criteria must be an alphanumeric string, and the search is limited to the first 20 results.

        Parameters
        ----------
        search_criteria : str

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

        Returns
        -------
        AsyncHttpResponse[typing.List[ExternalProvider]]
        """
        _response = await self._client_wrapper.httpx_client.request(
            "patients/v1/search_providers",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            params={
                "search_criteria": search_criteria,
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                typing.List[ExternalProvider],
                parse_obj_as(
                    type_=typing.List[ExternalProvider],  # type: ignore
                    object_=_response_json,
                ),
            )
            return AsyncHttpResponse(response=_response, data=_data)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get(
        self, id: PatientId, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[Patient]:
        """
        Gets a patient.

        Parameters
        ----------
        id : PatientId

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

        Returns
        -------
        AsyncHttpResponse[Patient]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                Patient,
                parse_obj_as(
                    type_=Patient,  # type: ignore
                    object_=_response_json,
                ),
            )
            return AsyncHttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_history(
        self, id: PatientId, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[typing.List[Patient]]:
        """
        Gets a patient along with it's full history.  The return list is ordered by version ascending.

        Parameters
        ----------
        id : PatientId

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

        Returns
        -------
        AsyncHttpResponse[typing.List[Patient]]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}/history",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                typing.List[Patient],
                parse_obj_as(
                    type_=typing.List[Patient],  # type: ignore
                    object_=_response_json,
                ),
            )
            return AsyncHttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def update(
        self,
        id: PatientId,
        version: str,
        *,
        request: MutablePatient,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Patient]:
        """
        Updates a patient.  The path must contain the most recent version to prevent race conditions.  Updating historic versions is not supported.

        Parameters
        ----------
        id : PatientId

        version : str

        request : MutablePatient

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

        Returns
        -------
        AsyncHttpResponse[Patient]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}/{jsonable_encoder(version)}",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="PUT",
            json=request,
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                Patient,
                parse_obj_as(
                    type_=Patient,  # type: ignore
                    object_=_response_json,
                ),
            )
            return AsyncHttpResponse(response=_response, data=_data)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def deactivate(
        self, id: PatientId, version: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[None]:
        """
        Sets a patient as deactivated.  The path must contain the most recent version plus 1 to prevent race conditions.  Deactivating historic versions is not supported.

        Parameters
        ----------
        id : PatientId

        version : str

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

        Returns
        -------
        AsyncHttpResponse[None]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}/{jsonable_encoder(version)}",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="DELETE",
            request_options=request_options,
        )
        if 200 <= _response.status_code < 300:
            return AsyncHttpResponse(response=_response, data=None)
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def reactivate(
        self, id: PatientId, version: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[None]:
        """
        Removes the deactivated flag for a patient.  The path must contain the most recent version plus 1 to prevent race conditions.  Reactivating historic versions is not supported.

        Parameters
        ----------
        id : PatientId

        version : str

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

        Returns
        -------
        AsyncHttpResponse[None]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"patients/v1/{jsonable_encoder(id)}/{jsonable_encoder(version)}",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="PATCH",
            request_options=request_options,
        )
        if 200 <= _response.status_code < 300:
            return AsyncHttpResponse(response=_response, data=None)
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "NotFoundError":
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ErrorBase4Xx,
                        parse_obj_as(
                            type_=ErrorBase4Xx,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
            if _response_json["errorName"] == "VersionConflictError":
                raise VersionConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        VersionConflictErrorBody,
                        parse_obj_as(
                            type_=VersionConflictErrorBody,  # type: ignore
                            object_=_response_json["content"],
                        ),
                    ),
                )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def search(
        self,
        *,
        mrn: typing.Optional[str] = None,
        similar_name_ordering: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[typing.List[Patient]]:
        """
        Returns a list of Patients based on the search criteria.

        Parameters
        ----------
        mrn : typing.Optional[str]

        similar_name_ordering : typing.Optional[str]
            A string that is used to order similar names in search results.

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

        Returns
        -------
        AsyncHttpResponse[typing.List[Patient]]
        """
        _response = await self._client_wrapper.httpx_client.request(
            "patients/v1",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            params={
                "mrn": mrn,
                "similar_name_ordering": similar_name_ordering,
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                typing.List[Patient],
                parse_obj_as(
                    type_=typing.List[Patient],  # type: ignore
                    object_=_response_json,
                ),
            )
            return AsyncHttpResponse(response=_response, data=_data)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def scan(
        self, *, since: dt.datetime, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[typing.List[Patient]]:
        """
        Scans up to 100 patient updates.  The since query parameter is inclusive, and the result list is ordered by updatedAt ascending.

        Parameters
        ----------
        since : dt.datetime

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

        Returns
        -------
        AsyncHttpResponse[typing.List[Patient]]
        """
        _response = await self._client_wrapper.httpx_client.request(
            "patients/v1/updates/scan",
            base_url=self._client_wrapper.get_environment().pre_encounter,
            method="GET",
            params={
                "since": serialize_datetime(since),
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        if 200 <= _response.status_code < 300:
            _data = typing.cast(
                typing.List[Patient],
                parse_obj_as(
                    type_=typing.List[Patient],  # type: ignore
                    object_=_response_json,
                ),
            )
            return AsyncHttpResponse(response=_response, data=_data)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
