# 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.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..errors.unprocessable_entity_error import UnprocessableEntityError
from ..types.bulk_operation_response import BulkOperationResponse
from ..types.member_list_response import MemberListResponse
from ..types.member_response import MemberResponse
from ..types.status_summary_response import StatusSummaryResponse

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


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

    def list_members(
        self,
        organization_id: str,
        *,
        skip: typing.Optional[int] = OMIT,
        take: typing.Optional[int] = OMIT,
        search_term: typing.Optional[str] = OMIT,
        role_id: typing.Optional[str] = OMIT,
        status_id: typing.Optional[str] = OMIT,
        sort_column: typing.Optional[str] = OMIT,
        sort_direction: typing.Optional[str] = OMIT,
        include_inactive: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[MemberListResponse]:
        """
        Get paginated list of organization members with filtering and sorting.

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            request: Pagination and filter parameters
            db: Database session
            auth: Authenticated user

        Returns:
            Paginated list of members with total count

        Parameters
        ----------
        organization_id : str
            Organization ID to list members from

        skip : typing.Optional[int]
            Number of records to skip

        take : typing.Optional[int]
            Number of records to return (max 500)

        search_term : typing.Optional[str]
            Search across full_name, email, and username

        role_id : typing.Optional[str]
            Filter by role ID

        status_id : typing.Optional[str]
            Filter by status ID

        sort_column : typing.Optional[str]
            Field to sort by (full_name, email, role, status, created_at, last_modified_at)

        sort_direction : typing.Optional[str]
            Sort direction (asc or desc)

        include_inactive : typing.Optional[bool]
            Include soft-deleted/inactive members

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

        Returns
        -------
        HttpResponse[MemberListResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users",
            method="POST",
            json={
                "skip": skip,
                "take": take,
                "search_term": search_term,
                "role_id": role_id,
                "status_id": status_id,
                "sort_column": sort_column,
                "sort_direction": sort_direction,
                "include_inactive": include_inactive,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    MemberListResponse,
                    parse_obj_as(
                        type_=MemberListResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_member_ids(
        self,
        organization_id: str,
        *,
        include_deleted: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[typing.List[str]]:
        """
        Get list of all member user IDs in the organization.

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            db: Database session
            auth: Authenticated user
            include_deleted: Whether to include soft-deleted members

        Returns:
            List of user IDs

        Parameters
        ----------
        organization_id : str
            Organization ID to get member IDs from

        include_deleted : typing.Optional[bool]

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

        Returns
        -------
        HttpResponse[typing.List[str]]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/ids",
            method="POST",
            params={
                "include_deleted": include_deleted,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.List[str],
                    parse_obj_as(
                        type_=typing.List[str],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_members_by_ids(
        self,
        organization_id: str,
        *,
        request: typing.Dict[str, typing.Any],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[typing.Dict[str, typing.Any]]:
        """
        Get organization members by specific user IDs.

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            request: Dictionary with 'user_ids' list
            db: Database session
            auth: Authenticated user

        Returns:
            Dictionary with users list, total count, and requested IDs

        Parameters
        ----------
        organization_id : str
            Organization ID to get members from

        request : typing.Dict[str, typing.Any]

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

        Returns
        -------
        HttpResponse[typing.Dict[str, typing.Any]]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/by-ids",
            method="POST",
            json=request,
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.Dict[str, typing.Any],
                    parse_obj_as(
                        type_=typing.Dict[str, typing.Any],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_status_summary(
        self, organization_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[StatusSummaryResponse]:
        """
        Get aggregated member counts grouped by status.

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            db: Database session
            auth: Authenticated user

        Returns:
            Status summary with counts for each status

        Parameters
        ----------
        organization_id : str
            Organization ID

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

        Returns
        -------
        HttpResponse[StatusSummaryResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/status-summary",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    StatusSummaryResponse,
                    parse_obj_as(
                        type_=StatusSummaryResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_member(
        self, organization_id: str, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[MemberResponse]:
        """
        Get details of a specific organization member.

        Accepts either:
        - User ID (usr_...) - will look up by user_id + organization_id
        - OrganizationUser ID (orgusr_...) - will look up directly by organization_user_id

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            user_id: User ID (usr_...) or OrganizationUser ID (orgusr_...)
            db: Database session
            auth: Authenticated user

        Returns:
            Member details

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_id : str
            User ID (usr_...) or OrganizationUser ID (orgusr_...) of the member to retrieve

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

        Returns
        -------
        HttpResponse[MemberResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/{jsonable_encoder(user_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    MemberResponse,
                    parse_obj_as(
                        type_=MemberResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def update_member(
        self,
        organization_id: str,
        user_id: str,
        *,
        role_id: typing.Optional[str] = OMIT,
        status_id: typing.Optional[str] = OMIT,
        first_name: typing.Optional[str] = OMIT,
        last_name: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[MemberResponse]:
        """
        Update a member's role and/or status.

        Accepts either:
        - User ID (usr_...)
        - OrganizationUser ID (orgusr_...)

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role for status changes)
        - User must have Admin or Owner role (for role changes only)
        - Cannot change owner's role
        - Cannot set owner to inactive status

        Args:
            organization_id: Organization ID
            user_id: User ID (usr_...) or OrganizationUser ID (orgusr_...)
            request: Update request with role_id and/or status_id
            db: Database session
            auth: Authenticated user

        Returns:
            Updated member details

        Raises:
            ValidationException: If attempting to update owner inappropriately
            AuthorizationException: If non-admin/owner attempts role change
            ResourceNotFoundException: If member, role, or status not found

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_id : str
            User ID (usr_...) or OrganizationUser ID (orgusr_...) of the member to update

        role_id : typing.Optional[str]
            New role ID

        status_id : typing.Optional[str]
            New status ID

        first_name : typing.Optional[str]
            Updated first name

        last_name : typing.Optional[str]
            Updated last name

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

        Returns
        -------
        HttpResponse[MemberResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/{jsonable_encoder(user_id)}",
            method="PUT",
            json={
                "role_id": role_id,
                "status_id": status_id,
                "first_name": first_name,
                "last_name": last_name,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    MemberResponse,
                    parse_obj_as(
                        type_=MemberResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def delete_member(
        self, organization_id: str, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[None]:
        """
        Soft delete a single organization member.

        Accepts either:
        - User ID (usr_...)
        - OrganizationUser ID (orgusr_...)

        Requires:
        - User must be authenticated
        - User must be a member of the organization
        - User must have Admin or Owner role
        - Cannot delete organization owner

        Args:
            organization_id: Organization ID
            user_id: User ID (usr_...) or OrganizationUser ID (orgusr_...)
            db: Database session
            auth: Authenticated user

        Raises:
            ValidationException: If attempting to delete owner
            ResourceNotFoundException: If member not found

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_id : str
            User ID (usr_...) or OrganizationUser ID (orgusr_...) of the member to delete

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

        Returns
        -------
        HttpResponse[None]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/{jsonable_encoder(user_id)}/delete",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return HttpResponse(response=_response, data=None)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def delete_members_bulk(
        self,
        organization_id: str,
        *,
        user_ids: typing.Sequence[str],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[BulkOperationResponse]:
        """
        Bulk delete organization members with partial failure handling.

        Requires:
        - User must be authenticated
        - User must be a member of the organization
        - User must have Admin or Owner role
        - Organization owner will be skipped automatically

        Args:
            organization_id: Organization ID
            request: List of user IDs to delete
            db: Database session
            auth: Authenticated user

        Returns:
            Bulk operation response with success/failure counts

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_ids : typing.Sequence[str]
            List of user IDs to delete

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

        Returns
        -------
        HttpResponse[BulkOperationResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/delete-bulk",
            method="POST",
            json={
                "user_ids": user_ids,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkOperationResponse,
                    parse_obj_as(
                        type_=BulkOperationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def restore_member(
        self, organization_id: str, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[None]:
        """
        Restore a soft-deleted organization member.

        Accepts either:
        - User ID (usr_...)
        - OrganizationUser ID (orgusr_...)

        Requires:
        - User must be authenticated
        - User must be a member of the organization
        - User must have Admin or Owner role
        - Member must be soft-deleted

        Args:
            organization_id: Organization ID
            user_id: User ID (usr_...) or OrganizationUser ID (orgusr_...)
            db: Database session
            auth: Authenticated user

        Raises:
            ResourceNotFoundException: If member not found
            ValidationException: If member is not deleted

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_id : str
            User ID (usr_...) or OrganizationUser ID (orgusr_...) of the member to restore

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

        Returns
        -------
        HttpResponse[None]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/{jsonable_encoder(user_id)}/restore",
            method="POST",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return HttpResponse(response=_response, data=None)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def change_status_bulk(
        self,
        organization_id: str,
        *,
        user_ids: typing.Sequence[str],
        status_id: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[BulkOperationResponse]:
        """
        Bulk change member status with partial failure handling.

        Requires:
        - User must be authenticated
        - User must be a member of the organization
        - User must have Admin or Owner role
        - Organization owner will be skipped if setting inactive status

        Args:
            organization_id: Organization ID
            request: List of user IDs and new status ID
            db: Database session
            auth: Authenticated user

        Returns:
            Bulk operation response with success/failure counts

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_ids : typing.Sequence[str]
            List of user IDs to update

        status_id : str
            New status ID

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

        Returns
        -------
        HttpResponse[BulkOperationResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/change-status-bulk",
            method="POST",
            json={
                "user_ids": user_ids,
                "status_id": status_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkOperationResponse,
                    parse_obj_as(
                        type_=BulkOperationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)


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

    async def list_members(
        self,
        organization_id: str,
        *,
        skip: typing.Optional[int] = OMIT,
        take: typing.Optional[int] = OMIT,
        search_term: typing.Optional[str] = OMIT,
        role_id: typing.Optional[str] = OMIT,
        status_id: typing.Optional[str] = OMIT,
        sort_column: typing.Optional[str] = OMIT,
        sort_direction: typing.Optional[str] = OMIT,
        include_inactive: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[MemberListResponse]:
        """
        Get paginated list of organization members with filtering and sorting.

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            request: Pagination and filter parameters
            db: Database session
            auth: Authenticated user

        Returns:
            Paginated list of members with total count

        Parameters
        ----------
        organization_id : str
            Organization ID to list members from

        skip : typing.Optional[int]
            Number of records to skip

        take : typing.Optional[int]
            Number of records to return (max 500)

        search_term : typing.Optional[str]
            Search across full_name, email, and username

        role_id : typing.Optional[str]
            Filter by role ID

        status_id : typing.Optional[str]
            Filter by status ID

        sort_column : typing.Optional[str]
            Field to sort by (full_name, email, role, status, created_at, last_modified_at)

        sort_direction : typing.Optional[str]
            Sort direction (asc or desc)

        include_inactive : typing.Optional[bool]
            Include soft-deleted/inactive members

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

        Returns
        -------
        AsyncHttpResponse[MemberListResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users",
            method="POST",
            json={
                "skip": skip,
                "take": take,
                "search_term": search_term,
                "role_id": role_id,
                "status_id": status_id,
                "sort_column": sort_column,
                "sort_direction": sort_direction,
                "include_inactive": include_inactive,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    MemberListResponse,
                    parse_obj_as(
                        type_=MemberListResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_member_ids(
        self,
        organization_id: str,
        *,
        include_deleted: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[typing.List[str]]:
        """
        Get list of all member user IDs in the organization.

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            db: Database session
            auth: Authenticated user
            include_deleted: Whether to include soft-deleted members

        Returns:
            List of user IDs

        Parameters
        ----------
        organization_id : str
            Organization ID to get member IDs from

        include_deleted : typing.Optional[bool]

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

        Returns
        -------
        AsyncHttpResponse[typing.List[str]]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/ids",
            method="POST",
            params={
                "include_deleted": include_deleted,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.List[str],
                    parse_obj_as(
                        type_=typing.List[str],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_members_by_ids(
        self,
        organization_id: str,
        *,
        request: typing.Dict[str, typing.Any],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[typing.Dict[str, typing.Any]]:
        """
        Get organization members by specific user IDs.

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            request: Dictionary with 'user_ids' list
            db: Database session
            auth: Authenticated user

        Returns:
            Dictionary with users list, total count, and requested IDs

        Parameters
        ----------
        organization_id : str
            Organization ID to get members from

        request : typing.Dict[str, typing.Any]

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

        Returns
        -------
        AsyncHttpResponse[typing.Dict[str, typing.Any]]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/by-ids",
            method="POST",
            json=request,
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.Dict[str, typing.Any],
                    parse_obj_as(
                        type_=typing.Dict[str, typing.Any],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_status_summary(
        self, organization_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[StatusSummaryResponse]:
        """
        Get aggregated member counts grouped by status.

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            db: Database session
            auth: Authenticated user

        Returns:
            Status summary with counts for each status

        Parameters
        ----------
        organization_id : str
            Organization ID

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

        Returns
        -------
        AsyncHttpResponse[StatusSummaryResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/status-summary",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    StatusSummaryResponse,
                    parse_obj_as(
                        type_=StatusSummaryResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_member(
        self, organization_id: str, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[MemberResponse]:
        """
        Get details of a specific organization member.

        Accepts either:
        - User ID (usr_...) - will look up by user_id + organization_id
        - OrganizationUser ID (orgusr_...) - will look up directly by organization_user_id

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role)

        Args:
            organization_id: Organization ID
            user_id: User ID (usr_...) or OrganizationUser ID (orgusr_...)
            db: Database session
            auth: Authenticated user

        Returns:
            Member details

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_id : str
            User ID (usr_...) or OrganizationUser ID (orgusr_...) of the member to retrieve

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

        Returns
        -------
        AsyncHttpResponse[MemberResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/{jsonable_encoder(user_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    MemberResponse,
                    parse_obj_as(
                        type_=MemberResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def update_member(
        self,
        organization_id: str,
        user_id: str,
        *,
        role_id: typing.Optional[str] = OMIT,
        status_id: typing.Optional[str] = OMIT,
        first_name: typing.Optional[str] = OMIT,
        last_name: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[MemberResponse]:
        """
        Update a member's role and/or status.

        Accepts either:
        - User ID (usr_...)
        - OrganizationUser ID (orgusr_...)

        Requires:
        - User must be authenticated
        - User must be a member of the organization (any role for status changes)
        - User must have Admin or Owner role (for role changes only)
        - Cannot change owner's role
        - Cannot set owner to inactive status

        Args:
            organization_id: Organization ID
            user_id: User ID (usr_...) or OrganizationUser ID (orgusr_...)
            request: Update request with role_id and/or status_id
            db: Database session
            auth: Authenticated user

        Returns:
            Updated member details

        Raises:
            ValidationException: If attempting to update owner inappropriately
            AuthorizationException: If non-admin/owner attempts role change
            ResourceNotFoundException: If member, role, or status not found

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_id : str
            User ID (usr_...) or OrganizationUser ID (orgusr_...) of the member to update

        role_id : typing.Optional[str]
            New role ID

        status_id : typing.Optional[str]
            New status ID

        first_name : typing.Optional[str]
            Updated first name

        last_name : typing.Optional[str]
            Updated last name

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

        Returns
        -------
        AsyncHttpResponse[MemberResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/{jsonable_encoder(user_id)}",
            method="PUT",
            json={
                "role_id": role_id,
                "status_id": status_id,
                "first_name": first_name,
                "last_name": last_name,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    MemberResponse,
                    parse_obj_as(
                        type_=MemberResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def delete_member(
        self, organization_id: str, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[None]:
        """
        Soft delete a single organization member.

        Accepts either:
        - User ID (usr_...)
        - OrganizationUser ID (orgusr_...)

        Requires:
        - User must be authenticated
        - User must be a member of the organization
        - User must have Admin or Owner role
        - Cannot delete organization owner

        Args:
            organization_id: Organization ID
            user_id: User ID (usr_...) or OrganizationUser ID (orgusr_...)
            db: Database session
            auth: Authenticated user

        Raises:
            ValidationException: If attempting to delete owner
            ResourceNotFoundException: If member not found

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_id : str
            User ID (usr_...) or OrganizationUser ID (orgusr_...) of the member to delete

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

        Returns
        -------
        AsyncHttpResponse[None]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/{jsonable_encoder(user_id)}/delete",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return AsyncHttpResponse(response=_response, data=None)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def delete_members_bulk(
        self,
        organization_id: str,
        *,
        user_ids: typing.Sequence[str],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[BulkOperationResponse]:
        """
        Bulk delete organization members with partial failure handling.

        Requires:
        - User must be authenticated
        - User must be a member of the organization
        - User must have Admin or Owner role
        - Organization owner will be skipped automatically

        Args:
            organization_id: Organization ID
            request: List of user IDs to delete
            db: Database session
            auth: Authenticated user

        Returns:
            Bulk operation response with success/failure counts

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_ids : typing.Sequence[str]
            List of user IDs to delete

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

        Returns
        -------
        AsyncHttpResponse[BulkOperationResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/delete-bulk",
            method="POST",
            json={
                "user_ids": user_ids,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkOperationResponse,
                    parse_obj_as(
                        type_=BulkOperationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def restore_member(
        self, organization_id: str, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[None]:
        """
        Restore a soft-deleted organization member.

        Accepts either:
        - User ID (usr_...)
        - OrganizationUser ID (orgusr_...)

        Requires:
        - User must be authenticated
        - User must be a member of the organization
        - User must have Admin or Owner role
        - Member must be soft-deleted

        Args:
            organization_id: Organization ID
            user_id: User ID (usr_...) or OrganizationUser ID (orgusr_...)
            db: Database session
            auth: Authenticated user

        Raises:
            ResourceNotFoundException: If member not found
            ValidationException: If member is not deleted

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_id : str
            User ID (usr_...) or OrganizationUser ID (orgusr_...) of the member to restore

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

        Returns
        -------
        AsyncHttpResponse[None]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/{jsonable_encoder(user_id)}/restore",
            method="POST",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return AsyncHttpResponse(response=_response, data=None)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def change_status_bulk(
        self,
        organization_id: str,
        *,
        user_ids: typing.Sequence[str],
        status_id: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[BulkOperationResponse]:
        """
        Bulk change member status with partial failure handling.

        Requires:
        - User must be authenticated
        - User must be a member of the organization
        - User must have Admin or Owner role
        - Organization owner will be skipped if setting inactive status

        Args:
            organization_id: Organization ID
            request: List of user IDs and new status ID
            db: Database session
            auth: Authenticated user

        Returns:
            Bulk operation response with success/failure counts

        Parameters
        ----------
        organization_id : str
            Organization ID

        user_ids : typing.Sequence[str]
            List of user IDs to update

        status_id : str
            New status ID

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

        Returns
        -------
        AsyncHttpResponse[BulkOperationResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/organizations/{jsonable_encoder(organization_id)}/users/change-status-bulk",
            method="POST",
            json={
                "user_ids": user_ids,
                "status_id": status_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkOperationResponse,
                    parse_obj_as(
                        type_=BulkOperationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    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)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
