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

# %% auto 0
__all__ = ['DomoAccount', 'DomoAccount_Types', 'DomoAccounts_NoAccount', 'DomoAccounts']

# %% ../../nbs/classes/50_DomoAccount.ipynb 3
from domolibrary.routes.account import (
    Account_GET_Error,
    Account_NoMatch,
    Account_CRUD_Error,
    Account_CreateParams_Error,
    Account_Config_Error,
    ShareAccount,
    ShareAccount_V1_AccessLevel,
    ShareAccount_AccessLevel,
    Account_Share_Error,
    Account_AlreadyShared_Error 
    )

from domolibrary.classes.DomoAccount_Config import (
    AccountConfig_UsesOauth,
    AccountConfig_ProviderTypeNotDefined,
    DomoAccount_Config,
    AccountConfig,
)

from domolibrary.classes.DomoAccount_Default import (
    Account_CanIModify,
    UpsertAccount_MatchCriteria,
    DomoAccount_Default,
    DomoAccounConfig_MissingFields,
)

from domolibrary.classes.DomoAccount_Credential import (
    DAC_NoTargetInstance,
    DAC_NoPassword,
    DAC_NoUserName,
    DAC_NoAccessToken,
    DAC_ValidAuth,
    DomoAccount_Credential,
)

# %% ../../nbs/classes/50_DomoAccount.ipynb 4
from dataclasses import dataclass, field
from typing import List
from enum import Enum

import httpx
import datetime as dt


from nbdev.showdoc import patch_to

import domolibrary.routes.account as account_routes
import domolibrary.routes.datacenter as datacenter_routes

import domolibrary.client.DomoAuth as dmda
import domolibrary.client.DomoError as dmde
import domolibrary.utils.chunk_execution as dmce

# %% ../../nbs/classes/50_DomoAccount.ipynb 8
class DomoAccount(DomoAccount_Default):

    @classmethod
    def _from_json(
        cls,
        obj: dict,
        is_admin_summary: bool = True,
        auth: dmda.DomoAuth = None,
        is_use_default_account_class=False,
        **kwargs
    ):
        """converts data_v1_accounts API response into an accounts class object"""

        if is_use_default_account_class:
            new_class = DomoAccount_Types.DEFAULT.value

        else:
            new_class = DomoAccount_Types.get(
                obj.get("dataProviderId") or obj.get("dataProviderType")
            )


        return new_class._class_from_json(
            obj=obj, is_admin_summary=is_admin_summary, auth=auth, **kwargs
        )


class DomoAccount_Types(Enum):
    CREDENTIAL = DomoAccount_Credential
    DEFAULT = DomoAccount

    @classmethod
    def _missing_(cls, value):
        value = value.lower()

        for member in cls:
            if member.value == value:
                return member
            
            if value == "domo-access-token" and member.name =='CREDENTIAL':
                return member
            
        return cls.DEFAULT
    
    @classmethod
    def get(cls, value):

        if value == "domo-access-token":
            return cls.CREDENTIAL.value

        try:
            return cls[value].value

        except:
            return cls.DEFAULT.value

# %% ../../nbs/classes/50_DomoAccount.ipynb 22
class DomoAccounts_NoAccount(dmde.ClassError):
    def __init__(self, cls, cls_instance, message, domo_instance):
        super().__init__(
            cls=cls, cls_instance=cls_instance, message=message, entity_id=domo_instance
        )


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

    accounts : List[DomoAccount] = None

    @staticmethod
    async def _get_accounts_accountsapi(
        auth: dmda.DomoAuth,
        debug_api: bool = False,
        session: httpx.AsyncClient = None,
        return_raw: bool = False,
        is_use_default_account_class: bool = True,
        **kwargs,
    ):
        res = await account_routes.get_accounts(
            auth=auth, debug_api=debug_api, session=session
        )

        if return_raw:
            return res

        if len(res.response) == 0:
            return []

        return await dmce.gather_with_concurrency(
            n=60,
            *[
                DomoAccount.get_by_id(
                    account_id=json_obj.get("id"),
                    debug_api=debug_api,
                    session=session,
                    auth=auth,
                    is_use_default_account_class=is_use_default_account_class,
                    **kwargs,
                )
                for json_obj in res.response
            ],
        )

    @staticmethod
    async def _get_accounts_queryapi(
        auth: dmda.DomoAuth,
        debug_api: bool = False,
        additional_filters_ls=None,
        session: httpx.AsyncClient = None,
        return_raw: bool = False,
        is_use_default_account_class: bool = False,
        **kwargs,
    ):
        """v2 api for works with group_account_v2 beta"""

        import domolibrary.routes.datacenter as datacenter_routes

        res = await datacenter_routes.search_datacenter(
            auth=auth,
            entity_type=datacenter_routes.Datacenter_Enum.ACCOUNT.value,
            additional_filters_ls=additional_filters_ls,
            session=session,
            debug_api=debug_api,
        )

        if return_raw:
            return res

        if len(res.response) == 0:
            return []

        return [
            DomoAccount._from_json(
                account_obj,
                auth=auth,
                is_use_default_account_class=is_use_default_account_class,
                **kwargs,
            )
            for account_obj in res.response
        ]
    

    async def get(
        self,
        debug_api: bool = False,
        session: httpx.AsyncClient = None,
        return_raw: bool = False,
        is_use_default_account_class: bool = False,
        debug_num_stacks_to_drop : int = 2,
        **kwargs,
    ):
        domo_accounts = None
        try:
            domo_accounts = await self._get_accounts_queryapi(
                auth=self.auth,
                debug_api=debug_api,
                session=session,
                is_use_default_account_class=is_use_default_account_class,
                return_raw=return_raw,
                debug_num_stacks_to_drop = debug_num_stacks_to_drop+1,
                **kwargs,
            )

        except datacenter_routes.SearchDatacenter_NoResultsFound as e:
            print(e)
        
        if not domo_accounts:
            domo_accounts = await self._get_accounts_accountsapi(
                auth=self.auth,
                debug_api=debug_api,
                session=session,
                debug_num_stacks_to_drop = debug_num_stacks_to_drop+1,
                is_use_default_account_class=is_use_default_account_class,
                return_raw=return_raw,
                **kwargs,
            )
        
        if return_raw:
            return domo_accounts
        
        self.accounts = domo_accounts
        return self.accounts


    @classmethod
    async def get_accounts(
        cls,
        auth: dmda.DomoAuth,
        additional_filters_ls=None,  # datacenter_routes.generate_search_datacenter_filter
        # account string to search for, must be an exact match in spelling.  case insensitive
        # v2 will use the queryAPI as it returns more complete results than the accountsAPI
        is_v2: bool = None,
        account_name: str = None,
        account_id: str = None,
        account_type: AccountConfig = None,  # to retrieve a specific account type
        account_type_str=None,
        debug_api: bool = False,
        session: httpx.AsyncClient = None,
        return_raw: bool = False,
        is_use_default_account_class: bool = False,
        debug_prn: bool = False,
        **kwargs,
    ):
        """when possible pass is_v2 = True.  To use the query_API over accounts_API"""

        import domolibrary.classes.DomoBootstrap as bsr
        import domolibrary.routes.datacenter as datacenter_routes

        if isinstance(auth, dmda.DomoFullAuth) and is_v2 is None:
            instance_bsr = bsr.DomoBootstrap(auth=auth)

            is_v2 = await instance_bsr.is_feature_accountsv2_enabled(auth)

            if debug_prn:
                print(
                    f"{auth.domo_instance} {'is' if is_v2 else 'is not'} using the v2 beta"
                )

        if is_v2:
            try:
                domo_accounts = await cls._get_accounts_queryapi(
                    auth=auth,
                    debug_api=debug_api,
                    additional_filters_ls=additional_filters_ls,
                    session=session,
                    is_use_default_account_class=is_use_default_account_class,
                    return_raw=return_raw,
                    **kwargs,
                )
            except datacenter_routes.SearchDatacenter_NoResultsFound as e:
                print(e)
                domo_accounts = []
        else:
            domo_accounts = await cls._get_accounts_accountsapi(
                auth=auth,
                debug_api=debug_api,
                session=session,
                is_use_default_account_class=is_use_default_account_class,
                return_raw=return_raw,
                **kwargs,
            )

        if return_raw or len(domo_accounts) == 0:
            return domo_accounts

        if account_id:
            domo_account = next(
                (
                    domo_account
                    for domo_account in domo_accounts
                    if int(domo_account.id) == int(account_id)
                ),
                None,
            )

            if not domo_account:
                raise DomoAccounts_NoAccount(
                    message = f"account_id {account_id} not found",
                    domo_instance=auth.domo_instance,
                    cls= cls
                )

            return domo_account

        if account_name and isinstance(account_name, str):
            domo_accounts = [
                domo_account
                for domo_account in domo_accounts
                if domo_account.name.lower() == account_name.lower()
            ]

        if account_type:
            return [
                domo_account
                for domo_account in domo_accounts
                if domo_account.data_provider_type
                == account_type.value.data_provider_type
            ]

        if account_type_str:
            return [
                domo_account
                for domo_account in domo_accounts
                if domo_account.data_provider_type == account_type_str
            ]

        return domo_accounts

# %% ../../nbs/classes/50_DomoAccount.ipynb 25
@patch_to(DomoAccount)
async def get_accesslist(
    self: DomoAccount,
    auth: dmda.DomoAuth = None,
    return_raw: bool = False,
    session: httpx.AsyncClient = None,
    debug_api: bool = False,
    debug_num_stacks_to_drop: bool = False,
):
    auth = auth or self.auth
    res = await account_routes.get_account_accesslist(
        auth=auth,
        account_id=self.id,
        debug_api=debug_api,
        session=session,
        debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=self.__class__.__name__,
    )

    if return_raw:
        return res

    is_v2 = await self.is_feature_accountsv2_enabled()

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

    return self.accesslist

# %% ../../nbs/classes/50_DomoAccount.ipynb 29
@patch_to(DomoAccounts, cls_method=True)
async def upsert_account(
    cls: DomoAccounts,
    auth: dmda.DomoAuth,
    account_config: AccountConfig = None,
    account_name: str = None,
    account_id: str = None,
    debug_api: bool = False,
    debug_prn: bool = False,
    return_raw: bool = False,
    session: httpx.AsyncClient = None,
    return_search: bool = False,
    **kwargs,
):
    """search for an account and upsert it"""

    if not account_name and not account_id:
        raise UpsertAccount_MatchCriteria(domo_instance=auth.domo_instance)

    acc = None

    try:
        if account_id and acc is None:
            acc = await DomoAccounts.get_accounts(
                account_id=account_id,
                auth=auth,
                debug_api=debug_api,
                session=session,
                # is_use_default_account_class=True,
                **kwargs,
            )

        if account_name and acc is None:
            acc = await DomoAccounts.get_accounts(
                account_name=account_name,
                auth=auth,
                account_type_str=(account_config and account_config.data_provider_type)
                or None,
                debug_api=debug_api,
                session=session,
                **kwargs,
                # is_suppress_undefined_provider_type = True
            )

        if return_search:
            return acc

        if isinstance(acc, list) and len(acc) > 0:
            acc = acc[0]

        if not isinstance(
            acc, (DomoAccount_Default, DomoAccount, DomoAccount_Credential)
        ):
            raise DomoAccounts_NoAccount(
                cls=cls, domo_instance=auth.domo_instance, message="no account found"
            )

        if debug_prn:
            print(f"state after search: {acc.name if acc else 'no account found'}")

        if acc:
            if account_name:
                if debug_prn:
                    print(f"upsert-ing {acc.id}:  updating account_name")

                    await acc.update_name(
                        account_name=account_name,
                        debug_api=debug_api,
                        return_raw=return_raw,
                    )

            if account_config:  # upsert account
                acc.config = account_config

                if debug_prn:
                    print(f"upsertting {acc.id}:  updating config")

                await acc.update_config(debug_api=debug_api, return_raw=return_raw)

            return acc

    except DomoAccounts_NoAccount:
        if debug_prn:
            print(f"creating account {account_name} in {auth.domo_instance}")

        return await DomoAccount.create_account(
            account_name=account_name,
            config=account_config,
            auth=auth,
            debug_api=debug_api,
            return_raw=return_raw,
        )

# %% ../../nbs/classes/50_DomoAccount.ipynb 32
@patch_to(DomoAccount)
async def upsert_share_account_user(
    self: DomoAccount,
    domo_user,
    auth: dmda.DomoAuth = None,
    is_v2: bool = None,
    access_level: ShareAccount = None,  # will default to Read
    debug_api: bool = False,
    debug_prn: bool = False,
    session: httpx.AsyncClient = None,
):
    auth = auth or self.auth

    ls_share = await account_routes.get_account_accesslist(
        auth=auth, account_id=self.id
    )
    res = None

    if domo_user:
        user_id = domo_user.id
        found_user = next(
            (
                obj
                for obj in ls_share.response
                if obj["id"] == user_id and obj["type"] == "USER"
            ),
            None,
        )
        if not found_user:
            res = await self.share(
                domo_user=domo_user,
                auth=auth,
                access_level=access_level,
                debug_api=debug_api,
                debug_prn=debug_prn,
                session=session,
            )

    return res


@patch_to(DomoAccount)
async def upsert_share_account_group(
    self: DomoAccount,
    domo_group,
    auth: dmda.DomoAuth = None,
    is_v2: bool = None,
    access_level: ShareAccount = None,  # will default to Read
    debug_api: bool = False,
    debug_prn: bool = False,
    session: httpx.AsyncClient = None,
):
    auth = auth or self.auth

    ls_share = await account_routes.get_account_accesslist(
        auth=auth, account_id=self.id
    )
    res = None

    if domo_group:
        group_id = domo_group.id
        found_group = next(
            (
                obj
                for obj in ls_share.response
                if obj["id"] == group_id and obj["type"] == "GROUP"
            ),
            None,
        )
        if not found_group:
            res = await self.share(
                domo_group=domo_group,
                auth=auth,
                access_level=access_level,
                debug_api=debug_api,
                debug_prn=debug_prn,
                session=session,
            )

    return res
