"""Fill in a module description here"""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/LocalAccount/00_DJ_WorkspaceAccount.ipynb.

# %% auto 0
__all__ = ['DJA_UpdateCredsError', 'DJ_WorkspaceAccount']

# %% ../nbs/LocalAccount/00_DJ_WorkspaceAccount.ipynb 3
class DJA_UpdateCredsError(dlcr.ClassError):
    def __init__(self, cred_type, local_account_name, additional_message=None):
        message = f"unable to update {cred_type} for - {local_account_name}"

        if additional_message:
            message = f"{message}\n\n{additional_message}"

        super().__init__(message)

# %% ../nbs/LocalAccount/00_DJ_WorkspaceAccount.ipynb 4
import domojupyter.classes.DomoJupyter as dmdj

@dataclass
class DJ_WorkspaceAccount(dmdj.DomoJupyterAccount):
    target_instance: str

    dj_workspace: Any = field(repr=False)  # DJ_Workspace

    local_account_name: str
    local_domo_account: dmacc.DomoAccount = field(repr=False, default=None)
    local_creds: dict = field(repr=False, default=None)

    is_valid_full_auth: bool = None
    is_valid_token_auth: bool = None

    is_domo_account_exists: bool = False

    _target_token_auth: dmda.DomoAuth = None
    _target_full_auth: dmda.DomoAuth = None

    target_auth: dmda.DomoAuth = field(repr=False, default=None)
    backup_auth: dmda.DomoAuth = field(repr=False, default=None)

    username: str = None
    password: str = field(repr=False, default=None)
    access_token: str = field(repr=False, default=None)

    account_config: dmacc.AccountConfig = None

    


    @classmethod
    def from_workspace_by_account_name(
        cls,
        domo_instance: str,
        local_account_name: str,
        dj_workspace: Any,
    ):
        return cls(
            target_instance=domo_instance,
            local_account_name=local_account_name,
            dj_workspace=dj_workspace,
        )

# %% ../nbs/LocalAccount/00_DJ_WorkspaceAccount.ipynb 6
@patch_to(DJ_WorkspaceAccount)
async def _search_domo_groups_by_name(
    self, auth: dmda.DomoAuth, group_names: List[str]
):
    await dmdg.DomoGroups.toggle_system_group_visibility(
        is_hide_system_groups=False, auth=auth
    )

    await asyncio.sleep(1)

    domo_groups = await dmce.gather_with_concurrency(
        *[
            dmdg.DomoGroup.search_by_name(group_name=group_name, auth=auth)
            for group_name in group_names
        ],
        n=10,
    )
    await dmdg.DomoGroups.toggle_system_group_visibility(
        is_hide_system_groups=True, auth=auth
    )
    return domo_groups


@patch_to(DJ_WorkspaceAccount)
async def _upsert_group(
    self,
    auth: dmda.DomoAuth,
    group_name: str,
    group_owner_names: list[str] = [
        "Role: sie_instance_admin",
        "Role: sie_dde_instance_admin",
    ],
    debug_api: bool = False,
):

    domo_group = await dmdg.DomoGroup.upsert(
        group_name=group_name,
        group_type=dmdg.GroupType_Enum["CLOSED"].value,
        description=f"updated via {dt.date.today()}",
        auth=auth,
        debug_api=debug_api,
    )

    domo_group_owners = await self._search_domo_groups_by_name(
        auth=auth, group_names=group_owner_names
    )

    await domo_group.Membership.add_owners(add_owner_ls=domo_group_owners)

    return domo_group


@patch_to(DJ_WorkspaceAccount)
def _generate_account_config(self):
    account_config = dmacc.AccountConfig.domo_access_token.value(
        username=self.username,
        password=self.password,
        domo_access_token=self.domo_access_token,
    )

    return account_config


@patch_to(DJ_WorkspaceAccount)
async def _upsert_account_and_share_with_default_group(
    self,
    account_config: dmacc.AccountConfig,
    account_name: str,
    auth: dmda.DomoAuth,
    debug_api: bool = False,
    default_share_group: dmdg.DomoGroup = None,
):

    domo_account = await dmacc.DomoAccounts.upsert_account(
        account_config=account_config,
        account_name=account_name,
        auth=auth,
        debug_api=debug_api,
    )

    if default_share_group:
        share_res = await domo_account._share_v2(group_id=default_share_group.id)

    return domo_account


@patch_to(DJ_WorkspaceAccount)
async def _upsert_account(
    self,
    auth: dmda.DomoAuth,
    account_name: str,
    default_share_group_name: str = None,
    default_share_group_owner_names=[
        "Role: sie_instance_admin",
        "Role: sie_dde_instance_admin",
    ],
    debug_api: bool = False,
    is_test: bool = False,
):
    account_config = self._generate_account_config()

    group_name = default_share_group_name or self.dj_workspace.default_share_group_name

    default_share_group = None

    if group_name:
        default_share_group = await self._upsert_group(
            auth=auth,
            group_name=group_name,
            group_owner_names=default_share_group_owner_names
            or self.default_share_group_name,
            debug_api=debug_api,
        )

    if is_test:
        return account_config, default_share_group

    domo_account = await self._upsert_account_and_share_with_default_group(
        auth=auth,
        account_config=account_config,
        account_name=account_name,
        default_share_group=default_share_group,
        debug_api=debug_api,
    )

    return domo_account


@patch_to(DJ_WorkspaceAccount)
async def upsert_local_account(self, is_test=True, debug_api: bool = False):
    try:
        return await self._upsert_account(
            auth=self.dj_workspace.local_auth,
            account_name=self.local_account_name,
            is_test=is_test,
            debug_api=debug_api,
        )
    except dmde.DomoError as e:
        print(e)
        return None


@patch_to(DJ_WorkspaceAccount)
async def upsert_target_account(
    self,
    target_account_name: str,
    backup_auth: dmda.DomoAuth = None,
    is_test=True,
    debug_api: bool = False,
):
    try:
        target_auth = await self.generate_target_auth(backup_auth=backup_auth)
    except DJA_ValidAuth as e:
        raise DJA_UpdateCredsError(
            cred_type="target_account",
            local_account_name=target_account_name,
            additional_message=str(e),
        ) from e

        return await self._upsert_account(
            auth=target_auth,
            account_name=target_account_name,
            is_test=is_test,
            debug_api=debug_api,
        )

    except dmde.DomoError as e:
        print(e)
        return None


@patch_to(DJ_WorkspaceAccount)
async def upsert_remote_account(
    self,
    remote_account_name: str,
    auth: dmda.DomoAuth,
    is_test=True,
    debug_api: bool = False,
):
    try:
        return await self._upsert_account(
            auth=auth,
            account_name=remote_account_name,
            is_test=is_test,
            debug_api=debug_api,
        )
    except dmde.DomoError as e:
        print(e)
        return None


@patch_to(DJ_WorkspaceAccount)
async def upsert_accounts(
    self,
    target_account_name: str = None,
    target_auth_backup: dmda.DomoAuth = None,
    remote_account_name: str = None,
    remote_auth_ls: List[dmda.DomoAuth] = None,
    debug_api: bool = False,
):
    """attempts to upsert account in target instance AND deploy account to remote instances"""
    target_acc = await self.upsert_target_account(
        target_account_name=target_account_name or self.local_account_name,
        backup_auth=target_auth_backup,
        is_test=False,
        debug_api=debug_api,
    )

    local_acc = await self.upsert_local_account(is_test=False, debug_api=debug_api)

    remote_accs = None
    if remote_auth_ls:
        remote_accs = await dmce.gather_with_concurrency(
            *[
                self.upsert_remote_account(
                    remote_account_name=remote_account_name or self.local_account_name,
                    auth=r_auth,
                )
                for r_auth in remote_auth_ls
            ],
            n=10,
        )

    return {"target": target_acc, "local": local_acc, "remotes": remote_accs}

# %% ../nbs/LocalAccount/00_DJ_WorkspaceAccount.ipynb 9
class AccessToken_NotExpired(dlcr.ClassError):
    def __init__(self, token_name):
        super().__init__(f"token {token_name} is not expired")


@patch_to(DJ_WorkspaceAccount)
async def regenerate_access_token(
    self,
    domo_user: dmdu.DomoUser,
    auth: dmda.DomoAuth,
    token_name: str,
    duration_in_days: int = 90,
    access_token_days_to_expiry_threshold: int = 7,
    is_force_regeneration: bool = False,
    raise_exception: bool = True,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
):

    domo_config = dmic.DomoInstanceConfig(auth=auth)

    if not is_force_regeneration:
        domo_access_tokens = await domo_config.get_access_tokens(
            debug_api=debug_api, session=session
        )

        domo_access_token = next(
            (
                token
                for token in domo_access_tokens
                if token.owner == domo_user and token.name == token_name
            ),
            None,
        )

        if (
            domo_access_token
            and access_token_days_to_expiry_threshold
            <= (domo_access_token.expiration_date - dt.datetime.now()).days
        ):
            if raise_exception:
                raise AccessToken_NotExpired(token_name)

            return domo_access_token

    domo_access_token = await domo_config.regenerate_access_token(
        domo_user=domo_user,
        token_name=token_name,
        session=session,
        duration_in_days=duration_in_days,
        debug_api=debug_api,
    )
    self.domo_access_token = domo_access_token.token

    return domo_access_token


@patch_to(DJ_WorkspaceAccount)
async def regenerate_target_access_token(
    self,
    token_name: str = None,
    duration_in_days: int = 90,
    access_token_days_to_expiry_threshold: int = 7,
    is_force_regeneration: bool = False,
    debug_api: bool = False,
    trigger_upsert_accounts: bool = True,
    target_account_name: str = None,
    target_auth_backup: dmda.DomoAuth = None,
    remote_account_name: str = None,
    remote_auth_ls: List[dmda.DomoAuth] = None,
):

    if not self.is_valid_token_auth:
        is_force_regeneration = True

    target_auth = await self.generate_target_auth(backup_auth=target_auth_backup)

    domo_user = await dmdu.DomoUsers.by_email(
        email_ls=[self.username], auth=target_auth
    )

    domo_access_token = await self.regenerate_access_token(
        domo_user=domo_user,
        auth=target_auth,
        token_name=token_name or self.local_account_name,
        duration_in_days=duration_in_days,
        access_token_days_to_expiry_threshold=access_token_days_to_expiry_threshold,
        is_force_regeneration=is_force_regeneration,
        raise_exception=False,
        debug_api=debug_api,
    )

    if trigger_upsert_accounts:
        return await self.upsert_accounts(
            target_account_name=target_account_name or self.local_account_name,
            target_auth_backup=target_auth_backup,
            remote_account_name=remote_account_name or self.local_account_name,
            remote_auth_ls=remote_auth_ls,
            debug_api=debug_api,
        )

    return domo_access_token

# %% ../nbs/LocalAccount/00_DJ_WorkspaceAccount.ipynb 10
class AccessToken_NotExpired(dlcr.ClassError):
    def __init__(self, token_name):
        super().__init__(f"token {token_name} is not expired")


@patch_to(DJ_WorkspaceAccount)
async def regenerate_access_token(
    self,
    domo_user: dmdu.DomoUser,
    auth: dmda.DomoAuth,
    token_name: str,
    duration_in_days: int = 90,
    access_token_days_to_expiry_threshold: int = 7,
    is_force_regeneration: bool = False,
    raise_exception: bool = True,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
):

    domo_config = dmic.DomoInstanceConfig(auth=auth)

    if not is_force_regeneration:
        domo_access_tokens = await domo_config.get_access_tokens(
            debug_api=debug_api, session=session
        )

        domo_access_token = next(
            (
                token
                for token in domo_access_tokens
                if token.owner == domo_user and token.name == token_name
            ),
            None,
        )

        if (
            domo_access_token
            and access_token_days_to_expiry_threshold
            <= (domo_access_token.expiration_date - dt.datetime.now()).days
        ):
            if raise_exception:
                raise AccessToken_NotExpired(token_name)

            return domo_access_token

    domo_access_token = await domo_config.regenerate_access_token(
        domo_user=domo_user,
        token_name=token_name,
        session=session,
        duration_in_days=duration_in_days,
        debug_api=debug_api,
    )
    self.domo_access_token = domo_access_token.token

    return domo_access_token


@patch_to(DJ_WorkspaceAccount)
async def regenerate_target_access_token(
    self,
    token_name: str = None,
    duration_in_days: int = 90,
    access_token_days_to_expiry_threshold: int = 7,
    is_force_regeneration: bool = False,
    debug_api: bool = False,
    trigger_upsert_accounts: bool = True,
    target_account_name: str = None,
    target_auth_backup: dmda.DomoAuth = None,
    remote_account_name: str = None,
    remote_auth_ls: List[dmda.DomoAuth] = None,
):

    if not self.is_valid_token_auth:
        is_force_regeneration = True

    target_auth = await self.generate_target_auth(backup_auth=target_auth_backup)

    domo_user = await dmdu.DomoUsers.by_email(
        email_ls=[self.username], auth=target_auth
    )

    domo_access_token = await self.regenerate_access_token(
        domo_user=domo_user,
        auth=target_auth,
        token_name=token_name or self.local_account_name,
        duration_in_days=duration_in_days,
        access_token_days_to_expiry_threshold=access_token_days_to_expiry_threshold,
        is_force_regeneration=is_force_regeneration,
        raise_exception=False,
        debug_api=debug_api,
    )

    if trigger_upsert_accounts:
        return await self.upsert_accounts(
            target_account_name=target_account_name or self.local_account_name,
            target_auth_backup=target_auth_backup,
            remote_account_name=remote_account_name or self.local_account_name,
            remote_auth_ls=remote_auth_ls,
            debug_api=debug_api,
        )

    return domo_access_token
