# 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
import httpx
import json

from dataclasses import dataclass, field, asdict
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 dmcd

# %% ../../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)
    enforce_allowlist: bool
    idp_certificate: str

    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

    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,
    ):

        self.set_attribute( **kwargs)

        config_body = self.to_json()

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

        res = await sso_routes.update_sso_config(
            auth=self.auth,
            config_body=config_body,
            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()

        errors_obj = {}
        for n_key, current_value in asdict(new_config).items():
            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.sso_config

# %% ../../nbs/classes/50_DomoInsanceConfig_SSO.ipynb 8
@dataclass
class SSO_OIDC_Config(SSO_Config):
    
    login_enabled: bool
    idp_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

    # assertion_endpoint: str = None
    # ingest_attributes: bool = None

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

        new_obj = {
            dmcd.convert_str_to_snake_case(key, is_pascal=True): value
            for key, value in obj.items()
        }

        new_obj["enforce_allowlist"] = new_obj.pop("enforce_whitelist")
        new_obj["override_sso"] = new_obj.pop("override_s_s_o")

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

        return cls(auth=auth, **new_obj)

    def to_json(self, is_include_undefined: bool = False):
        obj = asdict(self)
        obj.pop("auth")

        return sso_routes.generate_sso_oidc_body(
            **obj, 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)

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

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

    # login_enabled: bool = None  # False
    # skip_to_idp: bool = None  # False
    # token_endpoint: str = None,
    # user_info_endpoint: str = None
    # public_key: str = None
    # override_sso: bool = None  # False
    # override_embed: bool = None  # False
    # # "https://{domo_instance}}.domo.com/auth/oidc"
    # well_known_config: str = None
    # assertion_endpoint: str = None
    # ingest_attributes: bool = None # False

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

        new_obj = {
            dmcd.convert_str_to_snake_case(key, is_pascal=True): value
            for key, value in obj.items()
        }

        new_obj["is_enabled"] = new_obj.pop("enabled")
        new_obj["enforce_allowlist"] = new_obj.pop("enforce_whitelist")

        new_obj["idp_enabled"] = bool(new_obj.pop("idp_enabled"))

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

        return cls(auth=auth, **new_obj)

    @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)

# %% ../../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
