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

# %% auto 0
__all__ = ['sync_role', 'UpsertRoleConfig', 'sync_user', 'UpsertUserConfig', 'get_group_manage_grants', 'sync_group',
           'UpsertGroupConfig', 'generate_user_accesstoken', 'Config_GenerateUserAccessToken']

# %% ../nbs/00_FactoryUser.ipynb 2
from domolibrary_extensions.utils.factory import (
    factory_function,
    FactoryLogs, 
    FactoryResponse, FactoryConfig, FactoryMessage)

from domolibrary.client.DomoAuth import DomoAuth
from domolibrary.classes.DomoRole import DomoRole, DomoRoles
from domolibrary.classes.DomoUser import DomoUser
from domolibrary.classes.DomoGroup import DomoGroup, DomoGroups

# %% ../nbs/00_FactoryUser.ipynb 3
from typing import List, Callable
from dataclasses import dataclass, field
import httpx

import domolibrary.classes.DomoInstanceConfig as dmic

import domolibrary.classes.DomoRole as dmdr
import domolibrary.classes.DomoUser as dmdu
import domolibrary.classes.DomoAccount as dmac 
import domolibrary_extensions.utils.factory as defc

# %% ../nbs/00_FactoryUser.ipynb 4
@factory_function(config_id_col = 'role_name')
async def sync_role(
    logs: FactoryLogs,
    res : FactoryResponse,
    config : FactoryConfig,
    debug_api: bool = False,
    session : httpx.AsyncClient = None):
    
    res.location = config.auth.domo_instance
    res.response = False
    auth = config.auth
    
    # STAGE_1 = GET GRANTS
    grant_ls = config.grant_ls
    step = FactoryMessage( stage="retrieve grants", is_success=False)
    res.add_message( step )
    
    if grant_ls:
        step.message = "using grants from config"
    
    # STAGE_2 = USE ALL GRANTS
    if config.is_all_grants:
        try:
            step_all_grants = FactoryMessage( stage="get super_admin grants", is_success=False)
            res.add_message( step_all_grants )

            domo_instance = dmic.DomoInstanceConfig(auth = auth)
            grant_ls = await domo_instance.get_grants(session = session)     
            step_all_grants.message = "using all grants"
            step_all_grants.is_success=True
            
        except Exception as e:
            step.is_success = False
            step.message = str(e)

    if not grant_ls:
        res.response = "no grant list"
        return res
    

    step.is_success = True
    config.grant_ls = grant_ls
            
    # STAGE_3 = upsert DOMO_ROLE
    step = FactoryMessage( stage="upsert role", is_success=False)
    res.add_message( step )
    
    domo_role = config.domo_role
    try:
        domo_role =  await DomoRoles.upsert_role(auth=auth,
                                                 name=config.role_name,
                                                 description=config.role_description,
                                                 grant_ls=grant_ls)
        
        step.is_success = True
        step.message = f"{domo_role.name} upserted"
    
    except Exception as e:
            step.is_success = False
            step.message = str(e)
    
    if not domo_role:
        res.response = "no domo role"
        return res
    
    # STAGE_4 = config DEFAUL_ROLE
    if config.is_default_role:
        step = FactoryMessage( stage="set default role", is_success=False)
        res.add_message( step )
        
        try:
            await domo_role.set_as_default_role(session = session)
            step.is_success = True
            step.message = f"{domo_role.name} set to default role in {auth.domo_instance}"
        
        except Exception as e:
            step.is_success = False
            step.message = str(e)
        
    res.response = domo_role
    return res

# %% ../nbs/00_FactoryUser.ipynb 5
@dataclass
class UpsertRoleConfig(FactoryConfig):
    role_name: str = None
    role_description:str = None
    grant_ls: List[str] = None
    user_ls: List[int] = None
    
    is_all_grants : bool = False
    is_default_role: bool = False
    
    domo_role : DomoRole = None
    
    factory_fn_ls : List[Callable] = field(default_factory = lambda:[sync_role])


# %% ../nbs/00_FactoryUser.ipynb 6
@factory_function(config_id_col = 'email')
async def sync_user(
    logs: FactoryLogs,
    res : FactoryResponse,
    config : FactoryConfig,
    debug_api: bool = False,
    session : httpx.AsyncClient = None):
    
    res.location = config.auth.domo_instance
    
    res.response = False
    
    auth = config.auth
    
    # STAGE_1 = DOMO ROLE OR DEFAULT ROLE
    domo_role = config.domo_role
    step = FactoryMessage( stage="retrieve domo role", is_success=False)
    res.add_message( step )
    
    if not domo_role:
        try:
            domo_role = await dmdr.DomoRoles.get_default_role(auth = auth,debug_api = debug_api, session = session)
            
        except Exception as e:
            step.is_success = False
            step.message = str(e)

    if not domo_role:
        res.response = "no domo role"
        return res
    
    step.message = f"using role {domo_role.id} - {domo_role.name}"
    step.is_success = True
    config.domo_role = domo_role
            
    # STAGE_2 = DOMO_USER
    domo_user = config.domo_user
    step = FactoryMessage( stage="upsert user", is_success=False)
    res.add_message( step )
    
    try:
        domo_user  = await dmdu.DomoUsers.upsert_user(
            auth = auth,
            email_address = config.email,
            display_name = config.display_name,
            session = session,
            role_id = domo_role.id)                    
    
    except Exception as e:
        step.message = e
        step.is_success = False
    
    if not domo_user:
        res.response = "no domo user"
        return res

    step.message = f"upsert user {domo_user.id} successful"
    step.is_success = True
    config.domo_user = domo_user
    
    res.response = domo_user
    
    password = config.password
    if not password:
        return res
    
    # STEP_3 = SET PASSWORD
    step = FactoryMessage( stage="set password", is_success=False)
    res.add_message( step )
    domo_user.password = password
        
    try:
        await domo_user.reset_password(new_password = password, debug_api = debug_api)
        step.message = f"set password {password}"
        step.is_success = True
    
    except Exception as e:
        step.message = e
        step.is_success = False
    
    return res

# %% ../nbs/00_FactoryUser.ipynb 7
@dataclass
class UpsertUserConfig(FactoryConfig):
    display_name : str = None
    email: str = None
    password :str = None
    domo_user : DomoUser = None
    domo_role : DomoRole = None
    factory_fn_ls : List[Callable] = field(default_factory = lambda:[sync_user])


# %% ../nbs/00_FactoryUser.ipynb 8
async def get_group_manage_grants(auth : DomoAuth, 
                                  session: httpx.AsyncClient = None):
    await DomoGroups.toggle_system_group_visibility(auth= auth, is_hide_system_groups = False,
                                                    # session = session
                                                   )
    
    domo_groups = await DomoGroup.search_by_name( group_name = "Grant: Manage all groups", auth = auth, session = session)
    
    await DomoGroups.toggle_system_group_visibility(auth= auth, is_hide_system_groups = True,
                                                    # session = session
                                                   )
    return domo_groups


@factory_function(config_id_col = 'group_name')
async def sync_group(
    logs: FactoryLogs,
    res : FactoryResponse,
    config : FactoryConfig,
    debug_api: bool = False,
    session : httpx.AsyncClient = None):
    
    res.location = config.auth.domo_instance
    res.response = False
    auth = config.auth
    
    # STAGE 1 Get group manage all groups
    step = FactoryMessage( stage="handle manage_groups", is_success=False)
    res.add_message( step )

    domo_group_manage_all = config.domo_group_manage_all
    step.message = 'using config user'
    step.is_success = True
    
    if not domo_group_manage_all:    
        try:
            domo_group_manage_all = await get_group_manage_grants(auth = auth,
                                                                  session = session)
            step.message = 'retrieved user'
            step.is_success = True
            config.domo_group_manage_all = domo_group_manage_all
            
        except Exception as e:
            step.message = e
            step.is_success = False
    
    if not domo_group_manage_all:
        res.response = 'no manage all groups user'
        return res
    
    # STAGE 2 upsert group
    step = FactoryMessage( stage="upsert group", is_success=False)
    res.add_message( step )

    domo_group = config.domo_group
    try:
        domo_group = await DomoGroup.upsert(auth = auth, 
                                                 group_name = config.group_name,
                                                 description = config.group_description,
                                                 group_type = config.group_type,
                                                 session = session
                                                )
        step.message = f"{config.group_name} upsertted in {auth.domo_instance}"
        step.is_success = True
        
        config.domo_group= domo_group
    
    except Exception as e:
        step.message = e
        step.is_success = False
    
    if not domo_group:
        res.response = 'no domo_group'
        return res
    
    res.response = domo_group
    
    # STAGE 3 add owners 
    step = FactoryMessage( stage="add owners", is_success=False)
    res.add_message( step )
    
    domo_owner_ls = config.domo_owner_ls or []
    domo_owner_ls.append(domo_group_manage_all)
    
    try:
        await domo_group.Membership.add_owners(add_owner_ls = domo_owner_ls)
        step.message = f"{len(domo_owner_ls)} owners added to group"
        step.is_success = True
        
    except Exception as e:
        step.message = e
        step.is_success = False
    
    # STAGE 4 add members
    domo_member_ls = config.domo_member_ls
    
    if not domo_member_ls:
        return res
    
    step = FactoryMessage( stage=f"add members", is_success=False)
    res.add_message( step )
    
    try:
        await domo_group.Membership.add_members( add_user_ls = domo_member_ls)
        step.message = f"{len(domo_member_ls)} members added to group"
        step.is_success = True
        
    except Exception as e:
        step.message = e
        step.is_success = False
    
    return res

# %% ../nbs/00_FactoryUser.ipynb 9
@dataclass
class UpsertGroupConfig(FactoryConfig):
    group_name : str = None
    group_description:str = None
    group_type :str = 'closed'
    domo_owner_ls : List[DomoUser] = None
    domo_member_ls : List[DomoUser] = None
    
    domo_group_manage_all : DomoGroup = None
    domo_group : DomoGroup = None
    
    factory_fn_ls : List[Callable] = field(default_factory = lambda:[sync_group])


# %% ../nbs/00_FactoryUser.ipynb 10
@factory_function(config_id_col = 'email')
async def generate_user_accesstoken(
    logs: FactoryLogs,
    res : FactoryResponse,
    config : FactoryConfig,
    debug_api: bool = False,
    session : httpx.AsyncClient = None):
    
    auth = config.auth
    domo_user = config.domo_user
    email = config.email
    is_regenerate_token = config.is_regenerate_token
    account_name = config.account_name
    duration_in_days = config.duration_in_days
    
    res.location = auth.domo_instance

    # Step 1 validate domo_user or email
    step = FactoryMessage( stage="validate domo_user or email")
    res.add_message( step )
    
    if not domo_user and not email:
        step.is_success = False
        step.message = "must provide email or domo_user"
        res.response = "no user"
        return res
    
    step.is_success = True
    step.message = 'retrieval using domo_user' if domo_user else 'retrieval using email'
    
    # step 2 = "validate is regenerate token"
    step = FactoryMessage( stage="validate is regenerate_token")
    res.add_message( step )
    
    if is_regenerate_token is None:
        is_regenerate_token = True
        config.is_regenerate_token = is_regenerate_token

    if not is_regenerate_token:
        step.message = "do not regenerate_token"
        step.is_success = True
        
        res.response = "do not regenerate token"
        return res
    
    step.message = 'do regenerate token'
    step.is_success = True
    
    # step 3 handle get domo_user
    step = FactoryMessage( stage="handle get domo_user", is_success=False)
    res.add_message( step )

    if domo_user:
        step.message = 'domo user passed into config'
        step.is_success = True
    
    if not domo_user:
        try:
            domo_user = await dmdu.DomoUsers.by_email(
                email_ls = [email],
                auth = auth,
                only_allow_one = True,
                debug_api = debug_api
            )
            step.message = 'domo user retrieved via search by email'
            step.is_success = True
        except Exception as e:
            step.message = e
            step.is_success = False
    
    if not domo_user:
        res.response = 'no user'
        return res
    
    config.domo_user = domo_user
    
    step = FactoryMessage( stage="regenerate_access_token", is_success=False)
    res.add_message( step )
    
    domo_instance = dmic.DomoInstanceConfig(auth = auth)
    access_token = None
    try:
        access_token = await domo_instance.regenerate_access_token( domo_user = domo_user,  # domo_user
            token_name = account_name,
            session= session,
            duration_in_days = duration_in_days,
            debug_api = debug_api)
        
        step.is_success = True
        step.message = access_token.token
        
    
    except Exception as e:
        step.message = e
        step.is_success = False
        
    if not access_token:
        res.response = "no access_token"
        return res
    
    config.domo_access_token = access_token
    config.access_token = access_token.token
    res.response = access_token
    return res

@dataclass
class Config_GenerateUserAccessToken(FactoryConfig):
    domo_user: dmdu.DomoUser = None
    email : str = None
    is_regenerate_token : bool = None
    account_name :str = None
    duration_in_days : int = 90
    domo_access_token : dmac.DomoAccount = None
   

    factory_fn_ls : List[Callable] = field(default_factory = lambda:[generate_user_accesstoken])


