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

import datetime as dt
import typing
import urllib.parse
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.jsonable_encoder import jsonable_encoder
from ...core.remove_none_from_dict import remove_none_from_dict
from ...errors.unprocessable_entity_error import UnprocessableEntityError
from ...types.auth_type import AuthType
from ...types.connection_status import ConnectionStatus
from ...types.demo_connection_status import DemoConnectionStatus
from ...types.demo_providers import DemoProviders
from ...types.email_providers import EmailProviders
from ...types.http_validation_error import HttpValidationError
from ...types.link_token_exchange_response import LinkTokenExchangeResponse
from ...types.manual_providers import ManualProviders
from ...types.o_auth_providers import OAuthProviders
from ...types.password_providers import PasswordProviders
from ...types.provider_link_response import ProviderLinkResponse
from ...types.providers import Providers
from ...types.region import Region
from ...types.source import Source
from ...types.source_link import SourceLink
from ...types.vital_token_created_response import VitalTokenCreatedResponse

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 LinkClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    def token(
        self,
        *,
        user_id: str,
        provider: typing.Optional[Providers] = OMIT,
        redirect_url: typing.Optional[str] = OMIT,
        filter_on_providers: typing.Optional[typing.List[Providers]] = OMIT,
    ) -> LinkTokenExchangeResponse:
        """
        Endpoint to generate a user link token, to be used throughout the vital
        link process. The vital link token is a one time use token, that
        expires after 10 minutes. If you would like vital-link widget to launch
        with a specific provider, pass in a provider in the body. If you would
        like to redirect to a custom url after successful or error connection,
        pass in your own custom redirect_url parameter.

        Parameters:
            - user_id: str. User id returned by vital create user request. This id should be stored in your database against the user and used for all interactions with the vital api.

            - provider: typing.Optional[Providers].

            - redirect_url: typing.Optional[str].

            - filter_on_providers: typing.Optional[typing.List[Providers]].
        """
        _request: typing.Dict[str, typing.Any] = {"user_id": user_id}
        if provider is not OMIT:
            _request["provider"] = provider.value if provider is not None else None
        if redirect_url is not OMIT:
            _request["redirect_url"] = redirect_url
        if filter_on_providers is not OMIT:
            _request["filter_on_providers"] = filter_on_providers
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/token"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(LinkTokenExchangeResponse, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def is_token_valid(
        self,
        *,
        token: str,
        is_used: typing.Optional[bool] = OMIT,
        oauth_info: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
    ) -> typing.Dict[str, typing.Any]:
        """
        Parameters:
            - token: str.

            - is_used: typing.Optional[bool].

            - oauth_info: typing.Optional[typing.Dict[str, typing.Any]].
        """
        _request: typing.Dict[str, typing.Any] = {"token": token}
        if is_used is not OMIT:
            _request["is_used"] = is_used if is_used is not None else None
        if oauth_info is not OMIT:
            _request["oauth_info"] = oauth_info
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/token/isValid"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.Dict[str, typing.Any], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def code_create(
        self, *, user_id: str, expires_at: typing.Optional[dt.datetime] = None
    ) -> VitalTokenCreatedResponse:
        """
        Generate a token to invite a user of Vital mobile app to your team

        Parameters:
            - user_id: str.

            - expires_at: typing.Optional[dt.datetime].
        """
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/code/create"),
            params=remove_none_from_dict(
                {"user_id": user_id, "expires_at": serialize_datetime(expires_at) if expires_at is not None else None}
            ),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(VitalTokenCreatedResponse, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def start_connect(self, *, link_token: str, provider: Providers) -> typing.Dict[str, typing.Any]:
        """
        REQUEST_SOURCE: VITAL-LINK
        Start link token process

        Parameters:
            - link_token: str.

            - provider: Providers.
        """
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/start"),
            json=jsonable_encoder({"link_token": link_token, "provider": provider}),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.Dict[str, typing.Any], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def token_state(self, *, vital_link_token: typing.Optional[str] = None) -> typing.Dict[str, typing.Any]:
        """
        REQUEST_SOURCE: VITAL-LINK
        Check link token state - can be hit continuously used as heartbeat

        Parameters:
            - vital_link_token: typing.Optional[str].
        ---
        from vital.client import Vital

        client = Vital(
            api_key="YOUR_API_KEY",
        )
        client.link.token_state()
        """
        _response = self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/state"),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.Dict[str, typing.Any], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def email_auth(
        self,
        *,
        email: str,
        provider: Providers,
        auth_type: AuthType,
        region: typing.Optional[Region] = OMIT,
        vital_link_token: typing.Optional[str] = None,
    ) -> ConnectionStatus:
        """
        REQUEST_SOURCE: VITAL-LINK
        PROVIDER_TYPE: EMAIL-AUTH
        This function is hit by vital-link to authenticate a email provider.

        Parameters:
            - email: str.

            - provider: Providers.

            - auth_type: AuthType.

            - region: typing.Optional[Region].

            - vital_link_token: typing.Optional[str].
        """
        _request: typing.Dict[str, typing.Any] = {
            "email": email,
            "provider": provider.value,
            "auth_type": auth_type.value,
        }
        if region is not OMIT:
            _request["region"] = region.value if region is not None else None
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/auth/email"),
            json=jsonable_encoder(_request),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ConnectionStatus, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def password_auth(
        self,
        *,
        username: str,
        password: str,
        provider: Providers,
        auth_type: AuthType,
        vital_link_client_region: typing.Optional[str] = None,
        vital_link_token: typing.Optional[str] = None,
    ) -> ConnectionStatus:
        """
        REQUEST_SOURCE: VITAL-LINK
        PROVIDER_TYPE: PASSWORD-AUTH
        This function is hit by vital-link to authenticate a password provider.

        Parameters:
            - username: str.

            - password: str.

            - provider: Providers.

            - auth_type: AuthType.

            - vital_link_client_region: typing.Optional[str].

            - vital_link_token: typing.Optional[str].
        """
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/auth"),
            json=jsonable_encoder(
                {"username": username, "password": password, "provider": provider, "auth_type": auth_type}
            ),
            headers=remove_none_from_dict(
                {
                    **self._client_wrapper.get_headers(),
                    "x-vital-link-client-region": vital_link_client_region,
                    "x-vital-link-token": vital_link_token,
                }
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ConnectionStatus, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def generate_oauth_link(
        self, oauth_provider: OAuthProviders, *, vital_link_token: typing.Optional[str] = None
    ) -> Source:
        """
        This endpoint generates an OAuth link for oauth provider

        Parameters:
            - oauth_provider: OAuthProviders.

            - vital_link_token: typing.Optional[str].
        """
        _response = self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"v2/link/provider/oauth/{oauth_provider}"),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(Source, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def connect_password_provider(
        self,
        provider: PasswordProviders,
        *,
        username: str,
        password: str,
        vital_link_client_region: typing.Optional[str] = None,
        vital_link_token: typing.Optional[str] = None,
    ) -> ProviderLinkResponse:
        """
        This connects auth providers that are password based.

        Parameters:
            - provider: PasswordProviders.

            - username: str. Username for provider

            - password: str. Password for provider

            - vital_link_client_region: typing.Optional[str].

            - vital_link_token: typing.Optional[str].
        """
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"v2/link/provider/password/{provider}"),
            json=jsonable_encoder({"username": username, "password": password}),
            headers=remove_none_from_dict(
                {
                    **self._client_wrapper.get_headers(),
                    "x-vital-link-client-region": vital_link_client_region,
                    "x-vital-link-token": vital_link_token,
                }
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ProviderLinkResponse, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def connect_email_auth_provider(
        self,
        provider: EmailProviders,
        *,
        email: str,
        email_provider_auth_link_provider: typing.Optional[Providers] = OMIT,
        region: typing.Optional[Region] = OMIT,
        vital_link_token: typing.Optional[str] = None,
    ) -> ConnectionStatus:
        """
        This connects auth providers that are email based.

        Parameters:
            - provider: EmailProviders.

            - email: str.

            - email_provider_auth_link_provider: typing.Optional[Providers].

            - region: typing.Optional[Region].

            - vital_link_token: typing.Optional[str].
        """
        _request: typing.Dict[str, typing.Any] = {"email": email}
        if email_provider_auth_link_provider is not OMIT:
            _request["provider"] = email_provider_auth_link_provider.value if email_provider_auth_link_provider is not None else None
        if region is not OMIT:
            _request["region"] = region.value if region is not None else None
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"v2/link/provider/email/{provider}"),
            json=jsonable_encoder(_request),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ConnectionStatus, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get_all_providers(self, *, vital_link_token: typing.Optional[str] = None) -> typing.List[SourceLink]:
        """
        GET List of all available providers given the generated link token.

        Parameters:
            - vital_link_token: typing.Optional[str].
        ---
        from vital.client import Vital

        client = Vital(
            api_key="YOUR_API_KEY",
        )
        client.link.get_all_providers()
        """
        _response = self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/providers"),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.List[SourceLink], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def connect_manual_provider(
        self, provider: ManualProviders, *, user_id: str, provider_id: typing.Optional[str] = OMIT
    ) -> typing.Dict[str, bool]:
        """
        REQUEST_SOURCE: CUSTOMER
        PROVIDER_TYPE: MANUAL-PROVIDER
        This connects auth providers that are password based.

        Parameters:
            - provider: ManualProviders.

            - user_id: str.

            - provider_id: typing.Optional[str].
        """
        _request: typing.Dict[str, typing.Any] = {"user_id": user_id}
        if provider_id is not OMIT:
            _request["provider_id"] = provider_id
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"v2/link/provider/manual/{provider}"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.Dict[str, bool], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def connect_demo_provider(self, *, user_id: str, provider: DemoProviders) -> DemoConnectionStatus:
        """
        POST Connect the given Vital user to a demo provider.

        Parameters:
            - user_id: str. Vital user ID

            - provider: DemoProviders. Demo provider. For more information, please check out our docs (https://docs.tryvital.io/wearables/providers/test_data)
        """
        _response = self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/connect/demo"),
            json=jsonable_encoder({"user_id": user_id, "provider": provider}),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(DemoConnectionStatus, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


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

    async def token(
        self,
        *,
        user_id: str,
        provider: typing.Optional[Providers] = OMIT,
        redirect_url: typing.Optional[str] = OMIT,
        filter_on_providers: typing.Optional[typing.List[Providers]] = OMIT,
    ) -> LinkTokenExchangeResponse:
        """
        Endpoint to generate a user link token, to be used throughout the vital
        link process. The vital link token is a one time use token, that
        expires after 10 minutes. If you would like vital-link widget to launch
        with a specific provider, pass in a provider in the body. If you would
        like to redirect to a custom url after successful or error connection,
        pass in your own custom redirect_url parameter.

        Parameters:
            - user_id: str. User id returned by vital create user request. This id should be stored in your database against the user and used for all interactions with the vital api.

            - provider: typing.Optional[Providers].

            - redirect_url: typing.Optional[str].

            - filter_on_providers: typing.Optional[typing.List[Providers]].
        """
        _request: typing.Dict[str, typing.Any] = {"user_id": user_id}
        if provider is not OMIT:
            _request["provider"] = provider.value if provider is not None else None
        if redirect_url is not OMIT:
            _request["redirect_url"] = redirect_url
        if filter_on_providers is not OMIT:
            _request["filter_on_providers"] = filter_on_providers
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/token"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(LinkTokenExchangeResponse, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def is_token_valid(
        self,
        *,
        token: str,
        is_used: typing.Optional[bool] = OMIT,
        oauth_info: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
    ) -> typing.Dict[str, typing.Any]:
        """
        Parameters:
            - token: str.

            - is_used: typing.Optional[bool].

            - oauth_info: typing.Optional[typing.Dict[str, typing.Any]].
        """
        _request: typing.Dict[str, typing.Any] = {"token": token}
        if is_used is not OMIT:
            _request["is_used"] = is_used
        if oauth_info is not OMIT:
            _request["oauth_info"] = oauth_info
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/token/isValid"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.Dict[str, typing.Any], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def code_create(
        self, *, user_id: str, expires_at: typing.Optional[dt.datetime] = None
    ) -> VitalTokenCreatedResponse:
        """
        Generate a token to invite a user of Vital mobile app to your team

        Parameters:
            - user_id: str.

            - expires_at: typing.Optional[dt.datetime].
        """
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/code/create"),
            params=remove_none_from_dict(
                {"user_id": user_id, "expires_at": serialize_datetime(expires_at) if expires_at is not None else None}
            ),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(VitalTokenCreatedResponse, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def start_connect(self, *, link_token: str, provider: Providers) -> typing.Dict[str, typing.Any]:
        """
        REQUEST_SOURCE: VITAL-LINK
        Start link token process

        Parameters:
            - link_token: str.

            - provider: Providers.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/start"),
            json=jsonable_encoder({"link_token": link_token, "provider": provider}),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.Dict[str, typing.Any], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def token_state(self, *, vital_link_token: typing.Optional[str] = None) -> typing.Dict[str, typing.Any]:
        """
        REQUEST_SOURCE: VITAL-LINK
        Check link token state - can be hit continuously used as heartbeat

        Parameters:
            - vital_link_token: typing.Optional[str].
        ---
        from vital.client import AsyncVital

        client = AsyncVital(
            api_key="YOUR_API_KEY",
        )
        await client.link.token_state()
        """
        _response = await self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/state"),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.Dict[str, typing.Any], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def email_auth(
        self,
        *,
        email: str,
        provider: Providers,
        auth_type: AuthType,
        region: typing.Optional[Region] = OMIT,
        vital_link_token: typing.Optional[str] = None,
    ) -> ConnectionStatus:
        """
        REQUEST_SOURCE: VITAL-LINK
        PROVIDER_TYPE: EMAIL-AUTH
        This function is hit by vital-link to authenticate a email provider.

        Parameters:
            - email: str.

            - provider: Providers.

            - auth_type: AuthType.

            - region: typing.Optional[Region].

            - vital_link_token: typing.Optional[str].
        """
        _request: typing.Dict[str, typing.Any] = {
            "email": email,
            "provider": provider.value,
            "auth_type": auth_type.value,
        }
        if region is not OMIT:
            _request["region"] = region.value if region is not None else None
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/auth/email"),
            json=jsonable_encoder(_request),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ConnectionStatus, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def password_auth(
        self,
        *,
        username: str,
        password: str,
        provider: Providers,
        auth_type: AuthType,
        vital_link_client_region: typing.Optional[str] = None,
        vital_link_token: typing.Optional[str] = None,
    ) -> ConnectionStatus:
        """
        REQUEST_SOURCE: VITAL-LINK
        PROVIDER_TYPE: PASSWORD-AUTH
        This function is hit by vital-link to authenticate a password provider.

        Parameters:
            - username: str.

            - password: str.

            - provider: Providers.

            - auth_type: AuthType.

            - vital_link_client_region: typing.Optional[str].

            - vital_link_token: typing.Optional[str].
        """
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/auth"),
            json=jsonable_encoder(
                {"username": username, "password": password, "provider": provider, "auth_type": auth_type}
            ),
            headers=remove_none_from_dict(
                {
                    **self._client_wrapper.get_headers(),
                    "x-vital-link-client-region": vital_link_client_region,
                    "x-vital-link-token": vital_link_token,
                }
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ConnectionStatus, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def generate_oauth_link(
        self, oauth_provider: OAuthProviders, *, vital_link_token: typing.Optional[str] = None
    ) -> Source:
        """
        This endpoint generates an OAuth link for oauth provider

        Parameters:
            - oauth_provider: OAuthProviders.

            - vital_link_token: typing.Optional[str].
        """
        _response = await self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"v2/link/provider/oauth/{oauth_provider}"),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(Source, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def connect_password_provider(
        self,
        provider: PasswordProviders,
        *,
        username: str,
        password: str,
        vital_link_client_region: typing.Optional[str] = None,
        vital_link_token: typing.Optional[str] = None,
    ) -> ProviderLinkResponse:
        """
        This connects auth providers that are password based.

        Parameters:
            - provider: PasswordProviders.

            - username: str. Username for provider

            - password: str. Password for provider

            - vital_link_client_region: typing.Optional[str].

            - vital_link_token: typing.Optional[str].
        """
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"v2/link/provider/password/{provider}"),
            json=jsonable_encoder({"username": username, "password": password}),
            headers=remove_none_from_dict(
                {
                    **self._client_wrapper.get_headers(),
                    "x-vital-link-client-region": vital_link_client_region,
                    "x-vital-link-token": vital_link_token,
                }
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ProviderLinkResponse, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def connect_email_auth_provider(
        self,
        provider: EmailProviders,
        *,
        email: str,
        email_provider_auth_link_provider: typing.Optional[Providers] = OMIT,
        region: typing.Optional[Region] = OMIT,
        vital_link_token: typing.Optional[str] = None,
    ) -> ConnectionStatus:
        """
        This connects auth providers that are email based.

        Parameters:
            - provider: EmailProviders.

            - email: str.

            - email_provider_auth_link_provider: typing.Optional[Providers].

            - region: typing.Optional[Region].

            - vital_link_token: typing.Optional[str].
        """
        _request: typing.Dict[str, typing.Any] = {"email": email}
        if email_provider_auth_link_provider is not OMIT:
            _request["provider"] = email_provider_auth_link_provider.value if email_provider_auth_link_provider is not None else None
        if region is not OMIT:
            _request["region"] = region.value if region is not None else None
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"v2/link/provider/email/{provider}"),
            json=jsonable_encoder(_request),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(ConnectionStatus, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get_all_providers(self, *, vital_link_token: typing.Optional[str] = None) -> typing.List[SourceLink]:
        """
        GET List of all available providers given the generated link token.

        Parameters:
            - vital_link_token: typing.Optional[str].
        ---
        from vital.client import AsyncVital

        client = AsyncVital(
            api_key="YOUR_API_KEY",
        )
        await client.link.get_all_providers()
        """
        _response = await self._client_wrapper.httpx_client.request(
            "GET",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/providers"),
            headers=remove_none_from_dict(
                {**self._client_wrapper.get_headers(), "x-vital-link-token": vital_link_token}
            ),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.List[SourceLink], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def connect_manual_provider(
        self, provider: ManualProviders, *, user_id: str, provider_id: typing.Optional[str] = OMIT
    ) -> typing.Dict[str, bool]:
        """
        REQUEST_SOURCE: CUSTOMER
        PROVIDER_TYPE: MANUAL-PROVIDER
        This connects auth providers that are password based.

        Parameters:
            - provider: ManualProviders.

            - user_id: str.

            - provider_id: typing.Optional[str].
        """
        _request: typing.Dict[str, typing.Any] = {"user_id": user_id}
        if provider_id is not OMIT:
            _request["provider_id"] = provider_id
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"v2/link/provider/manual/{provider}"),
            json=jsonable_encoder(_request),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(typing.Dict[str, bool], _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def connect_demo_provider(self, *, user_id: str, provider: DemoProviders) -> DemoConnectionStatus:
        """
        POST Connect the given Vital user to a demo provider.

        Parameters:
            - user_id: str. Vital user ID

            - provider: DemoProviders. Demo provider. For more information, please check out our docs (https://docs.tryvital.io/wearables/providers/test_data)
        """
        _response = await self._client_wrapper.httpx_client.request(
            "POST",
            urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v2/link/connect/demo"),
            json=jsonable_encoder({"user_id": user_id, "provider": provider}),
            headers=self._client_wrapper.get_headers(),
            timeout=60,
        )
        if 200 <= _response.status_code < 300:
            return pydantic.parse_obj_as(DemoConnectionStatus, _response.json())  # type: ignore
        if _response.status_code == 422:
            raise UnprocessableEntityError(pydantic.parse_obj_as(HttpValidationError, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
