# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------

import os
import uuid
from datetime import datetime, timedelta


from .log import logger
from .parser import Parser
from .display import Display
from .constants import Constants, CryptoParam, SsoStorageParam, SsoEnvVarParam, SsoStorage, SsoCrypto

from .fernet_crypto import FernetCrypto, fernet_installed, check_password_strength
from .dpapi_crypto import DpapiCrypto, dpapi_installed
from .dict_db_storage import DictDbStorage


_SUPPORTED_STORAGE = [
    SsoStorage.IPYTHON_DB
]


_SUPPORTED_CRYPTO = [
    SsoCrypto.DPAPI
]


def get_sso_store(authority = None, **options) -> SsoStorage: #pylint: disable=no-method-argument
    encryption_keys_string = os.getenv(Constants.SSO_ENV_VAR_NAME)
    if not encryption_keys_string:
        # Display.showWarningMessage(f"Warning: SSO is not activated because environment variable {SSO_ENV_VAR_NAME} is not set")
        return

    key_vals = Parser.parse_and_get_kv_string(encryption_keys_string, {})
    cache_name = key_vals.get(SsoEnvVarParam.CACHE_NAME)  
    secret_key = key_vals.get(SsoEnvVarParam.SECRET_KEY)
    secret_salt_uuid = key_vals.get(SsoEnvVarParam.SECRET_SALT_UUID)
    crypto = key_vals.get(SsoEnvVarParam.CRYPTO)
    storage = key_vals.get(SsoEnvVarParam.STORAGE)

    if storage in _SUPPORTED_STORAGE:
        pass
    elif storage is None:
        Display.showWarningMessage(f"Warning: SSO is not activated due to environment variable {Constants.SSO_ENV_VAR_NAME} is missing {SsoEnvVarParam.STORAGE} key/value")
        return
    else:
        Display.showWarningMessage(f"Warning: SSO is not activated due to {storage} storage is not supported")
        return

    if storage == SsoStorage.IPYTHON_DB:
        if not(cache_name):
            Display.showWarningMessage(f"Warning: SSO is not activated due to environment variable {Constants.SSO_ENV_VAR_NAME} is missing {SsoEnvVarParam.CACHE_NAME} key/value")
            return  

    if crypto in _SUPPORTED_CRYPTO:
        pass
    elif crypto is None:
        Display.showWarningMessage(f"Warning: SSO is not activated due to environment variable {Constants.SSO_ENV_VAR_NAME} is missing {SsoEnvVarParam.CRYPTO} key/value")
        return
    else:
        Display.showWarningMessage(f"Warning: SSO is not activated due to {crypto} cryptography is not supported")
        return

    crypto_obj = None
    if crypto == SsoCrypto.DPAPI:
        if  not dpapi_installed:
            Display.showWarningMessage(f"Warning: SSO is not activated due to {SsoCrypto.DPAPI} cryptography failed to install")
            return
        crypto_obj = DpapiCrypto()

    elif crypto == SsoCrypto.FERNET:
        if  not fernet_installed:
            Display.showWarningMessage(f"Warning: SSO is not activated due to {SsoCrypto.FERNET} cryptography and/or password-strength modules are not found")
            return

        if not(secret_key):
            Display.showWarningMessage(f"Warning: SSO is not activated due to environment variable {Constants.SSO_ENV_VAR_NAME} is missing {SsoEnvVarParam.SECRET_KEY} key/value")
            return

        if not(secret_salt_uuid):
            Display.showWarningMessage(f"Warning: SSO is not activated due to environment variable {Constants.SSO_ENV_VAR_NAME} is missing {SsoEnvVarParam.SECRET_SALT_UUID} key/value")
            return

        hint = check_password_strength(secret_key)
        if hint:
            message = f"Warning: SSO could not be activated due to {SsoEnvVarParam.SECRET_KEY} key in environment variable {Constants.SSO_ENV_VAR_NAME} is too simple. It should contain: \n{hint}" 
            Display.showWarningMessage(message)
            return

        try:
            salt = uuid.UUID(secret_salt_uuid, version=4)            
        except:
            Display.showWarningMessage(f"Warning: SSO is not activated due to {SsoEnvVarParam.SECRET_SALT_UUID} key in environment variable {Constants.SSO_ENV_VAR_NAME} is not set to a valid uuid")
            return

        crypto_options = {
            CryptoParam.PASSWORD: f"{cache_name or ''}-{secret_key}",
            CryptoParam.SALT: salt,
            CryptoParam.LENGTH: 32
        }
        crypto_obj = FernetCrypto(crypto_options)
       
    if crypto_obj is not None:
        gc_ttl_in_secs = options.get('sso_db_gc_interval', 0) * Constants.HOUR_SECS #convert from hours to seconds
        storage_options = {
            SsoStorageParam.AUTHORITY: authority,
            SsoStorageParam.CRYPTO_OBJ: crypto_obj,
            SsoStorageParam.CACHE_NAME: cache_name,
            SsoStorageParam.GC_TTL_IN_SECS: gc_ttl_in_secs
        }

        if storage == SsoStorage.IPYTHON_DB:
            db = Display._get_ipython_db(**options)
            return DictDbStorage(db, storage_options)
