# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/routes/auth.ipynb.

# %% auto 0
__all__ = ['AuthError', 'InvalidCredentialsError', 'AccountLockedError', 'InvalidAuthTypeError', 'InvalidInstanceError',
           'NoAccessTokenReturned', 'get_full_auth', 'get_developer_auth', 'who_am_i', 'elevate_user_otp']

# %% ../../nbs/routes/auth.ipynb 2
from typing import Optional, Any, List

import httpx

import domolibrary.client.ResponseGetData as rgd
import domolibrary.client.Logger as lg
import domolibrary.client.DomoError as dmde
import domolibrary.utils.chunk_execution as dmce

# %% ../../nbs/routes/auth.ipynb 5
class AuthError(dmde.RouteError):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)


class InvalidCredentialsError(AuthError):
    """return invalid credentials sent to API"""

    def __init__(self, res, **kwargs):
        super().__init__(res=res, **kwargs)


class AccountLockedError(AuthError):
    """return invalid credentials sent to API"""

    def __init__(self, res, **kwargs):
        super().__init__(res=res, **kwargs)


class InvalidAuthTypeError(AuthError):
    """return invalid Auth type sent to API"""

    def __init__(
        self,
        res = None,
        required_auth_type: Optional[Any] = None,
        required_auth_type_ls: Optional[List[Any]] = None,
        domo_instance: Optional[str] = None,
        **kwargs
    ):

        message = f"This API rquires {required_auth_type.__name__ if required_auth_type else ', '.join([auth_type.__name__ for auth_type in required_auth_type_ls])}"

        super().__init__(message=message, res=res, domo_instance=domo_instance, **kwargs)


class InvalidInstanceError(AuthError):
    """return if invalid domo_instance sent to API"""

    def __init__(self, res, **kwargs):
        super().__init__(res=res, **kwargs)


class NoAccessTokenReturned(AuthError):
    def __init__(self, res, **kwargs):
        super().__init__(res=res, **kwargs)

# %% ../../nbs/routes/auth.ipynb 7
async def get_full_auth(
    domo_instance: str,  # domo_instance.domo.com
    domo_username: str,  # email address
    domo_password: str,
    auth: Any = None,
    session: Optional[httpx.AsyncClient] = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
    return_raw: bool = False,
) -> rgd.ResponseGetData:
    """uses username and password authentication to retrieve a full_auth access token"""

    import domolibrary.client.get_data as gd

    domo_instance = domo_instance or auth.domo_instance

    url = f"https://{domo_instance}.domo.com/api/content/v2/authentication"

    body = {
        "method": "password",
        "emailAddress": domo_username,
        "password": domo_password,
    }

    res = await gd.get_data(
        auth=auth,
        method="POST",
        url=url,
        body=body,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
        session=session,
        return_raw=return_raw,
    )

    if return_raw:
        return res

    if res.status == 403 and res.response == "Forbidden":
        raise InvalidInstanceError(
            res = res,
            domo_instance = domo_instance
        )

    if res.is_success and isinstance(res.response, dict):

        if res.response.get("reason") == "INVALID_CREDENTIALS":
            res.is_success = False

            raise InvalidCredentialsError(
                domo_instance = domo_instance,
                res = res

            )

        if res.response.get("reason") == "ACCOUNT_LOCKED":
            res.is_success = False

            raise AccountLockedError(
                domo_instance = domo_instance,
                res =res
            )

        if res.response == {} or res.response == "":  # no access token
            res.is_success = False

            raise NoAccessTokenReturned(
                domo_instance= domo_instance,
                res = res
            )

    if not res.response.get("sessionToken"):
        res.is_success = True

        raise InvalidCredentialsError(
            domo_instance = domo_instance,
            res = res
        )

    return res

# %% ../../nbs/routes/auth.ipynb 15
async def get_developer_auth(
    domo_client_id: str,
    domo_client_secret: str,
    auth : Any = None,
    session: Optional[httpx.AsyncClient] = None,
    debug_api: bool = False,
    parent_class: str = None,
    debug_num_stacks_to_drop= 1,
    return_raw: bool = False
) -> rgd.ResponseGetData:
    
    """
    only use for authenticating against apis documented under developer.domo.com
    """

    import domolibrary.client.get_data as gd

    url = "https://api.domo.com/oauth/token?grant_type=client_credentials"

    if not session:
        is_close_session = True
    
    # add basic auth to the session
    session = httpx.AsyncClient(
            auth=httpx.BasicAuth(domo_client_id, domo_client_secret)
        )
    

    res = await gd.get_data(method="GET",
                            url=url,
                            session = session,
                            debug_api = debug_api,
                            auth = auth,
                            num_stacks_to_drop = debug_num_stacks_to_drop,
                            parent_class = parent_class, 
                            return_raw = return_raw
                            )

    
    if is_close_session:
        await session.aclose()

    if return_raw:
        return res
     
    if res.status == 401 and res.response == "Unauthorized":
        res.is_success = False
        raise InvalidCredentialsError(
            res = res,
        )

    return res

# %% ../../nbs/routes/auth.ipynb 19
async def who_am_i(
    auth: Any,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
    debug_num_stacks_to_drop=0,
    debug_api: bool = False,
    return_raw: bool = False,
):
    """
    will attempt to validate against the 'me' API.
    This is the same authentication test the Domo Java CLI uses.
    """

    import domolibrary.client.get_data as gd

    url = f"https://{auth.domo_instance}.domo.com/api/content/v2/users/me"

    res = await gd.get_data(
        auth=auth,
        url=url,
        method="GET",
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
        session=session,
        return_raw=return_raw,
    )

    if return_raw:
        return res

    if res.status == 403 and res.response == "Forbidden":
        raise InvalidInstanceError(
            res = res
        )

    if res.status == 401 and res.response == "Unauthorized":
        res.is_sucess = False

        raise InvalidCredentialsError(
            res = res,
        )

    return res

# %% ../../nbs/routes/auth.ipynb 21
async def elevate_user_otp(
    auth,
    one_time_password: str,
    user_id: str = None,
    debug_api: bool = False,
    debug_num_stacks_to_drop=1,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
):
    import domolibrary.client.get_data as gd

    
    if not auth.user_id and not user_id:
        await auth.who_am_i()

    user_id = user_id or auth.user_id
    
    url = f"https://{auth.domo_instance}.domo.com/api/identity/v1/authentication/elevations/{user_id}"

    body = {"timeBasedOneTimePassword": one_time_password}

    res = await gd.get_data(
        auth=auth,
        method="PUT",
        url=url,
        body=body,
        debug_api=debug_api,
        num_stacks_to_drop=debug_num_stacks_to_drop,
        parent_class=parent_class,
        session = session
    )

    if not res.is_success:
        raise InvalidCredentialsError(
            res=res
        )
    
    return res
