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

import typing
from json.decoder import JSONDecodeError

from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ...core.http_response import AsyncHttpResponse, HttpResponse
from ...core.jsonable_encoder import encode_path_param
from ...core.parse_error import ParsingError
from ...core.pydantic_utilities import parse_obj_as
from ...core.request_options import RequestOptions
from ...core.serialization import convert_and_respect_annotation_metadata
from ...errors.bad_request_error import BadRequestError
from ...errors.conflict_error import ConflictError
from ...errors.forbidden_error import ForbiddenError
from ...errors.too_many_requests_error import TooManyRequestsError
from ...errors.unauthorized_error import UnauthorizedError
from ...types.delete_user_identity_response_content import DeleteUserIdentityResponseContent
from ...types.user_id import UserId
from ...types.user_identity import UserIdentity
from ...types.user_identity_provider_enum import UserIdentityProviderEnum
from pydantic import ValidationError

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


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

    def link(
        self,
        id: str,
        *,
        provider: typing.Optional[UserIdentityProviderEnum] = OMIT,
        connection_id: typing.Optional[str] = OMIT,
        user_id: typing.Optional[UserId] = OMIT,
        link_with: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[typing.List[UserIdentity]]:
        """
        Link two user accounts together forming a primary and secondary relationship. On successful linking, the endpoint returns the new array of the primary account identities.

        Note: There are two ways of invoking the endpoint:

        - With the authenticated primary account's JWT in the Authorization header, which has the `update:current_user_identities` scope:

          ```http
          POST /api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities
          Authorization: "Bearer PRIMARY_ACCOUNT_JWT"
          {
            "link_with": "SECONDARY_ACCOUNT_JWT"
          }
          ```

          In this case, only the `link_with` param is required in the body, which also contains the JWT obtained upon the secondary account's authentication.

        - With a token generated by the API V2 containing the `update:users` scope:

          ```http
          POST /api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities
          Authorization: "Bearer YOUR_API_V2_TOKEN"
          {
            "provider": "SECONDARY_ACCOUNT_PROVIDER",
            "connection_id": "SECONDARY_ACCOUNT_CONNECTION_ID(OPTIONAL)",
            "user_id": "SECONDARY_ACCOUNT_USER_ID"
          }
          ```

          In this case you need to send `provider` and `user_id` in the body. Optionally you can also send the `connection_id` param which is suitable for identifying a particular database connection for the 'auth0' provider.

        Parameters
        ----------
        id : str
            ID of the primary user account to link a second user account to.

        provider : typing.Optional[UserIdentityProviderEnum]
            Identity provider of the secondary user account being linked.

        connection_id : typing.Optional[str]
            connection_id of the secondary user account being linked when more than one `auth0` database provider exists.

        user_id : typing.Optional[UserId]
            user_id of the secondary user account being linked.

        link_with : typing.Optional[str]
            JWT for the secondary account being linked. If sending this parameter, `provider`, `user_id`, and `connection_id` must not be sent.

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

        Returns
        -------
        HttpResponse[typing.List[UserIdentity]]
            Identity successfully added.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"users/{encode_path_param(id)}/identities",
            method="POST",
            json={
                "provider": provider,
                "connection_id": connection_id,
                "user_id": convert_and_respect_annotation_metadata(
                    object_=user_id, annotation=UserId, direction="write"
                ),
                "link_with": link_with,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.List[UserIdentity],
                    parse_obj_as(
                        type_=typing.List[UserIdentity],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 409:
                raise ConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 429:
                raise TooManyRequestsError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        except ValidationError as e:
            raise ParsingError(
                status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
            )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def delete(
        self,
        id: str,
        provider: UserIdentityProviderEnum,
        user_id: str,
        *,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[DeleteUserIdentityResponseContent]:
        """
        Unlink a specific secondary account from a target user. This action requires the ID of both the target user and the secondary account.

        Unlinking the secondary account removes it from the identities array of the target user and creates a new standalone profile for the secondary account. To learn more, review [Unlink User Accounts](https://auth0.com/docs/manage-users/user-accounts/user-account-linking/unlink-user-accounts).

        Parameters
        ----------
        id : str
            ID of the primary user account.

        provider : UserIdentityProviderEnum
            Identity provider name of the secondary linked account (e.g. `google-oauth2`).

        user_id : str
            ID of the secondary linked account (e.g. `123456789081523216417` part after the `|` in `google-oauth2|123456789081523216417`).

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

        Returns
        -------
        HttpResponse[DeleteUserIdentityResponseContent]
            User identity successfully unlinked.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"users/{encode_path_param(id)}/identities/{encode_path_param(provider)}/{encode_path_param(user_id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DeleteUserIdentityResponseContent,
                    parse_obj_as(
                        type_=DeleteUserIdentityResponseContent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 429:
                raise TooManyRequestsError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        except ValidationError as e:
            raise ParsingError(
                status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
            )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)


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

    async def link(
        self,
        id: str,
        *,
        provider: typing.Optional[UserIdentityProviderEnum] = OMIT,
        connection_id: typing.Optional[str] = OMIT,
        user_id: typing.Optional[UserId] = OMIT,
        link_with: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[typing.List[UserIdentity]]:
        """
        Link two user accounts together forming a primary and secondary relationship. On successful linking, the endpoint returns the new array of the primary account identities.

        Note: There are two ways of invoking the endpoint:

        - With the authenticated primary account's JWT in the Authorization header, which has the `update:current_user_identities` scope:

          ```http
          POST /api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities
          Authorization: "Bearer PRIMARY_ACCOUNT_JWT"
          {
            "link_with": "SECONDARY_ACCOUNT_JWT"
          }
          ```

          In this case, only the `link_with` param is required in the body, which also contains the JWT obtained upon the secondary account's authentication.

        - With a token generated by the API V2 containing the `update:users` scope:

          ```http
          POST /api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities
          Authorization: "Bearer YOUR_API_V2_TOKEN"
          {
            "provider": "SECONDARY_ACCOUNT_PROVIDER",
            "connection_id": "SECONDARY_ACCOUNT_CONNECTION_ID(OPTIONAL)",
            "user_id": "SECONDARY_ACCOUNT_USER_ID"
          }
          ```

          In this case you need to send `provider` and `user_id` in the body. Optionally you can also send the `connection_id` param which is suitable for identifying a particular database connection for the 'auth0' provider.

        Parameters
        ----------
        id : str
            ID of the primary user account to link a second user account to.

        provider : typing.Optional[UserIdentityProviderEnum]
            Identity provider of the secondary user account being linked.

        connection_id : typing.Optional[str]
            connection_id of the secondary user account being linked when more than one `auth0` database provider exists.

        user_id : typing.Optional[UserId]
            user_id of the secondary user account being linked.

        link_with : typing.Optional[str]
            JWT for the secondary account being linked. If sending this parameter, `provider`, `user_id`, and `connection_id` must not be sent.

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

        Returns
        -------
        AsyncHttpResponse[typing.List[UserIdentity]]
            Identity successfully added.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"users/{encode_path_param(id)}/identities",
            method="POST",
            json={
                "provider": provider,
                "connection_id": connection_id,
                "user_id": convert_and_respect_annotation_metadata(
                    object_=user_id, annotation=UserId, direction="write"
                ),
                "link_with": link_with,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.List[UserIdentity],
                    parse_obj_as(
                        type_=typing.List[UserIdentity],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 409:
                raise ConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 429:
                raise TooManyRequestsError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        except ValidationError as e:
            raise ParsingError(
                status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
            )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def delete(
        self,
        id: str,
        provider: UserIdentityProviderEnum,
        user_id: str,
        *,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[DeleteUserIdentityResponseContent]:
        """
        Unlink a specific secondary account from a target user. This action requires the ID of both the target user and the secondary account.

        Unlinking the secondary account removes it from the identities array of the target user and creates a new standalone profile for the secondary account. To learn more, review [Unlink User Accounts](https://auth0.com/docs/manage-users/user-accounts/user-account-linking/unlink-user-accounts).

        Parameters
        ----------
        id : str
            ID of the primary user account.

        provider : UserIdentityProviderEnum
            Identity provider name of the secondary linked account (e.g. `google-oauth2`).

        user_id : str
            ID of the secondary linked account (e.g. `123456789081523216417` part after the `|` in `google-oauth2|123456789081523216417`).

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

        Returns
        -------
        AsyncHttpResponse[DeleteUserIdentityResponseContent]
            User identity successfully unlinked.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"users/{encode_path_param(id)}/identities/{encode_path_param(provider)}/{encode_path_param(user_id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DeleteUserIdentityResponseContent,
                    parse_obj_as(
                        type_=DeleteUserIdentityResponseContent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 429:
                raise TooManyRequestsError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        except ValidationError as e:
            raise ParsingError(
                status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
            )
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
