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

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

# %% ../../nbs/classes/50_DomoAccount.ipynb 3
from domolibrary.routes.account import (
    ShareAccount_V1_AccessLevel,
    ShareAccount_V2_AccessLevel,
    ShareAccount,
    GetAccount_NoMatch,
    ShareAccount_Error,
    ShareAccount_Error_AlreadyShared,
    DeleteAccount_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
from typing import Any
from enum import Enum

import httpx
import datetime as dt


from nbdev.showdoc import patch_to

import domolibrary.utils.convert as cd
import domolibrary.utils.DictDot as util_dd
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_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 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 21
@dataclass
class DomoAccounts:
    auth: dmda.DomoAuth

# %% ../../nbs/classes/50_DomoAccount.ipynb 22
@staticmethod
@patch_to(DomoAccounts)
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
        ],
    )


@patch_to(DomoAccounts, cls_method=True)
async def _get_accounts_queryapi(
    cls: DomoAccounts,
    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
    ]


@patch_to(DomoAccounts, cls_method=True)
async def get_accounts(
    cls: DomoAccounts,
    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,
    is_suppress_undefined_provider_type: bool = False,
    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 GetAccount_NoMatch(
                account_id=account_id, domo_instance=auth.domo_instance
            )

        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
@dataclass
class Account_Accesslist_Share:
    entity: Any
    access_level: ShareAccount
    auth: dmda.DomoAuth

    @staticmethod
    async def _get_entity(obj, auth: dmda.DomoAuth):
        if obj["type"] == "USER":
            import domolibrary.classes.DomoUser as dmu

            return await dmu.DomoUser.get_by_id(user_id=obj["id"], auth=auth)

        if obj["type"] == "GROUP":
            import domolibrary.classes.DomoGroup as dmg

            return await dmg.DomoGroup.get_by_id(group_id=obj["id"], auth=auth)

        return None

    @staticmethod
    def _get_access_level(access_level, is_v2: int):
        if is_v2 == 1:
            return ShareAccount_V2_AccessLevel[access_level]

        else:
            return ShareAccount_V1_AccessLevel[access_level]

    @classmethod
    async def _from_json(
        cls: ShareAccount, obj, auth: dmda.DomoAuth, is_v2: bool = False
    ):
        return cls(
            entity=await cls._get_entity(obj, auth=auth),
            auth=auth,
            access_level=cls._get_access_level(obj["accessLevel"], is_v2),
        )


@dataclass
class Account_Accesslist:
    account: DomoAccount
    auth: dmda.DomoAuth
    domo_users = None
    domo_groups = None

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

    if return_raw:
        return res

    is_v2 = await self.is_feature_accountsv2_enabled()

    self.accesslist = await dmce.gather_with_concurrency(
        *[
            Account_Accesslist_Share._from_json(obj=obj, auth=auth, is_v2=is_v2)
            for obj in res.response["list"]
        ],
        n=10,
    )
    return self.accesslist

# %% ../../nbs/classes/50_DomoAccount.ipynb 30
@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,
    **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
    res = None

    if account_id:
        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 acc and account_name:
            if debug_prn:
                print(f"upsertting {acc.id}:  updating account_name")
            res = await acc.update_name(
                account_name=account_name, debug_api=debug_api, return_raw=return_raw
            )

    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 isinstance(acc, list) and len(acc) > 0 and isinstance(acc[0], DomoAccount):
            acc = acc[0]

        else:
            acc = None

    if acc and account_config:  # upsert account
        acc.config = account_config

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

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

    if return_raw and acc:
        return res

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

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

    return acc

# %% ../../nbs/classes/50_DomoAccount.ipynb 33
@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["list"]
                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["list"]
                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
