# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/classes/50_DomoAccess.ipynb.

# %% auto 0
__all__ = ['Access_Entity', 'Access_Config_Error', 'DomoAccess', 'DomoAccess_Account', 'DomoAccess_OAuth']

# %% ../../nbs/classes/50_DomoAccess.ipynb 3
from domolibrary.routes.account import (
    ShareAccount_AccessLevel,
    ShareAccount_V1_AccessLevel,
    ShareAccount,
    Account_Share_Error,
)

# %% ../../nbs/classes/50_DomoAccess.ipynb 4
from dataclasses import dataclass, field
from typing import Any, List

from abc import abstractmethod

import httpx

import domolibrary.client.DomoAuth as dmda
import domolibrary.client.DomoError as dmde
import domolibrary.routes.account as account_routes

import domolibrary.utils.chunk_execution as dmce

# %% ../../nbs/classes/50_DomoAccess.ipynb 7
@dataclass
class Access_Entity:
    entity: Any
    access_level: ShareAccount
    auth: dmda.DomoAuth = field(repr=False)

    @classmethod
    async def from_user_id(
        cls,
        user_id,
        access_level: ShareAccount,
        auth: dmda.DomoAuth,
        session: httpx.AsyncClient = None,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
    ):

        # if entity_type == "USER":
        import domolibrary.classes.DomoUser as dmdu

        domo_user = await dmdu.DomoUser.get_by_id(
            user_id=user_id,
            auth=auth,
            session=session,
            debug_api=debug_api,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop + 1,
        )

        return cls(entity=domo_user, access_level=access_level, auth=auth)

    @classmethod
    async def from_group_id(
        cls,
        group_id,
        access_level: ShareAccount,
        auth: dmda.DomoAuth,
        session: httpx.AsyncClient = None,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
    ):

        import domolibrary.classes.DomoGroup as dmdg

        domo_group = await dmdg.DomoGroup.get_by_id(
            group_id=group_id,
            auth=auth,
            session=session,
            debug_api=debug_api,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop + 1,
        )

        return cls(entity=domo_group, access_level=access_level, auth=auth)

    def __eq__(self, other):
        return (
            self.entity.id == other.entity.id
            and self.entity.__class__.__name__ == other.entity.__class__.__name__
        )

# %% ../../nbs/classes/50_DomoAccess.ipynb 8
class Access_Config_Error(dmde.ClassError):
    def __init__(self, cls_instance, account_id, message):
        super().__init__(
            cls_instance=cls_instance, message=message, entity_id=account_id
        )


@dataclass
class DomoAccess:
    auth: dmda.DomoAuth = field(repr=False)

    share_enum: Any = field(repr = False)

    accesslist: List[Access_Entity] = field(default_factory=lambda: []) # can include users or groups

    accesslist_all_users: List[Any] = field(default_factory=lambda: [])  # DomoUser

    parent_id: int = None
    parent: any = field(repr=False, default=None)

    @abstractmethod
    async def get(self, *args, **kwargs):
        pass

    def _common_init(self):
        if not self.parent_id and self.parent and hasattr(self.parent, "id"):
            self.parent_id = self.parent.id

    def __post_init__(self):
        self._common_init()

    async def get_all_users(
        self,
        debug_api: bool = False,
        debug_num_stacks_to_drop: int = 1,
        session: httpx.AsyncClient = None,
    ):

        import domolibrary.classes.DomoUser as dmdu
        import domolibrary.classes.DomoGroup as dmdg

        await self.get(
            debug_api=debug_api,
            session=session,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop + 1,
        )

        for access in self.accesslist:
            entity = access.entity

            if isinstance(entity, dmdu.DomoUser):
                if entity not in self.accesslist_all_users:
                    self.accesslist_all_users.append(entity)

            if isinstance(entity, dmdg.DomoGroup):
                domo_users = await access.entity.Membership.get_members()

                [
                    self.accesslist_all_users.append(user)
                    for user in domo_users
                    if user not in self.accesslist_all_users
                ]

        return self.accesslist_all_users

    async def share(
        self,
        user_id=None,
        group_id=None,
        domo_group=None,
        domo_user=None,
        access_level: ShareAccount = None,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
        session: httpx.AsyncClient = None,
    ):
        access_level = access_level or self.share_enum.default

        share_payload = access_level.generate_payload(
            user_id=user_id or (domo_user and domo_user.id),
            group_id=group_id or (domo_group and domo_group.id),
        )

        res = await access_level.share(
            auth=self.auth,
            account_id=self.parent_id,
            share_payload=share_payload,
            debug_api=debug_api,
            session=session,
            parent_class=self.__class__.__name__,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        )

        return res
    
    async def upsert_share(
        self,
        user_id=None,
        group_id=None,
        domo_group=None,
        domo_user=None,
        access_level: ShareAccount = None,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
        session: httpx.AsyncClient = None,
    ):
        user_id=user_id or (domo_user and domo_user.id)
        group_id=group_id or (domo_group and domo_group.id)

        await self.get(session = session, debug_api = debug_api, debug_num_stacks_to_drop = debug_num_stacks_to_drop + 1, )
        
        for member in self.accesslist:
            if ( member.entity.id == user_id or member.entity.id == group_id) and access_level == member.access_level:
                return False

        return await self.share(
            user_id = user_id,
            group_id = group_id,
            access_level= access_level,
            debug_api= debug_api,
            debug_num_stacks_to_drop= debug_num_stacks_to_drop,
            session = session
        )    
        

# %% ../../nbs/classes/50_DomoAccess.ipynb 10
@dataclass
class DomoAccess_Account(DomoAccess):
    version: int = None  # api version - aligns to feature switch

    share_enum: ShareAccount = field(repr = False, default = ShareAccount_AccessLevel)

    def __post_init__(self):
        self._common_init()
        
        if isinstance(self.share_enum , ShareAccount_AccessLevel):
            self.version = 2
        elif isinstance(self.share_enum , ShareAccount_V1_AccessLevel):
            self.version = 1
        
        return True

    async def get(
        self,
        debug_api: bool = False,
        return_raw: bool = False,
        session: httpx.AsyncClient = None,
        debug_num_stacks_to_drop=2,
    ):
        """assumes v2 access api"""

        res = await account_routes.get_account_accesslist(
            auth=self.auth,
            account_id=self.parent_id,
            debug_api=debug_api,
            session=session,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        )

        if return_raw:
            return res

        self.accesslist = await dmce.gather_with_concurrency(
            *[
                Access_Entity.from_user_id(
                    user_id=obj["id"],
                    auth=self.auth,
                    access_level=self.share_enum(obj["accessLevel"]),
                )
                for obj in res.response
                if obj["type"] == "USER"
            ],
            *[
                Access_Entity.from_group_id(
                    group_id=obj["id"],
                    auth=self.auth,
                    access_level=self.share_enum(obj["accessLevel"]),
                )
                for obj in res.response
                if obj["type"] == "GROUP"
            ],
            n=10,
        )
        return self.accesslist

# %% ../../nbs/classes/50_DomoAccess.ipynb 18
@dataclass
class DomoAccess_OAuth(DomoAccess):
    share_enum: account_routes.ShareAccount = field(
        repr=False, default=ShareAccount_AccessLevel
    )

    async def get(
        self,
        debug_api: bool = False,
        return_raw: bool = False,
        session: httpx.AsyncClient = None,
        debug_num_stacks_to_drop=2,
    ):
        """assumes v2 access api"""

        res = await account_routes.get_oauth_account_accesslist(
            auth=self.auth,
            account_id=self.parent_id,
            debug_api=debug_api,
            session=session,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        )

        if return_raw:
            return res

        self.accesslist = await dmce.gather_with_concurrency(
            *[
                Access_Entity.from_user_id(
                    user_id=obj["id"],
                    auth=self.auth,
                    access_level=self.share_enum(obj["accessLevel"]),
                )
                for obj in res.response
                if obj["type"] == "USER"
            ],
            *[
                Access_Entity.from_group_id(
                    group_id=obj["id"],
                    auth=self.auth,
                    access_level=self.share_enum(obj["accessLevel"]),
                )
                for obj in res.response
                if obj["type"] == "GROUP"
            ],
            n=10,
        )
        return self.accesslist
