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

import typing
import urllib.parse
import uuid
from json.decoder import JSONDecodeError

from .....core.api_error import ApiError
from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from .....core.jsonable_encoder import jsonable_encoder
from .....core.remove_none_from_dict import remove_none_from_dict
from ....commons.errors.entity_not_found_error import EntityNotFoundError
from ....commons.errors.unprocessable_entity_error import UnprocessableEntityError
from ....commons.types.date import Date
from ....commons.types.entity_not_found_error_message import EntityNotFoundErrorMessage
from ....commons.types.page_token import PageToken
from ....commons.types.regions import Regions
from ....commons.types.state import State
from ....commons.types.unprocessable_entity_error_message import UnprocessableEntityErrorMessage
from .errors.contract_is_linked_to_fee_schedule_http_error import ContractIsLinkedToFeeScheduleHttpError
from .types.authorized_signatory import AuthorizedSignatory
from .types.authorized_signatory_update import AuthorizedSignatoryUpdate
from .types.contract_id import ContractId
from .types.contract_is_linked_to_fee_schedule_error import ContractIsLinkedToFeeScheduleError
from .types.contract_status import ContractStatus
from .types.contract_with_providers import ContractWithProviders
from .types.contracting_provider_id import ContractingProviderId
from .types.contracts_page import ContractsPage
from .types.date_update import DateUpdate
from .types.insurance_types import InsuranceTypes
from .types.regions_update import RegionsUpdate
from .types.rendering_providerid import RenderingProviderid

try:
    import pydantic.v1 as pydantic  # type: ignore
except ImportError:
    import pydantic  # type: ignore

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


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

    def get(self, contract_id: ContractId) -> ContractWithProviders:
        """
        Parameters:
            - contract_id: ContractId.
        """
        _response = self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"api/contracts/v2/{contract_id}"),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ContractWithProviders, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "EntityNotFoundError":
                raise EntityNotFoundError(
                    pydantic.parse_obj_as(EntityNotFoundErrorMessage, _response_json["content"])  # type: ignore
                )
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get_multi(
        self,
        *,
        page_token: typing.Optional[PageToken] = None,
        limit: typing.Optional[int] = None,
        contracting_provider_id: typing.Optional[ContractingProviderId] = None,
        rendering_provider_ids: typing.Optional[
            typing.Union[RenderingProviderid, typing.List[RenderingProviderid]]
        ] = None,
        payer_names: typing.Optional[typing.Union[str, typing.List[str]]] = None,
        states: typing.Optional[typing.Union[State, typing.List[State]]] = None,
        contract_status: typing.Optional[ContractStatus] = None,
    ) -> ContractsPage:
        """
        Parameters:
            - page_token: typing.Optional[PageToken].

            - limit: typing.Optional[int]. Max number of contracts returned. Defaults to 1000. Max is 1000.

            - contracting_provider_id: typing.Optional[ContractingProviderId].

            - rendering_provider_ids: typing.Optional[typing.Union[RenderingProviderid, typing.List[RenderingProviderid]]].

            - payer_names: typing.Optional[typing.Union[str, typing.List[str]]]. Filter to contracts that include any of the included payer names.

            - states: typing.Optional[typing.Union[State, typing.List[State]]].

            - contract_status: typing.Optional[ContractStatus]. The status of the contract. Defaults to `pending`
        """
        _response = self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "api/contracts/v2"),
            params=remove_none_from_dict(
                {
                    "page_token": page_token,
                    "limit": limit,
                    "contracting_provider_id": jsonable_encoder(contracting_provider_id),
                    "rendering_provider_ids": jsonable_encoder(rendering_provider_ids),
                    "payer_names": payer_names,
                    "states": states,
                    "contract_status": contract_status,
                }
            ),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ContractsPage, _response_json)  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def create(
        self,
        *,
        contracting_provider_id: ContractingProviderId,
        rendering_provider_ids: typing.List[RenderingProviderid],
        payer_uuid: uuid.UUID,
        effective_date: Date,
        expiration_date: typing.Optional[Date] = OMIT,
        regions: Regions,
        contract_status: typing.Optional[ContractStatus] = OMIT,
        authorized_signatory: typing.Optional[AuthorizedSignatory] = OMIT,
        commercial_insurance_types: InsuranceTypes,
        medicare_insurance_types: InsuranceTypes,
        medicaid_insurance_types: InsuranceTypes,
    ) -> ContractWithProviders:
        """
        Creates a new contract within the user's current organization

        Parameters:
            - contracting_provider_id: ContractingProviderId. The UUID of the provider under agreement to the contract

            - rendering_provider_ids: typing.List[RenderingProviderid]. A rendering provider isn't contracted directly with the payer but can render
                                                                        services under the contract held by the contracting provider.
                                                                        Max items is 100.

            - payer_uuid: uuid.UUID. The UUID of the insurance company under agreement to the contract

            - effective_date: Date. The starting day upon which the contract is effective

            - expiration_date: typing.Optional[Date]. An optional end day upon which the contract expires

            - regions: Regions. The state(s) to which the contract's coverage extends.
                                It may also be set to "national" for the entirety of the US.
            - contract_status: typing.Optional[ContractStatus].

            - authorized_signatory: typing.Optional[AuthorizedSignatory].

            - commercial_insurance_types: InsuranceTypes. The commercial plan insurance types this contract applies.

            - medicare_insurance_types: InsuranceTypes. The Medicare plan insurance types this contract applies.

            - medicaid_insurance_types: InsuranceTypes. The Medicaid plan insurance types this contract applies.
        """
        _request: typing.Dict[str, typing.Any] = {
            "contracting_provider_id": contracting_provider_id,
            "rendering_provider_ids": rendering_provider_ids,
            "payer_uuid": payer_uuid,
            "effective_date": effective_date,
            "regions": regions,
            "commercial_insurance_types": commercial_insurance_types,
            "medicare_insurance_types": medicare_insurance_types,
            "medicaid_insurance_types": medicaid_insurance_types,
        }
        if expiration_date is not OMIT:
            _request["expiration_date"] = expiration_date
        if contract_status is not OMIT:
            _request["contract_status"] = contract_status
        if authorized_signatory is not OMIT:
            _request["authorized_signatory"] = authorized_signatory
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "api/contracts/v2"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ContractWithProviders, _response_json)  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def delete(self, contract_id: ContractId) -> None:
        """
        Parameters:
            - contract_id: ContractId.
        """
        _response = self._client_wrapper.httpx_client.request(
            "DELETE",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"api/contracts/v2/{contract_id}"),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "ContractIsLinkedToFeeScheduleHttpError":
                raise ContractIsLinkedToFeeScheduleHttpError(
                    pydantic.parse_obj_as(ContractIsLinkedToFeeScheduleError, _response_json["content"])  # type: ignore
                )
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def update(
        self,
        contract_id: ContractId,
        *,
        rendering_provider_ids: typing.Optional[typing.List[RenderingProviderid]] = OMIT,
        effective_date: typing.Optional[Date] = OMIT,
        expiration_date: typing.Optional[DateUpdate] = OMIT,
        regions: typing.Optional[RegionsUpdate] = OMIT,
        contract_status: typing.Optional[ContractStatus] = OMIT,
        authorized_signatory: typing.Optional[AuthorizedSignatoryUpdate] = OMIT,
        commercial_insurance_types: typing.Optional[InsuranceTypes] = OMIT,
        medicare_insurance_types: typing.Optional[InsuranceTypes] = OMIT,
        medicaid_insurance_types: typing.Optional[InsuranceTypes] = OMIT,
    ) -> ContractWithProviders:
        """
        Parameters:
            - contract_id: ContractId.

            - rendering_provider_ids: typing.Optional[typing.List[RenderingProviderid]]. A rendering provider isn't contracted directly with the payer but can render
                                                                                         services under the contract held by the contracting provider.
                                                                                         Max items is 100.

            - effective_date: typing.Optional[Date]. The starting day upon which the contract is effective

            - expiration_date: typing.Optional[DateUpdate]. An optional end day upon which the contract expires

            - regions: typing.Optional[RegionsUpdate]. If present, the contract's rendering providers will be patched to this exact
                                                       value, overriding what was set before.

            - contract_status: typing.Optional[ContractStatus].

            - authorized_signatory: typing.Optional[AuthorizedSignatoryUpdate].

            - commercial_insurance_types: typing.Optional[InsuranceTypes].

            - medicare_insurance_types: typing.Optional[InsuranceTypes].

            - medicaid_insurance_types: typing.Optional[InsuranceTypes].
        """
        _request: typing.Dict[str, typing.Any] = {}
        if rendering_provider_ids is not OMIT:
            _request["rendering_provider_ids"] = rendering_provider_ids
        if effective_date is not OMIT:
            _request["effective_date"] = effective_date
        if expiration_date is not OMIT:
            _request["expiration_date"] = expiration_date
        if regions is not OMIT:
            _request["regions"] = regions
        if contract_status is not OMIT:
            _request["contract_status"] = contract_status
        if authorized_signatory is not OMIT:
            _request["authorized_signatory"] = authorized_signatory
        if commercial_insurance_types is not OMIT:
            _request["commercial_insurance_types"] = commercial_insurance_types
        if medicare_insurance_types is not OMIT:
            _request["medicare_insurance_types"] = medicare_insurance_types
        if medicaid_insurance_types is not OMIT:
            _request["medicaid_insurance_types"] = medicaid_insurance_types
        _response = self._client_wrapper.httpx_client.request(
            "PATCH",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"api/contracts/v2/{contract_id}"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ContractWithProviders, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "UnprocessableEntityError":
                raise UnprocessableEntityError(
                    pydantic.parse_obj_as(UnprocessableEntityErrorMessage, _response_json["content"])  # type: ignore
                )
        raise ApiError(status_code=_response.status_code, body=_response_json)


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

    async def get(self, contract_id: ContractId) -> ContractWithProviders:
        """
        Parameters:
            - contract_id: ContractId.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"api/contracts/v2/{contract_id}"),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ContractWithProviders, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "EntityNotFoundError":
                raise EntityNotFoundError(
                    pydantic.parse_obj_as(EntityNotFoundErrorMessage, _response_json["content"])  # type: ignore
                )
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get_multi(
        self,
        *,
        page_token: typing.Optional[PageToken] = None,
        limit: typing.Optional[int] = None,
        contracting_provider_id: typing.Optional[ContractingProviderId] = None,
        rendering_provider_ids: typing.Optional[
            typing.Union[RenderingProviderid, typing.List[RenderingProviderid]]
        ] = None,
        payer_names: typing.Optional[typing.Union[str, typing.List[str]]] = None,
        states: typing.Optional[typing.Union[State, typing.List[State]]] = None,
        contract_status: typing.Optional[ContractStatus] = None,
    ) -> ContractsPage:
        """
        Parameters:
            - page_token: typing.Optional[PageToken].

            - limit: typing.Optional[int]. Max number of contracts returned. Defaults to 1000. Max is 1000.

            - contracting_provider_id: typing.Optional[ContractingProviderId].

            - rendering_provider_ids: typing.Optional[typing.Union[RenderingProviderid, typing.List[RenderingProviderid]]].

            - payer_names: typing.Optional[typing.Union[str, typing.List[str]]]. Filter to contracts that include any of the included payer names.

            - states: typing.Optional[typing.Union[State, typing.List[State]]].

            - contract_status: typing.Optional[ContractStatus]. The status of the contract. Defaults to `pending`
        """
        _response = await self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "api/contracts/v2"),
            params=remove_none_from_dict(
                {
                    "page_token": page_token,
                    "limit": limit,
                    "contracting_provider_id": jsonable_encoder(contracting_provider_id),
                    "rendering_provider_ids": jsonable_encoder(rendering_provider_ids),
                    "payer_names": payer_names,
                    "states": states,
                    "contract_status": contract_status,
                }
            ),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ContractsPage, _response_json)  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def create(
        self,
        *,
        contracting_provider_id: ContractingProviderId,
        rendering_provider_ids: typing.List[RenderingProviderid],
        payer_uuid: uuid.UUID,
        effective_date: Date,
        expiration_date: typing.Optional[Date] = OMIT,
        regions: Regions,
        contract_status: typing.Optional[ContractStatus] = OMIT,
        authorized_signatory: typing.Optional[AuthorizedSignatory] = OMIT,
        commercial_insurance_types: InsuranceTypes,
        medicare_insurance_types: InsuranceTypes,
        medicaid_insurance_types: InsuranceTypes,
    ) -> ContractWithProviders:
        """
        Creates a new contract within the user's current organization

        Parameters:
            - contracting_provider_id: ContractingProviderId. The UUID of the provider under agreement to the contract

            - rendering_provider_ids: typing.List[RenderingProviderid]. A rendering provider isn't contracted directly with the payer but can render
                                                                        services under the contract held by the contracting provider.
                                                                        Max items is 100.

            - payer_uuid: uuid.UUID. The UUID of the insurance company under agreement to the contract

            - effective_date: Date. The starting day upon which the contract is effective

            - expiration_date: typing.Optional[Date]. An optional end day upon which the contract expires

            - regions: Regions. The state(s) to which the contract's coverage extends.
                                It may also be set to "national" for the entirety of the US.
            - contract_status: typing.Optional[ContractStatus].

            - authorized_signatory: typing.Optional[AuthorizedSignatory].

            - commercial_insurance_types: InsuranceTypes. The commercial plan insurance types this contract applies.

            - medicare_insurance_types: InsuranceTypes. The Medicare plan insurance types this contract applies.

            - medicaid_insurance_types: InsuranceTypes. The Medicaid plan insurance types this contract applies.
        """
        _request: typing.Dict[str, typing.Any] = {
            "contracting_provider_id": contracting_provider_id,
            "rendering_provider_ids": rendering_provider_ids,
            "payer_uuid": payer_uuid,
            "effective_date": effective_date,
            "regions": regions,
            "commercial_insurance_types": commercial_insurance_types,
            "medicare_insurance_types": medicare_insurance_types,
            "medicaid_insurance_types": medicaid_insurance_types,
        }
        if expiration_date is not OMIT:
            _request["expiration_date"] = expiration_date
        if contract_status is not OMIT:
            _request["contract_status"] = contract_status
        if authorized_signatory is not OMIT:
            _request["authorized_signatory"] = authorized_signatory
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "api/contracts/v2"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ContractWithProviders, _response_json)  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def delete(self, contract_id: ContractId) -> None:
        """
        Parameters:
            - contract_id: ContractId.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "DELETE",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"api/contracts/v2/{contract_id}"),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "ContractIsLinkedToFeeScheduleHttpError":
                raise ContractIsLinkedToFeeScheduleHttpError(
                    pydantic.parse_obj_as(ContractIsLinkedToFeeScheduleError, _response_json["content"])  # type: ignore
                )
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def update(
        self,
        contract_id: ContractId,
        *,
        rendering_provider_ids: typing.Optional[typing.List[RenderingProviderid]] = OMIT,
        effective_date: typing.Optional[Date] = OMIT,
        expiration_date: typing.Optional[DateUpdate] = OMIT,
        regions: typing.Optional[RegionsUpdate] = OMIT,
        contract_status: typing.Optional[ContractStatus] = OMIT,
        authorized_signatory: typing.Optional[AuthorizedSignatoryUpdate] = OMIT,
        commercial_insurance_types: typing.Optional[InsuranceTypes] = OMIT,
        medicare_insurance_types: typing.Optional[InsuranceTypes] = OMIT,
        medicaid_insurance_types: typing.Optional[InsuranceTypes] = OMIT,
    ) -> ContractWithProviders:
        """
        Parameters:
            - contract_id: ContractId.

            - rendering_provider_ids: typing.Optional[typing.List[RenderingProviderid]]. A rendering provider isn't contracted directly with the payer but can render
                                                                                         services under the contract held by the contracting provider.
                                                                                         Max items is 100.

            - effective_date: typing.Optional[Date]. The starting day upon which the contract is effective

            - expiration_date: typing.Optional[DateUpdate]. An optional end day upon which the contract expires

            - regions: typing.Optional[RegionsUpdate]. If present, the contract's rendering providers will be patched to this exact
                                                       value, overriding what was set before.

            - contract_status: typing.Optional[ContractStatus].

            - authorized_signatory: typing.Optional[AuthorizedSignatoryUpdate].

            - commercial_insurance_types: typing.Optional[InsuranceTypes].

            - medicare_insurance_types: typing.Optional[InsuranceTypes].

            - medicaid_insurance_types: typing.Optional[InsuranceTypes].
        """
        _request: typing.Dict[str, typing.Any] = {}
        if rendering_provider_ids is not OMIT:
            _request["rendering_provider_ids"] = rendering_provider_ids
        if effective_date is not OMIT:
            _request["effective_date"] = effective_date
        if expiration_date is not OMIT:
            _request["expiration_date"] = expiration_date
        if regions is not OMIT:
            _request["regions"] = regions
        if contract_status is not OMIT:
            _request["contract_status"] = contract_status
        if authorized_signatory is not OMIT:
            _request["authorized_signatory"] = authorized_signatory
        if commercial_insurance_types is not OMIT:
            _request["commercial_insurance_types"] = commercial_insurance_types
        if medicare_insurance_types is not OMIT:
            _request["medicare_insurance_types"] = medicare_insurance_types
        if medicaid_insurance_types is not OMIT:
            _request["medicaid_insurance_types"] = medicaid_insurance_types
        _response = await self._client_wrapper.httpx_client.request(
            "PATCH",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"api/contracts/v2/{contract_id}"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ContractWithProviders, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "UnprocessableEntityError":
                raise UnprocessableEntityError(
                    pydantic.parse_obj_as(UnprocessableEntityErrorMessage, _response_json["content"])  # type: ignore
                )
        raise ApiError(status_code=_response.status_code, body=_response_json)
