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

# %% auto 0
__all__ = ['SSOConfig_InstantiationError', 'SSOConfig_UpdateError', 'SSO_Config', 'SSO_OIDC_Config', 'SSO_SAML_Config', 'SSO']

# %% ../../nbs/classes/50_DomoInsanceConfig_SSO.ipynb 2
from domolibrary.routes.instance_config_sso import (
    SSO_CRUD_Error, SSO_GET_Error
)

# %% ../../nbs/classes/50_DomoInsanceConfig_SSO.ipynb 3
from typing import Callable
from dataclasses import dataclass, field, asdict

import json
from copy import deepcopy
import httpx

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

import domolibrary.routes.instance_config_sso as sso_routes

import domolibrary.utils.convert as dmcv

# %% ../../nbs/classes/50_DomoInsanceConfig_SSO.ipynb 7
class SSOConfig_InstantiationError(dmde.ClassError):
    def __init__(self, message, auth, cls_instance=None):

        super().__init__(auth=auth, message=message, cls_instance=cls_instance)


class SSOConfig_UpdateError(dmde.ClassError):
    def __init__(self, errors_obj, res: rgd.ResponseGetData, cls_instance):
        message = json.dumps(errors_obj)
        super().__init__(res=res, message=message, cls_instance=cls_instance)


@dataclass
class SSO_Config:
    """base class for SAML and OIDC Config"""

    auth: dmda.DomoAuth = field(repr=False)

    idp_enabled: bool  # False
    enforce_allowlist: bool
    idp_certificate: str

    raw: dict = field(repr=  False) # base API response

    def set_attribute(self, **kwargs):

        for key, value in kwargs.items():
            if not hasattr(self, key):
                raise SSOConfig_InstantiationError(
                    message=f"key {key} not part of class", auth=self.auth
                )
            if value is not None:
                setattr(self, key, value)

        return self

    @classmethod
    def _parent_from_json(cls, obj : dict ,raw : dict, auth : dmda.DomoAuth,  **kwargs):
        new_obj = {
            dmcv.convert_str_to_snake_case(key, is_pascal=True): value
            for key, value in obj.items()
        }

        idp_enabled = new_obj.pop('idp_enabled')
        if isinstance(idp_enabled, str):
            idp_enabled = dmcv.convert_string_to_bool(idp_enabled)


        enforce_allowlist = new_obj.pop("enforce_whitelist")

        idp_certificate = (
            new_obj.pop("certificate") if hasattr(new_obj, "certificate") else None
        )

        sso_cls= cls(
            auth = auth, 
            enforce_allowlist = enforce_allowlist,
            idp_certificate = idp_certificate,
            idp_enabled=idp_enabled,
            raw = raw,

            **kwargs,
            **new_obj,
        )

        sso_cls.set_attribute(**new_obj)

        return sso_cls

        

    def _to_json(self, generate_alternate_body_fn : Callable  = None, is_include_undefined: bool = False):
        obj = asdict(self)
        obj.pop("auth")

        if generate_alternate_body_fn:
            return generate_alternate_body_fn(**obj, is_include_undefined=is_include_undefined)

        return { key: dmcv.convert_snake_to_pascal(value) for key, value in obj.items()}
    
    def to_json(self, is_include_undefined: bool = False):
    
        return self._to_json(is_include_undefined=is_include_undefined)

    
    async def _update(
        self,
        update_config_route_fn: Callable,
        session: httpx.AsyncClient  = None,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
        debug_is_test: bool = False,
        return_raw: bool = False,
        **kwargs,
    ):

        self.set_attribute( **kwargs)

        body_sso = self.to_json()

        if debug_is_test:
            print("⚗️⚠️ This is a test, SSO Config will not be updated")
            return body_sso

        res = await update_config_route_fn(
            auth=self.auth,
            body_sso=body_sso,
            parent_class=self.__class__.__name__,
            session=session,
            debug_api=debug_api,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        )

        if return_raw:
            return res

        new_config = await self.get(auth = self.auth)

        errors_obj = {}
        for n_key, current_value in asdict(new_config).items():
            if n_key in ['auth']:
                continue

            expected_value = getattr(self, n_key)

            if expected_value != current_value:
                errors_obj.update(
                    {
                        "key": n_key,
                        "expected_value": expected_value,
                        "current_value": current_value,
                    }
                )

            self.set_attribute( **{ n_key : current_value} )

        if errors_obj:
            raise SSOConfig_UpdateError(
                res=res, errors_obj=errors_obj, cls_instance=self
            )

        return self

# %% ../../nbs/classes/50_DomoInsanceConfig_SSO.ipynb 8
@dataclass
class SSO_OIDC_Config(SSO_Config):

    login_enabled: bool
    import_groups: bool
    require_invitation: bool
    skip_to_idp: bool
    redirect_url: str  # url
    override_sso: bool
    override_embed: bool
    well_known_config: str



    auth_request_endpoint: str = None  # url
    token_endpoint: str = None
    user_info_endpoint: str = None
    public_key: str = None


    @classmethod
    def _from_json(cls, auth: dmda.DomoAuth, obj: dict):

        raw = deepcopy(obj)

        override_sso = obj.pop("overrideSSO")

        return cls._parent_from_json(auth=auth, obj = obj, override_sso=override_sso, raw = raw)

    def to_json(self, is_include_undefined: bool = False):
        return self._to_json(
            generate_alternate_body_fn=sso_routes.generate_sso_oidc_body,
            is_include_undefined=is_include_undefined,
        )

    @classmethod
    async def get(
        cls,
        auth: dmda.DomoAuth,
        session: httpx.AsyncClient = None,
        debug_api: bool = False,
        return_raw: bool = False,
    ):
        res = await sso_routes.get_sso_oidc_config(
            auth=auth,
            session=session,
            parent_class=cls.__name__,
            debug_api=debug_api,
            debug_num_stacks_to_drop=2,
        )

        if return_raw:
            return res

        return cls._from_json(auth=auth, obj=res.response)

    async def update(
        self,
        session: httpx.AsyncClient  = None,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
        debug_is_test: bool = False,
        return_raw: bool = False,
        **kwargs,
    ):
        return await self._update(
            update_config_route_fn = sso_routes.update_sso_oidc_config,
            session = session,
            debug_api = debug_api,
            debug_num_stacks_to_drop= debug_num_stacks_to_drop+1,
            debug_is_test = debug_is_test,
            return_raw = return_raw,
            **kwargs,
        )

# %% ../../nbs/classes/50_DomoInsanceConfig_SSO.ipynb 11
@dataclass
class SSO_SAML_Config(SSO_Config):
    is_enabled: bool
    import_groups: bool  # False
    require_invitation : bool
    redirect_url: str

    auth_request_endpoint: str = None
    issuer: str = None
    relay_state : str = None
    redirect_url : str = None

    @classmethod
    def _from_json(cls, auth: dmda.DomoAuth, obj: dict):
        raw = deepcopy(obj)

        is_enabled = obj.pop('enabled')

        return cls._parent_from_json(auth=auth, obj = obj,is_enabled=is_enabled ,raw = raw)

    def to_json(self, is_include_undefined: bool = False):
        return self._to_json(
            generate_alternate_body_fn=sso_routes.generate_sso_saml_body,
            is_include_undefined=is_include_undefined,
        )

    @classmethod
    async def get(
        cls,
        auth: dmda.DomoAuth,
        session: httpx.AsyncClient = None,
        debug_api: bool = False,
        return_raw: bool = False,
    ):
        res = await sso_routes.get_sso_saml_config(
            auth=auth,
            session=session,
            parent_class=cls.__name__,
            debug_api=debug_api,
            debug_num_stacks_to_drop=1,
        )

        if return_raw:
            return res

        return SSO_SAML_Config._from_json(auth=auth, obj=res.response)
    

    async def update(
        self,
        session: httpx.AsyncClient  = None,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
        debug_is_test: bool = False,
        return_raw: bool = False,
        **kwargs,
    ):
        return await self._update(
            update_config_route_fn = sso_routes.update_sso_saml_config,
            session = session,
            debug_api = debug_api,
            debug_num_stacks_to_drop= debug_num_stacks_to_drop+1,
            debug_is_test = debug_is_test,
            return_raw = return_raw,
            **kwargs,
        )

# %% ../../nbs/classes/50_DomoInsanceConfig_SSO.ipynb 14
@dataclass
class SSO:
    """
    class for managing SSO Config.  
    Includes both OIDC aand SAML
    """

    auth  : dmda.DomoAuth = field(repr = False)
    
    OIDC : SSO_OIDC_Config = field(default = None) # OIDDC config class
    SAML : SSO_SAML_Config = field(default = None) # SAML config class


    async def get_oidc(self):
        self.OIDC = await SSO_OIDC_Config.get(auth = self.auth)
    
    async def get_saml(self):
        self.SAML = await SSO_SAML_Config.get(auth = self.auth)

    
    async def get(self):
        await self.get_oidc()
        await self.get_saml()

        return self
