# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/routes/group.ipynb.

# %% auto 0
__all__ = ['Group_GET_Error', 'SearchGroups_Error', 'search_groups_by_name', 'get_all_groups', 'get_group_by_id',
           'Group_CRUD_Error', 'is_system_groups_visible', 'toggle_system_group_visibility', 'GroupType_Enum',
           'generate_body_create_group', 'create_group', 'update_group', 'delete_groups', 'get_group_owners',
           'get_group_membership', 'generate_body_update_group_membership', 'update_group_membership',
           'update_group_members', 'update_group_owners']

# %% ../../nbs/routes/group.ipynb 2
import httpx
from domolibrary.client.DomoEntity import DomoEnum
from typing import Union, List

import domolibrary.client.get_data as gd
import domolibrary.client.ResponseGetData as rgd
import domolibrary.client.DomoAuth as dmda
import domolibrary.client.DomoError as dmde

import domolibrary.utils.convert as dmcv

# %% ../../nbs/routes/group.ipynb 6
class Group_GET_Error(dmde.RouteError):
    def __init__(
        self,
        res: rgd.ResponseGetData,
        message=None,
    ):
        super().__init__(res=res, message=message or res.response)


class SearchGroups_Error(dmde.RouteError):
    def __init__(
        self,
        res: rgd.ResponseGetData,
        message=None,
    ):
        super().__init__(res=res, message=message or res.response)


@gd.route_function
async def search_groups_by_name(
    auth: dmda.DomoAuth,
    search_name: str,
    is_exact_match: bool = True,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
    debug_num_stacks_to_drop=1,
    parent_class: str = None,
) -> rgd.ResponseGetData:
    """uses /content/v2/groups/grouplist api -- includes user details"""

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/grouplist?ascending=true&search={search_name}&sort=name "

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="GET",
        debug_api=debug_api,
        session=session,
        parent_class=parent_class,
        num_stacks_to_drop=debug_num_stacks_to_drop,
    )
    if not res.is_success:
        raise Group_GET_Error(res=res)

    if not is_exact_match:
        return res

    match_group = next(
        (group for group in res.response if group.get("name") == search_name), None
    )
    
    if not match_group:
        raise SearchGroups_Error(
            res=res,
            message=f"There is no exact match for {search_name}",
        )
    
    res.response = match_group

    return res

# %% ../../nbs/routes/group.ipynb 9
@gd.route_function
async def get_all_groups(
    auth: dmda.DomoAuth,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    debug_loop: bool = False,
    debug_num_stacks_to_drop: int = 1,
    parent_class: str = None,
    return_raw: bool = False,
    maximum = None
) -> rgd.ResponseGetData:
    """uses /content/v2/groups/grouplist api -- includes user details"""

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/grouplist"

    def arr_fn(res):
        return res.response

    res = await gd.looper(
        offset_params={"offset": "offset", "limit": "limit"},
        arr_fn=arr_fn,
        loop_until_end=True if maximum is None else False,
        limit=30,
        url=url,
        method="GET",
        auth=auth,
        session=session,
        debug_loop=debug_loop,
        debug_api=debug_api,
        parent_class=parent_class,
        debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        return_raw = return_raw,
        maximum = maximum,
    )

    if return_raw:
        return res

    if not res.is_success:
        raise Group_GET_Error(res = res)

    return res

# %% ../../nbs/routes/group.ipynb 12
@gd.route_function
async def get_group_by_id(
    auth: dmda.DomoAuth,
    group_id: str,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
    debug_num_stacks_to_drop: int = 1,
) -> rgd.ResponseGetData:
    """uses /content/v2/groups/ api -- does not return details"""

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/{group_id}"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="GET",
        debug_api=debug_api,
        session=session,
        parent_class=parent_class,
        num_stacks_to_drop=debug_num_stacks_to_drop,
    )

    if res.status == 404 and res.response == "Not Found":
        raise SearchGroups_Error(
            res = res,
            message=f"group {group_id} not found",
            )

    if not res.is_success:
        raise Group_GET_Error(res =res)

    return res

# %% ../../nbs/routes/group.ipynb 14
class Group_CRUD_Error(dmde.RouteError):
    def __init__(self, res: rgd.ResponseGetData, message=None):
        super().__init__(res=res, message=message or res.response)


@gd.route_function
async def is_system_groups_visible(
    auth: dmda.DomoAuth,
    session: httpx.AsyncClient,
    debug_api: bool = False,
    debug_num_stacks_to_drop=1,
    parent_class: str = None,
    return_raw: bool = False
):

    url = f"https://{auth.domo_instance}.domo.com/api/customer/v1/properties/groups.system.enabled"

    res = await gd.get_data(
        url=url,
        auth=auth,
        method="GET",
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        session=session,
        parent_class=parent_class,
    )
    
    if return_raw:
        return res

    if not res.is_success:
        raise Group_GET_Error(res=res)
    
    
    if res.response.get('value'):
        res.response['value'] = dmcv.convert_string_to_bool(res.response['value']) 

    return res


@gd.route_function
async def toggle_system_group_visibility(
    auth,
    is_hide_system_groups: bool,
    debug_api: bool = False,
    debug_prn: bool = False,
    debug_num_stacks_to_drop=1,
    parent_class: str = None,
    session: httpx.AsyncClient = None,
):
    if debug_prn:
        print(
            f"toggling group visiblity in {auth.domo_instance} { 'hiding system groups' if is_hide_system_groups else 'show system groups'}"
        )

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/setVisibility"

    res = await gd.get_data(
        url=url,
        method="POST",
        auth=auth,
        body={"type": "system", "hidden": is_hide_system_groups},
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        session=session,
        parent_class=parent_class,
    )

    if not res.is_success:
        raise Group_CRUD_Error(res=res)

    return await is_system_groups_visible(
        auth=auth,
        debug_api=debug_api,
        debug_num_stacks_to_drop=debug_num_stacks_to_drop + 1,
        parent_class=parent_class,
        session = session
    )

# %% ../../nbs/routes/group.ipynb 19
class GroupType_Enum(DomoEnum):
    OPEN = "open"
    ADHOC = "adHoc"
    CLOSED = "closed"
    DIRECTORY = "directory"
    DYNAMIC = "dynamic"
    SYSYTEM = "system"


def generate_body_create_group(
    group_name: str, 
    group_type: str = "open",
    description: str = ""
) -> dict:
    """Generates the body to create group for content_v2_group API"""
    body = {"name": group_name, "type": group_type, "description": description}

    return body

# %% ../../nbs/routes/group.ipynb 22
@gd.route_function
async def create_group(
    auth: dmda.DomoAuth,
    group_name: str,
    group_type: Union[GroupType_Enum, str] = "open",
    description: str = "",
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    debug_num_stacks_to_drop: int = 1,
    parent_class: str = None,
    return_raw: bool = False,
) -> rgd.ResponseGetData:
    # body : {"name": "GROUP_NAME", "type": "open", "description": ""}

    if isinstance(group_type, GroupType_Enum):
        group_type = group_type.value

    body = generate_body_create_group(
        group_name=group_name, group_type=group_type, description=description
    )
    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="POST",
        body=body,
        debug_api=debug_api,
        session=session,
        parent_class=parent_class,
        num_stacks_to_drop=debug_num_stacks_to_drop,
    )

    if return_raw:
        return res

    if not res.is_success:
        try:
            group_exists = await search_groups_by_name(
                auth=auth, search_name=group_name, is_exact_match=True
            )

            if group_exists.is_success:
                raise Group_CRUD_Error(
                    res=res,
                    message=f"{group_name} already exists. Choose a different group_name",
                )

        except SearchGroups_Error as e:
            raise Group_CRUD_Error(
                res=res,
                message=res.response,
            )

    return res

# %% ../../nbs/routes/group.ipynb 25
@gd.route_function
async def update_group(
    auth: dmda.DomoAuth,
    group_id: int,
    group_name: str = None,
    group_type: str = None,
    description: str = None,
    additional_params: dict = None,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
    debug_num_stacks_to_drop=1,
    parent_class: str = None,
) -> rgd.ResponseGetData:

    if isinstance(group_type, GroupType_Enum):
        group_type = group_type.value

    s = {"groupId": int(group_id)}

    if group_name:
        s.update({"name": group_name})

    if group_type:
        s.update({"type": group_type})

    if description:
        s.update({"description": description})

    if additional_params and isinstance(additional_params, dict):
        s.update({**additional_params})
        pass

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body=[s],
        debug_api=debug_api,
        session=session,
        parent_class=parent_class,
        num_stacks_to_drop=debug_num_stacks_to_drop,
    )

    if group_name and res.status == 400:
        raise Group_CRUD_Error(
            res = res,
            message="are you trying to create an account with a duplicate name?",
             )

    if not res.is_success:
        raise Group_CRUD_Error(
            res = res,
            message=res.response,
            )

    res.response = f"updated {group_id} from {auth.domo_instance}"
    return res

# %% ../../nbs/routes/group.ipynb 28
@gd.route_function
async def delete_groups(
    auth: dmda.DomoAuth,
    group_ids: List[str],  # list of group_ids
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    debug_num_stacks_to_drop: int = 1,
    parent_class: str = None,
    return_raw: bool = False,
) -> rgd.ResponseGetData:

    group_ids = group_ids if isinstance(group_ids, list) else [str(group_ids)]

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="DELETE",
        body=group_ids,
        debug_api=debug_api,
        session=session,
        parent_class=parent_class,
        num_stacks_to_drop=debug_num_stacks_to_drop,
    )

    if return_raw:
        return res

    if not res.is_success:
        raise Group_CRUD_Error(
            res = res,
            message=f"failed to delete {', '.join(group_ids)}",
        )

    res.response = f"deleted {', '.join(group_ids)} from {auth.domo_instance}"
    return res

# %% ../../nbs/routes/group.ipynb 31
@gd.route_function
async def get_group_owners(
    auth: dmda.DomoAuth,
    group_id: str,
    debug_api: bool = False,
    debug_num_stacks_to_drop=1,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
    return_raw: bool = False,
    # maximum: int = None,
    # skip: int = 0,
    # debug_loop: bool = False,
) -> rgd.ResponseGetData:

    # url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/access"
    # url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/users?group={group_id}"
    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/permissions?checkOwnership=true&includeUsers=false"

    res = await gd.get_data(
        auth=auth,
        url=url,
        body=[str(group_id)],
        method="POST",
        debug_api=debug_api,
        session=session,
        parent_class=parent_class,
        num_stacks_to_drop=debug_num_stacks_to_drop,
    )

    ## probably not paginated, headers would not make sence when checking owners

    # def arr_fn(res):
    #     return res.response[0].get("permissions").get("owners")

    # res = await gd.looper(
    #     auth=auth,
    #     session=session,
    #     url=url,
    #     offset_params={"offset": "offset", "limit": "limit"},
    #     arr_fn=arr_fn,
    #     loop_until_end=(
    #         True if maximum is None else False
    #     ),  # usually you'll set this to true.  it will override maximum
    #     method="POST",
    #     body=[str(group_id)],
    #     offset_params_in_body=False,
    #     limit=50,
    #     skip=skip,
    #     maximum=maximum,
    #     debug_api=debug_api,
    #     debug_loop=debug_loop,
    #     debug_num_stacks_to_drop=debug_num_stacks_to_drop + 1,
    #     parent_class=parent_class,
    #     return_raw=return_raw,
    # )
    
    if return_raw:
        return res
    
    if not res.is_success:
        raise Group_GET_Error(res=res)
    
    res.response = res.response[0]['permissions']['owners']

    return res

# %% ../../nbs/routes/group.ipynb 34
@gd.route_function
async def get_group_membership(
    auth: dmda.DomoAuth,
    group_id: str,
    return_raw: bool = False,
    debug_api: bool = False,
    maximum = None,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
    debug_num_stacks_to_drop: int = 1,
    debug_loop : bool = False,
) -> rgd.ResponseGetData:

    # url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/access"
    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/users"

    # res = await gd.get_data(
    #     auth=auth,
    #     url=url,
    #     method="GET",
    #     debug_api=debug_api,
    #     session=session,
    #     parent_class=parent_class,
    #     num_stacks_to_drop=debug_num_stacks_to_drop,
    #     params = {
    #         "offset" : 1,
    #         "limit" : 1
    #     }
    # )
    def arr_fn(res):
        return res.response.get("groupUserList")

    fixed_params = {"group" :  group_id}
    
    res = await gd.looper(
        auth= auth,
        session  = session,
        url = url,
        fixed_params = fixed_params,
        offset_params = {"offset" : "offset" , "limit" : "limit"},
        arr_fn = arr_fn,
        loop_until_end = True if maximum is None else False,  # usually you'll set this to true.  it will override maximum
        maximum = maximum,
        method="GET",
        offset_params_in_body = False,
        limit=500,
        skip=0,
        debug_api = debug_api,
        debug_loop = debug_loop,
        debug_num_stacks_to_drop = debug_num_stacks_to_drop,
        parent_class = parent_class,
        return_raw = return_raw,
    ) 

    if return_raw:
        return res
    
    if not res.is_success:
        raise Group_GET_Error(res = res)

    return res

# %% ../../nbs/routes/group.ipynb 38
def generate_body_update_group_membership(
    group_id: str,
    add_owner_arr: List[str] = None,
    remove_owner_arr: List[str] = None,
    remove_member_arr: List[str] = None,
    add_member_arr: List[str] = None,
) -> list[dict]:
    """
    each member or owner obj should be an object of shape {"type", "id"}
    """
    body = {"groupId": int(group_id)}

    if add_owner_arr and len(add_owner_arr) > 0:
        body.update({"addOwners": add_owner_arr})

    if remove_owner_arr and len(remove_owner_arr) > 0:
        body.update({"removeOwners": remove_owner_arr})

    if remove_member_arr and len(remove_member_arr) > 0:
        body.update({"removeMembers": remove_member_arr})
    if add_member_arr and len(add_member_arr) > 0:
        body.update({"addMembers": add_member_arr})

    return [body]

# %% ../../nbs/routes/group.ipynb 40
@gd.route_function
async def update_group_membership(
    auth: dmda.DomoAuth,
    group_id: str,
    update_payload: dict = None,
    add_member_arr: list[dict] = None,
    remove_member_arr: list[dict] = None,
    add_owner_arr: list[dict] = None,
    remove_owner_arr: list[dict] = None,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
    debug_num_stacks_to_drop: int = 1,
) -> rgd.ResponseGetData:
    """
    each member or owner obj should be an object of shape {"type", "id"}
    """

    update_payload = update_payload or generate_body_update_group_membership(
        group_id=group_id,
        add_member_arr=add_member_arr,
        remove_member_arr=remove_member_arr,
        add_owner_arr=add_owner_arr,
        remove_owner_arr=remove_owner_arr
    )

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/access"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body=update_payload,
        debug_api=debug_api,
        session=session,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )

    if not res.is_success:
        raise Group_CRUD_Error(res=res)

    return res


@gd.route_function
async def update_group_members(
    auth: dmda.DomoAuth,
    group_id: str,
    add_member_arr: list[dict] = None,
    remove_member_arr: list[dict] = None,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
    debug_num_stacks_to_drop: int = 1,
) -> rgd.ResponseGetData:
    """
    each member or owner obj should be an object of shape {"type", "id"}
    """

    body = generate_body_update_group_membership(
        group_id=group_id,
        add_member_arr=add_member_arr,
        remove_member_arr=remove_member_arr,
    )

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/access"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body=body,
        debug_api=debug_api,
        session=session,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )

    if not res.is_success:
        raise Group_CRUD_Error(res=res)

    return res


@gd.route_function
async def update_group_owners(
    auth: dmda.DomoAuth,
    group_id: str,
    add_owner_arr: list[dict] = None,
    remove_owner_arr: list[dict] = None,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
    debug_num_stacks_to_drop: int = 1,
) -> rgd.ResponseGetData:
    """
    each member or owner obj should be an object of shape {"type", "id"}
    """
    body = generate_body_update_group_membership(
        group_id=group_id,
        add_owner_arr=add_owner_arr,
        remove_owner_arr=remove_owner_arr,
    )

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/groups/access"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="PUT",
        body=body,
        debug_api=debug_api,
        session=session,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
    )

    if not res.is_success:
        raise Group_CRUD_Error(res=res)

    return res
