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

from __future__ import annotations

import os
import typing

import httpx
from .core.api_error import ApiError
from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from .core.logging import LogConfig, Logger
from .core.oauth_token_provider import AsyncOAuthTokenProvider, OAuthTokenProvider
from .environment import PhenomlClientEnvironment

if typing.TYPE_CHECKING:
    from .agent.client import AgentClient, AsyncAgentClient
    from .authtoken.client import AsyncAuthtokenClient, AuthtokenClient
    from .cohort.client import AsyncCohortClient, CohortClient
    from .construe.client import AsyncConstrueClient, ConstrueClient
    from .fhir.client import AsyncFhirClient, FhirClient
    from .fhir_provider.client import AsyncFhirProviderClient, FhirProviderClient
    from .lang2fhir.client import AsyncLang2FhirClient, Lang2FhirClient
    from .summary.client import AsyncSummaryClient, SummaryClient
    from .tools.client import AsyncToolsClient, ToolsClient
    from .workflows.client import AsyncWorkflowsClient, WorkflowsClient


class PhenomlClient:
    """
    Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.

    Parameters
    ----------

    base_url : typing.Optional[str]
        The base url to use for requests from the client.

    client_id : str
        The client identifier used for authentication.

    client_secret : str
        The client secret used for authentication.

    timeout : typing.Optional[float]
        The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.

    follow_redirects : typing.Optional[bool]
        Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.

    httpx_client : typing.Optional[httpx.Client]
        The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.

    # or ...

    base_url : typing.Optional[str]
        The base url to use for requests from the client.

    token : typing.Callable[[], str]
        Authenticate by providing a callable that returns a pre-generated bearer token. In this mode, OAuth client credentials are not required.

    timeout : typing.Optional[float]
        The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.

    follow_redirects : typing.Optional[bool]
        Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.

    httpx_client : typing.Optional[httpx.Client]
        The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.

    Examples
    --------
    from phenoml import PhenomlClient

    client = PhenomlClient()

    # or ...

    from phenoml import PhenomlClient

    client = PhenomlClient(
        base_url="https://yourhost.com/path/to/api",
        token="YOUR_BEARER_TOKEN",
    )
    """

    @typing.overload
    def __init__(
        self,
        *,
        base_url: typing.Optional[str] = None,
        environment: PhenomlClientEnvironment = PhenomlClientEnvironment.DEFAULT,
        instance_url: typing.Optional[str] = None,
        headers: typing.Optional[typing.Dict[str, str]] = None,
        timeout: typing.Optional[float] = None,
        follow_redirects: typing.Optional[bool] = True,
        httpx_client: typing.Optional[httpx.Client] = None,
        logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
        client_id: typing.Optional[str] = os.getenv("PHENOML_CLIENT_ID"),
        client_secret: typing.Optional[str] = os.getenv("PHENOML_CLIENT_SECRET"),
    ): ...
    @typing.overload
    def __init__(
        self,
        *,
        base_url: typing.Optional[str] = None,
        environment: PhenomlClientEnvironment = PhenomlClientEnvironment.DEFAULT,
        instance_url: typing.Optional[str] = None,
        headers: typing.Optional[typing.Dict[str, str]] = None,
        timeout: typing.Optional[float] = None,
        follow_redirects: typing.Optional[bool] = True,
        httpx_client: typing.Optional[httpx.Client] = None,
        logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
        token: typing.Callable[[], str],
    ): ...
    def __init__(
        self,
        *,
        base_url: typing.Optional[str] = None,
        environment: PhenomlClientEnvironment = PhenomlClientEnvironment.DEFAULT,
        instance_url: typing.Optional[str] = None,
        headers: typing.Optional[typing.Dict[str, str]] = None,
        client_id: typing.Optional[str] = os.getenv("PHENOML_CLIENT_ID"),
        client_secret: typing.Optional[str] = os.getenv("PHENOML_CLIENT_SECRET"),
        token: typing.Optional[typing.Callable[[], str]] = None,
        _token_getter_override: typing.Optional[typing.Callable[[], str]] = None,
        timeout: typing.Optional[float] = None,
        follow_redirects: typing.Optional[bool] = True,
        httpx_client: typing.Optional[httpx.Client] = None,
        logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
    ):
        _defaulted_timeout = (
            timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
        )
        if instance_url is not None:
            _instance_url = instance_url if instance_url is not None else "experiment.app.pheno.ml"
            base_url = "https://{instanceUrl}".format(instanceUrl=_instance_url)
        if token is not None:
            self._client_wrapper = SyncClientWrapper(
                base_url=_get_base_url(base_url=base_url, environment=environment),
                headers=headers,
                httpx_client=httpx_client
                if httpx_client is not None
                else httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
                if follow_redirects is not None
                else httpx.Client(timeout=_defaulted_timeout),
                timeout=_defaulted_timeout,
                logging=logging,
                token=_token_getter_override if _token_getter_override is not None else token,
            )
        elif client_id is not None and client_secret is not None:
            oauth_token_provider = OAuthTokenProvider(
                client_id=client_id,
                client_secret=client_secret,
                client_wrapper=SyncClientWrapper(
                    base_url=_get_base_url(base_url=base_url, environment=environment),
                    headers=headers,
                    httpx_client=httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
                    if follow_redirects is not None
                    else httpx.Client(timeout=_defaulted_timeout),
                    timeout=_defaulted_timeout,
                    logging=logging,
                ),
            )
            self._client_wrapper = SyncClientWrapper(
                base_url=_get_base_url(base_url=base_url, environment=environment),
                headers=headers,
                token=_token_getter_override if _token_getter_override is not None else oauth_token_provider.get_token,
                httpx_client=httpx_client
                if httpx_client is not None
                else httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
                if follow_redirects is not None
                else httpx.Client(timeout=_defaulted_timeout),
                timeout=_defaulted_timeout,
                logging=logging,
            )
        else:
            raise ApiError(
                body="The client must be instantiated with either 'token' or both 'client_id' and 'client_secret'"
            )
        self._agent: typing.Optional[AgentClient] = None
        self._authtoken: typing.Optional[AuthtokenClient] = None
        self._cohort: typing.Optional[CohortClient] = None
        self._construe: typing.Optional[ConstrueClient] = None
        self._fhir: typing.Optional[FhirClient] = None
        self._fhir_provider: typing.Optional[FhirProviderClient] = None
        self._lang2fhir: typing.Optional[Lang2FhirClient] = None
        self._summary: typing.Optional[SummaryClient] = None
        self._tools: typing.Optional[ToolsClient] = None
        self._workflows: typing.Optional[WorkflowsClient] = None

    @property
    def agent(self):
        if self._agent is None:
            from .agent.client import AgentClient  # noqa: E402

            self._agent = AgentClient(client_wrapper=self._client_wrapper)
        return self._agent

    @property
    def authtoken(self):
        if self._authtoken is None:
            from .authtoken.client import AuthtokenClient  # noqa: E402

            self._authtoken = AuthtokenClient(client_wrapper=self._client_wrapper)
        return self._authtoken

    @property
    def cohort(self):
        if self._cohort is None:
            from .cohort.client import CohortClient  # noqa: E402

            self._cohort = CohortClient(client_wrapper=self._client_wrapper)
        return self._cohort

    @property
    def construe(self):
        if self._construe is None:
            from .construe.client import ConstrueClient  # noqa: E402

            self._construe = ConstrueClient(client_wrapper=self._client_wrapper)
        return self._construe

    @property
    def fhir(self):
        if self._fhir is None:
            from .fhir.client import FhirClient  # noqa: E402

            self._fhir = FhirClient(client_wrapper=self._client_wrapper)
        return self._fhir

    @property
    def fhir_provider(self):
        if self._fhir_provider is None:
            from .fhir_provider.client import FhirProviderClient  # noqa: E402

            self._fhir_provider = FhirProviderClient(client_wrapper=self._client_wrapper)
        return self._fhir_provider

    @property
    def lang2fhir(self):
        if self._lang2fhir is None:
            from .lang2fhir.client import Lang2FhirClient  # noqa: E402

            self._lang2fhir = Lang2FhirClient(client_wrapper=self._client_wrapper)
        return self._lang2fhir

    @property
    def summary(self):
        if self._summary is None:
            from .summary.client import SummaryClient  # noqa: E402

            self._summary = SummaryClient(client_wrapper=self._client_wrapper)
        return self._summary

    @property
    def tools(self):
        if self._tools is None:
            from .tools.client import ToolsClient  # noqa: E402

            self._tools = ToolsClient(client_wrapper=self._client_wrapper)
        return self._tools

    @property
    def workflows(self):
        if self._workflows is None:
            from .workflows.client import WorkflowsClient  # noqa: E402

            self._workflows = WorkflowsClient(client_wrapper=self._client_wrapper)
        return self._workflows


class AsyncPhenomlClient:
    """
    Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.

    Parameters
    ----------

    base_url : typing.Optional[str]
        The base url to use for requests from the client.

    client_id : str
        The client identifier used for authentication.

    client_secret : str
        The client secret used for authentication.

    timeout : typing.Optional[float]
        The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.

    follow_redirects : typing.Optional[bool]
        Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.

    httpx_client : typing.Optional[httpx.AsyncClient]
        The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.

    # or ...

    base_url : typing.Optional[str]
        The base url to use for requests from the client.

    token : typing.Callable[[], str]
        Authenticate by providing a callable that returns a pre-generated bearer token. In this mode, OAuth client credentials are not required.

    timeout : typing.Optional[float]
        The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.

    follow_redirects : typing.Optional[bool]
        Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.

    httpx_client : typing.Optional[httpx.AsyncClient]
        The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.

    Examples
    --------
    from phenoml import AsyncPhenomlClient

    client = AsyncPhenomlClient()

    # or ...

    from phenoml import AsyncPhenomlClient

    client = AsyncPhenomlClient(
        base_url="https://yourhost.com/path/to/api",
        token="YOUR_BEARER_TOKEN",
    )
    """

    @typing.overload
    def __init__(
        self,
        *,
        base_url: typing.Optional[str] = None,
        environment: PhenomlClientEnvironment = PhenomlClientEnvironment.DEFAULT,
        instance_url: typing.Optional[str] = None,
        headers: typing.Optional[typing.Dict[str, str]] = None,
        timeout: typing.Optional[float] = None,
        follow_redirects: typing.Optional[bool] = True,
        httpx_client: typing.Optional[httpx.AsyncClient] = None,
        logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
        client_id: typing.Optional[str] = os.getenv("PHENOML_CLIENT_ID"),
        client_secret: typing.Optional[str] = os.getenv("PHENOML_CLIENT_SECRET"),
    ): ...
    @typing.overload
    def __init__(
        self,
        *,
        base_url: typing.Optional[str] = None,
        environment: PhenomlClientEnvironment = PhenomlClientEnvironment.DEFAULT,
        instance_url: typing.Optional[str] = None,
        headers: typing.Optional[typing.Dict[str, str]] = None,
        timeout: typing.Optional[float] = None,
        follow_redirects: typing.Optional[bool] = True,
        httpx_client: typing.Optional[httpx.AsyncClient] = None,
        logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
        token: typing.Callable[[], str],
    ): ...
    def __init__(
        self,
        *,
        base_url: typing.Optional[str] = None,
        environment: PhenomlClientEnvironment = PhenomlClientEnvironment.DEFAULT,
        instance_url: typing.Optional[str] = None,
        headers: typing.Optional[typing.Dict[str, str]] = None,
        client_id: typing.Optional[str] = os.getenv("PHENOML_CLIENT_ID"),
        client_secret: typing.Optional[str] = os.getenv("PHENOML_CLIENT_SECRET"),
        token: typing.Optional[typing.Callable[[], str]] = None,
        _token_getter_override: typing.Optional[typing.Callable[[], str]] = None,
        timeout: typing.Optional[float] = None,
        follow_redirects: typing.Optional[bool] = True,
        httpx_client: typing.Optional[httpx.AsyncClient] = None,
        logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
    ):
        _defaulted_timeout = (
            timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
        )
        if instance_url is not None:
            _instance_url = instance_url if instance_url is not None else "experiment.app.pheno.ml"
            base_url = "https://{instanceUrl}".format(instanceUrl=_instance_url)
        if token is not None:
            self._client_wrapper = AsyncClientWrapper(
                base_url=_get_base_url(base_url=base_url, environment=environment),
                headers=headers,
                httpx_client=httpx_client
                if httpx_client is not None
                else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
                if follow_redirects is not None
                else httpx.AsyncClient(timeout=_defaulted_timeout),
                timeout=_defaulted_timeout,
                logging=logging,
                token=_token_getter_override if _token_getter_override is not None else token,
            )
        elif client_id is not None and client_secret is not None:
            oauth_token_provider = AsyncOAuthTokenProvider(
                client_id=client_id,
                client_secret=client_secret,
                client_wrapper=AsyncClientWrapper(
                    base_url=_get_base_url(base_url=base_url, environment=environment),
                    headers=headers,
                    httpx_client=httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
                    if follow_redirects is not None
                    else httpx.AsyncClient(timeout=_defaulted_timeout),
                    timeout=_defaulted_timeout,
                    logging=logging,
                ),
            )
            self._client_wrapper = AsyncClientWrapper(
                base_url=_get_base_url(base_url=base_url, environment=environment),
                headers=headers,
                token=_token_getter_override,
                async_token=oauth_token_provider.get_token,
                httpx_client=httpx_client
                if httpx_client is not None
                else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
                if follow_redirects is not None
                else httpx.AsyncClient(timeout=_defaulted_timeout),
                timeout=_defaulted_timeout,
                logging=logging,
            )
        else:
            raise ApiError(
                body="The client must be instantiated with either 'token' or both 'client_id' and 'client_secret'"
            )
        self._agent: typing.Optional[AsyncAgentClient] = None
        self._authtoken: typing.Optional[AsyncAuthtokenClient] = None
        self._cohort: typing.Optional[AsyncCohortClient] = None
        self._construe: typing.Optional[AsyncConstrueClient] = None
        self._fhir: typing.Optional[AsyncFhirClient] = None
        self._fhir_provider: typing.Optional[AsyncFhirProviderClient] = None
        self._lang2fhir: typing.Optional[AsyncLang2FhirClient] = None
        self._summary: typing.Optional[AsyncSummaryClient] = None
        self._tools: typing.Optional[AsyncToolsClient] = None
        self._workflows: typing.Optional[AsyncWorkflowsClient] = None

    @property
    def agent(self):
        if self._agent is None:
            from .agent.client import AsyncAgentClient  # noqa: E402

            self._agent = AsyncAgentClient(client_wrapper=self._client_wrapper)
        return self._agent

    @property
    def authtoken(self):
        if self._authtoken is None:
            from .authtoken.client import AsyncAuthtokenClient  # noqa: E402

            self._authtoken = AsyncAuthtokenClient(client_wrapper=self._client_wrapper)
        return self._authtoken

    @property
    def cohort(self):
        if self._cohort is None:
            from .cohort.client import AsyncCohortClient  # noqa: E402

            self._cohort = AsyncCohortClient(client_wrapper=self._client_wrapper)
        return self._cohort

    @property
    def construe(self):
        if self._construe is None:
            from .construe.client import AsyncConstrueClient  # noqa: E402

            self._construe = AsyncConstrueClient(client_wrapper=self._client_wrapper)
        return self._construe

    @property
    def fhir(self):
        if self._fhir is None:
            from .fhir.client import AsyncFhirClient  # noqa: E402

            self._fhir = AsyncFhirClient(client_wrapper=self._client_wrapper)
        return self._fhir

    @property
    def fhir_provider(self):
        if self._fhir_provider is None:
            from .fhir_provider.client import AsyncFhirProviderClient  # noqa: E402

            self._fhir_provider = AsyncFhirProviderClient(client_wrapper=self._client_wrapper)
        return self._fhir_provider

    @property
    def lang2fhir(self):
        if self._lang2fhir is None:
            from .lang2fhir.client import AsyncLang2FhirClient  # noqa: E402

            self._lang2fhir = AsyncLang2FhirClient(client_wrapper=self._client_wrapper)
        return self._lang2fhir

    @property
    def summary(self):
        if self._summary is None:
            from .summary.client import AsyncSummaryClient  # noqa: E402

            self._summary = AsyncSummaryClient(client_wrapper=self._client_wrapper)
        return self._summary

    @property
    def tools(self):
        if self._tools is None:
            from .tools.client import AsyncToolsClient  # noqa: E402

            self._tools = AsyncToolsClient(client_wrapper=self._client_wrapper)
        return self._tools

    @property
    def workflows(self):
        if self._workflows is None:
            from .workflows.client import AsyncWorkflowsClient  # noqa: E402

            self._workflows = AsyncWorkflowsClient(client_wrapper=self._client_wrapper)
        return self._workflows


def _get_base_url(*, base_url: typing.Optional[str] = None, environment: PhenomlClientEnvironment) -> str:
    if base_url is not None:
        return base_url
    elif environment is not None:
        return environment.value
    else:
        raise Exception("Please pass in either base_url or environment to construct the client")
