# 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 jsonable_encoder
from ...core.request_options import RequestOptions
from ...core.unchecked_base_model import construct_type
from ...errors.forbidden_error import ForbiddenError
from ...errors.method_not_allowed_error import MethodNotAllowedError
from ...errors.not_found_error import NotFoundError
from ...types.lse_organization_member_list import LseOrganizationMemberList
from ...types.organization_member import OrganizationMember
from ...types.paginated_lse_organization_member_list_list import PaginatedLseOrganizationMemberListList
from ...types.role9e7enum import Role9E7Enum

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


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

    def list(
        self,
        id: int,
        *,
        contributed_to_projects: typing.Optional[bool] = None,
        exclude_project_id: typing.Optional[int] = None,
        exclude_workspace_id: typing.Optional[int] = None,
        ordering: typing.Optional[str] = None,
        page: typing.Optional[int] = None,
        page_size: typing.Optional[int] = None,
        role: typing.Optional[str] = None,
        search: typing.Optional[str] = None,
        tags: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[PaginatedLseOrganizationMemberListList]:
        """
        <Card href="https://humansignal.com/goenterprise">
                <img style="pointer-events: none; margin-left: 0px; margin-right: 0px;" src="https://docs.humansignal.com/images/badge.svg" alt="Label Studio Enterprise badge"/>
                <p style="margin-top: 10px; font-size: 14px;">
                    This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
                </p>
            </Card>
        Retrieve a list of all users and roles in a specific organization.

        Parameters
        ----------
        id : int
            A unique integer value identifying this organization.

        contributed_to_projects : typing.Optional[bool]
            Whether to include projects created and contributed to by the members.

        exclude_project_id : typing.Optional[int]
            Project ID to exclude users who are already associated with this project (direct members, workspace members, or implicit admin/owner access).

        exclude_workspace_id : typing.Optional[int]
            Workspace ID to exclude users who are already associated with this workspace (direct workspace members or implicit admin/owner access).

        ordering : typing.Optional[str]
            Which field to use when ordering the results.

        page : typing.Optional[int]
            A page number within the paginated result set.

        page_size : typing.Optional[int]
            Number of results to return per page.

        role : typing.Optional[str]
            Filter members by organization role. Accepts single role or comma-separated list of roles.

            **Format:**
            - Single role: `?role=RE`
            - Multiple roles: `?role=AN,RE` (users with ANY of these roles)

            **Role Codes:**
            - `OW` = Owner
            - `AD` = Administrator
            - `MA` = Manager
            - `RE` = Reviewer
            - `AN` = Annotator
            - `NO` = Not Activated
            - `DI` = Disabled

        search : typing.Optional[str]
            A search term.

        tags : typing.Optional[str]
            Filter members by tags. Use a comma-separated list of tag IDs.

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

        Returns
        -------
        HttpResponse[PaginatedLseOrganizationMemberListList]

        """
        _response = self._client_wrapper.httpx_client.request(
            f"api/organizations/{jsonable_encoder(id)}/memberships",
            method="GET",
            params={
                "contributed_to_projects": contributed_to_projects,
                "exclude_project_id": exclude_project_id,
                "exclude_workspace_id": exclude_workspace_id,
                "ordering": ordering,
                "page": page,
                "page_size": page_size,
                "role": role,
                "search": search,
                "tags": tags,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    PaginatedLseOrganizationMemberListList,
                    construct_type(
                        type_=PaginatedLseOrganizationMemberListList,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def update(
        self,
        id: int,
        *,
        role: typing.Optional[Role9E7Enum] = OMIT,
        user_id: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[LseOrganizationMemberList]:
        """
        <Card href="https://humansignal.com/goenterprise">
                <img style="pointer-events: none; margin-left: 0px; margin-right: 0px;" src="https://docs.humansignal.com/images/badge.svg" alt="Label Studio Enterprise badge"/>
                <p style="margin-top: 10px; font-size: 14px;">
                    This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
                </p>
            </Card>
        Update organization membership or role for a specific user ID.

        **User Rotation Best Practices for API Usage**

        To maintain compliance with our licensing terms and ensure optimal performance of HumanSignal's APIs, please consider the following guidelines when managing user assignments:

        * **Maintain a 7-Day Minimum Assignment**: Once a licensed seat is assigned to a user, maintain that assignment for at least seven consecutive days before rotating it to another user.

        * **Automate, Monitor, and Log Rotations**: Implement automated scheduling and logging mechanisms to track the timing of user rotations. This helps ensure that rotations adhere to the seven-day minimum period.

        * **Adhere to API Update Frequency and Wait Periods**: When updating user assignments via our APIs, follow the recommended frequency and wait period guidelines provided in the HumanSignal API documentation. Avoid sending rapid, successive requests that might overload the endpoint. Instead, incorporate appropriate delays between calls as specified in the documentation.

        * **Avoid Overloading the API Endpoint**: Design your integration to batch or schedule updates where possible, and implement backoff strategies if the API indicates rate limiting. This helps prevent service disruptions and ensures a smooth operation.

        Parameters
        ----------
        id : int
            A unique integer value identifying this organization.

        role : typing.Optional[Role9E7Enum]
            Organization role

            * `OW` - Owner
            * `AD` - Administrator
            * `MA` - Manager
            * `RE` - Reviewer
            * `AN` - Annotator
            * `DI` - Deactivated
            * `NO` - Not Activated

        user_id : typing.Optional[int]
            Member

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

        Returns
        -------
        HttpResponse[LseOrganizationMemberList]

        """
        _response = self._client_wrapper.httpx_client.request(
            f"api/organizations/{jsonable_encoder(id)}/memberships",
            method="PATCH",
            json={
                "role": role,
                "user_id": user_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    LseOrganizationMemberList,
                    construct_type(
                        type_=LseOrganizationMemberList,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get(
        self,
        id: int,
        user_pk: int,
        *,
        contributed_to_projects: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[OrganizationMember]:
        """
        Get organization member details by user ID.

        Parameters
        ----------
        id : int

        user_pk : int
            A unique integer value identifying the user to get organization details for.

        contributed_to_projects : typing.Optional[bool]
            Whether to include projects created and contributed to by the member.

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

        Returns
        -------
        HttpResponse[OrganizationMember]

        """
        _response = self._client_wrapper.httpx_client.request(
            f"api/organizations/{jsonable_encoder(id)}/memberships/{jsonable_encoder(user_pk)}/",
            method="GET",
            params={
                "contributed_to_projects": contributed_to_projects,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    OrganizationMember,
                    construct_type(
                        type_=OrganizationMember,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def delete(
        self, id: int, user_pk: int, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[None]:
        """
        Soft delete a member from the organization.

        Parameters
        ----------
        id : int

        user_pk : int
            A unique integer value identifying the user to be deleted from the organization.

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

        Returns
        -------
        HttpResponse[None]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"api/organizations/{jsonable_encoder(id)}/memberships/{jsonable_encoder(user_pk)}/",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return HttpResponse(response=_response, data=None)
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 405:
                raise MethodNotAllowedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)


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

    async def list(
        self,
        id: int,
        *,
        contributed_to_projects: typing.Optional[bool] = None,
        exclude_project_id: typing.Optional[int] = None,
        exclude_workspace_id: typing.Optional[int] = None,
        ordering: typing.Optional[str] = None,
        page: typing.Optional[int] = None,
        page_size: typing.Optional[int] = None,
        role: typing.Optional[str] = None,
        search: typing.Optional[str] = None,
        tags: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[PaginatedLseOrganizationMemberListList]:
        """
        <Card href="https://humansignal.com/goenterprise">
                <img style="pointer-events: none; margin-left: 0px; margin-right: 0px;" src="https://docs.humansignal.com/images/badge.svg" alt="Label Studio Enterprise badge"/>
                <p style="margin-top: 10px; font-size: 14px;">
                    This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
                </p>
            </Card>
        Retrieve a list of all users and roles in a specific organization.

        Parameters
        ----------
        id : int
            A unique integer value identifying this organization.

        contributed_to_projects : typing.Optional[bool]
            Whether to include projects created and contributed to by the members.

        exclude_project_id : typing.Optional[int]
            Project ID to exclude users who are already associated with this project (direct members, workspace members, or implicit admin/owner access).

        exclude_workspace_id : typing.Optional[int]
            Workspace ID to exclude users who are already associated with this workspace (direct workspace members or implicit admin/owner access).

        ordering : typing.Optional[str]
            Which field to use when ordering the results.

        page : typing.Optional[int]
            A page number within the paginated result set.

        page_size : typing.Optional[int]
            Number of results to return per page.

        role : typing.Optional[str]
            Filter members by organization role. Accepts single role or comma-separated list of roles.

            **Format:**
            - Single role: `?role=RE`
            - Multiple roles: `?role=AN,RE` (users with ANY of these roles)

            **Role Codes:**
            - `OW` = Owner
            - `AD` = Administrator
            - `MA` = Manager
            - `RE` = Reviewer
            - `AN` = Annotator
            - `NO` = Not Activated
            - `DI` = Disabled

        search : typing.Optional[str]
            A search term.

        tags : typing.Optional[str]
            Filter members by tags. Use a comma-separated list of tag IDs.

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

        Returns
        -------
        AsyncHttpResponse[PaginatedLseOrganizationMemberListList]

        """
        _response = await self._client_wrapper.httpx_client.request(
            f"api/organizations/{jsonable_encoder(id)}/memberships",
            method="GET",
            params={
                "contributed_to_projects": contributed_to_projects,
                "exclude_project_id": exclude_project_id,
                "exclude_workspace_id": exclude_workspace_id,
                "ordering": ordering,
                "page": page,
                "page_size": page_size,
                "role": role,
                "search": search,
                "tags": tags,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    PaginatedLseOrganizationMemberListList,
                    construct_type(
                        type_=PaginatedLseOrganizationMemberListList,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def update(
        self,
        id: int,
        *,
        role: typing.Optional[Role9E7Enum] = OMIT,
        user_id: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[LseOrganizationMemberList]:
        """
        <Card href="https://humansignal.com/goenterprise">
                <img style="pointer-events: none; margin-left: 0px; margin-right: 0px;" src="https://docs.humansignal.com/images/badge.svg" alt="Label Studio Enterprise badge"/>
                <p style="margin-top: 10px; font-size: 14px;">
                    This endpoint is not available in Label Studio Community Edition. [Learn more about Label Studio Enterprise](https://humansignal.com/goenterprise)
                </p>
            </Card>
        Update organization membership or role for a specific user ID.

        **User Rotation Best Practices for API Usage**

        To maintain compliance with our licensing terms and ensure optimal performance of HumanSignal's APIs, please consider the following guidelines when managing user assignments:

        * **Maintain a 7-Day Minimum Assignment**: Once a licensed seat is assigned to a user, maintain that assignment for at least seven consecutive days before rotating it to another user.

        * **Automate, Monitor, and Log Rotations**: Implement automated scheduling and logging mechanisms to track the timing of user rotations. This helps ensure that rotations adhere to the seven-day minimum period.

        * **Adhere to API Update Frequency and Wait Periods**: When updating user assignments via our APIs, follow the recommended frequency and wait period guidelines provided in the HumanSignal API documentation. Avoid sending rapid, successive requests that might overload the endpoint. Instead, incorporate appropriate delays between calls as specified in the documentation.

        * **Avoid Overloading the API Endpoint**: Design your integration to batch or schedule updates where possible, and implement backoff strategies if the API indicates rate limiting. This helps prevent service disruptions and ensures a smooth operation.

        Parameters
        ----------
        id : int
            A unique integer value identifying this organization.

        role : typing.Optional[Role9E7Enum]
            Organization role

            * `OW` - Owner
            * `AD` - Administrator
            * `MA` - Manager
            * `RE` - Reviewer
            * `AN` - Annotator
            * `DI` - Deactivated
            * `NO` - Not Activated

        user_id : typing.Optional[int]
            Member

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

        Returns
        -------
        AsyncHttpResponse[LseOrganizationMemberList]

        """
        _response = await self._client_wrapper.httpx_client.request(
            f"api/organizations/{jsonable_encoder(id)}/memberships",
            method="PATCH",
            json={
                "role": role,
                "user_id": user_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    LseOrganizationMemberList,
                    construct_type(
                        type_=LseOrganizationMemberList,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get(
        self,
        id: int,
        user_pk: int,
        *,
        contributed_to_projects: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[OrganizationMember]:
        """
        Get organization member details by user ID.

        Parameters
        ----------
        id : int

        user_pk : int
            A unique integer value identifying the user to get organization details for.

        contributed_to_projects : typing.Optional[bool]
            Whether to include projects created and contributed to by the member.

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

        Returns
        -------
        AsyncHttpResponse[OrganizationMember]

        """
        _response = await self._client_wrapper.httpx_client.request(
            f"api/organizations/{jsonable_encoder(id)}/memberships/{jsonable_encoder(user_pk)}/",
            method="GET",
            params={
                "contributed_to_projects": contributed_to_projects,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    OrganizationMember,
                    construct_type(
                        type_=OrganizationMember,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def delete(
        self, id: int, user_pk: int, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[None]:
        """
        Soft delete a member from the organization.

        Parameters
        ----------
        id : int

        user_pk : int
            A unique integer value identifying the user to be deleted from the organization.

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

        Returns
        -------
        AsyncHttpResponse[None]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"api/organizations/{jsonable_encoder(id)}/memberships/{jsonable_encoder(user_pk)}/",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return AsyncHttpResponse(response=_response, data=None)
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 405:
                raise MethodNotAllowedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
