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

# %% auto 0
__all__ = ['DAC_NoTargetInstance', 'DAC_NoTargetUser', 'DAC_NoPassword', 'DAC_NoUserName', 'DAC_NoAccessToken', 'DAC_ValidAuth',
           'DomoAccount_Credential']

# %% ../../nbs/classes/50_DomoAccount_Credential.ipynb 3
from typing import Callable

from dataclasses import dataclass, field
import httpx

import domolibrary.client.DomoError as dmde
import domolibrary.client.DomoAuth as dmda


import domolibrary.classes.DomoAccount_Default as dmacb
import domolibrary.classes.DomoAccessToken as dmact
import domolibrary.classes.DomoUser as dmdu
import domolibrary.utils.convert as dmcv

from nbdev.showdoc import patch_to

# %% ../../nbs/classes/50_DomoAccount_Credential.ipynb 5
class DAC_NoTargetInstance(dmde.ClassError):
    def __init__(self, cls_instance):
        super().__init__(
            message=f"no target_instance on class - {cls_instance.name}",
            cls_instance=cls_instance,
        )


class DAC_NoTargetUser(dmde.ClassError):
    def __init__(self, cls_instance):
        super().__init__(
            message=f"no target_user on class - {cls_instance.name}",
            cls_instance=cls_instance,
        )


class DAC_NoPassword(dmde.ClassError):
    def __init__(self, cls_instance):
        super().__init__(
            message=f"no password stored in account - {cls_instance.name}",
            cls_instance=cls_instance,
        )


class DAC_NoUserName(dmde.ClassError):
    def __init__(self, cls_instance):
        super().__init__(
            message=f"no username stored in account - {cls_instance.name}",
            cls_instance=cls_instance,
        )


class DAC_NoAccessToken(dmde.ClassError):
    def __init__(self, cls_instance):
        super().__init__(
            message=f"no access_token stored in account - {cls_instance.name}",
            cls_instance=cls_instance,
        )


class DAC_ValidAuth(dmde.ClassError):
    def __init__(self, cls_instance, message=None):
        super().__init__(
            message=message
            or f"{cls_instance.name} no valid auth retrieved for domo_instance - {cls_instance.target_instance}",
            cls_instance=cls_instance,
        )

# %% ../../nbs/classes/50_DomoAccount_Credential.ipynb 6
@dataclass
class DomoAccount_Credential(dmacb.DomoAccount_Default):

    target_instance: str = None

    is_valid_full_auth: bool = None
    is_valid_token_auth: bool = None

    _token_auth: dmda.DomoAuth = field(repr=False, default=None)
    _full_auth: dmda.DomoAuth = field(repr=False, default=None)

    target_auth: dmda.DomoAuth = field(default=None)
    target_user: dmdu.DomoUser = field(default=None)

    # def __post_init__(self):
    #     if not self.target_instance:
    #         raise DAC_NoTargetInstance(self)

    @classmethod
    def _class_from_json(
        cls,
        obj: dict,
        is_admin_summary: bool = True,
        auth: dmda.DomoAuth = None,
        **kwargs,
    ):
        return cls._default_from_json(
            obj=obj,
            is_admin_summary=is_admin_summary,
            auth=auth,
            target_instance=kwargs.get("target_instance"),
        )

    def set_password(self, password: str):
        self.Config.password = password
        return True

    def set_username(self, username: str):
        self.Config.username = username
        return True

    def set_access_token(self, access_token: str):
        self.Config.domo_access_token = access_token
        return True

    async def test_full_auth(
        self, debug_api: bool = False, session: httpx.AsyncClient = None
    ):
        """
        1. generates full auth object
        2. tests full auth object
        """
        self.is_valid_full_auth = False

        if not self.Config.username:
            raise DAC_NoUserName(self)

        if not self.Config.password:
            raise DAC_NoPassword(self)

        if not self.target_instance:
            raise DAC_NoTargetInstance(self)

        self._full_auth = dmda.DomoFullAuth(
            domo_instance=self.target_instance,
            domo_username=self.Config.username,
            domo_password=self.Config.password,
        )

        try:
            await self._full_auth.print_is_token(debug_api=debug_api, session=session)
            self.is_valid_full_auth = True

        except dmda.AuthError as e:
            dmcv.print_md(f"🤯 test_full_auth for: ***{self.name}*** returned {e}")

            self.is_valid_full_auth = False

        return self.is_valid_full_auth

    async def test_token_auth(
        self, debug_api: bool = False, session: httpx.AsyncClient = None
    ):
        """
        1. generates token auth object
        2. tests token auth object
        """

        self.is_valid_token_auth = False

        if not self.Config.domo_access_token:
            raise DAC_NoAccessToken(self)

        if not self.target_instance:
            raise DAC_NoTargetInstance(self)

        self._token_auth = dmda.DomoTokenAuth(
            domo_instance=self.target_instance,
            domo_access_token=self.Config.domo_access_token,
        )

        try:
            await self._token_auth.print_is_token(debug_api=debug_api, session=session)
            self.is_valid_token_auth = True
            self.target_auth = self._token_auth

        except dmda.AuthError as e:
            dmcv.print_md(f"🤯 test_token_auth for: ***{self.name}*** returned {e}")
            self.is_valid_token_auth = False

        return self.is_valid_token_auth

    def _set_target_auth(
        self,
        valid_backup_auth: dmda.DomoAuth = None,  # validated backup_auth
    ):
        """
        generates an auth object using the best of Token Auth < Full Auth
        uses a validated backup_auth as a failover target_auth
        """

        target_auth = None

        if self.is_valid_token_auth:
            target_auth = self._token_auth

        if self.is_valid_full_auth:
            target_auth = self._full_auth

        if not target_auth and (valid_backup_auth and valid_backup_auth.is_valid_token):
            target_auth = valid_backup_auth

        if not target_auth:
            raise DAC_ValidAuth(self)

        self.target_auth = target_auth

        return self.target_auth

    async def test_auths(
        self,
        backup_auth: dmda.DomoAuth = None,
        debug_api: bool = False,
        session: httpx.AsyncClient = None,
    ):
        ## test token auth
        try:
            await self.test_token_auth(debug_api=debug_api, session=session)

        except dmde.DomoError as e:
            print(f"testing token: {self.name}: {e}")

        ## test full auth
        try:
            await self.test_full_auth(debug_api=debug_api, session=session)

        except dmde.DomoError as e:
            print(f"testing full auth: {self.name}: {e}")

        ## generate target_auth
        try:
            self._set_target_auth(valid_backup_auth=backup_auth)

        except DAC_ValidAuth as e:
            print(f"{self.name}: unable to generate valid target_auth: {e}")

        return self.to_json()

    
    def to_json(self):
        return {
            "account_id": self.id,
            "alias": self.name,
            "target_instance": self.target_instance,
            "is_valid_full_auth": self.is_valid_full_auth,
            "is_valid_token_auth": self.is_valid_token_auth,
        }

# %% ../../nbs/classes/50_DomoAccount_Credential.ipynb 7
@patch_to(DomoAccount_Credential)
async def get_target_user(
    self,
    user_email: None,  # defaults to username from the AccountConfig object
    backup_auth: dmda.DomoAuth = None,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
    is_test_auths: bool = False,
):
    user_email = self.Config.username or user_email

    if not user_email:
        raise DAC_NoUserName(self)

    if is_test_auths or not self.target_auth:
        self.test_auths(session=session, debug_api=debug_api, backup_auth=backup_auth)

    if not self.target_auth:
        raise DAC_ValidAuth(
            self,
            message="no target_auth - run with is_test_auths = True and/or pass a valid backup_auth",
        )

    self.target_user = await dmdu.DomoUsers.by_email(
        email_ls=[user_email],
        auth=self.target_auth,
        debug_api=debug_api,
        session=session,
    )

    return self.target_user


@patch_to(DomoAccount_Credential)
async def update_target_user_password(
    self: DomoAccount_Credential,
    new_password: str,
    user_email: str = None,  # defaults to username from the AccountConfig object
    is_test_auths: bool = False,
    is_update_account: bool = True,
    backup_auth: dmda.DomoAuth = None,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
):

    if is_test_auths or not self.target_auth:
        self.test_auths(session=session, debug_api=debug_api, backup_auth=backup_auth)

    if not self.target_user:
        await self.get_target_user(
            debug_api=debug_api,
            session=session,
            user_email=user_email,
            is_test_auths=False,
        )

    await self.target_user.reset_password(
        new_password=new_password, debug_api=debug_api, session=session
    )

    self.set_password(new_password)

    if is_update_account:
        await self.update_config(debug_api=debug_api, session=session)

    return self


@patch_to(DomoAccount_Credential)
async def reset_access_token(
    self,
    token_name=None,
    duration_in_days=90,
    user_email: str = None,  # defaults to username from the AccountConfig object
    is_test_auths: bool = False,
    is_update_account: bool = True,
    backup_auth: dmda.DomoAuth = None,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
):

    if is_test_auths or not self.target_auth:
        self.test_auths(session=session, debug_api=debug_api, backup_auth=backup_auth)

    if not self.target_user:
        await self.get_target_user(
            debug_api=debug_api,
            session=session,
            user_email=user_email,
            is_test_auths=False,
        )

    if not token_name:
        token_name = self.target_user.email_address

    domo_access_tokens = await self.target_user.get_access_tokens(
        session=session, debug_api=debug_api
    )

    domo_access_token = next(
        (dat for dat in domo_access_tokens if dat.name.lower() == token_name.lower()),
        None,
    )

    if domo_access_token:
        await domo_access_token.regenerate(
            duration_in_days=duration_in_days, session=session, debug_api=debug_api
        )

    else:
        domo_access_token = await dmact.DomoAccessToken.generate(
            duration_in_days=duration_in_days,
            token_name=token_name,
            auth=self.target_auth,
            owner=self.target_user,
            debug_api=debug_api,
            session=session,
        )

    self.set_access_token(domo_access_token.token)

    if is_update_account:
        await self.update_config(debug_api=debug_api, session = session)

    return self
