import os
import logging
import yt.wrapper as default_yt

from .constants import YtCluster


__all__ = [
    'create_yt_client',
    'create_all_yt_clients',
]

logger = logging.getLogger(__name__)

WHITE_SO_LIST = (
    'yson_lib.so',
)
WHITE_PACKAGES_SO_LIST = (
    'google/protobuf',
    'numpy',
    'sklearn',
    'scipy',
    'markupsafe',  # flask json encoder dependency
)
BLACK_MODULE_LIST = (
    'hashlib',
    'hmac',
    'weakref',
    'ntpath'
)


def _package_names(white_list):
    """ Generates path part for different python versions """
    for path in white_list:
        yield 'dist-packages/{}'.format(path)
        yield 'site-packages/{}'.format(path)


def module_filter(module):
    module_name = getattr(module, '__name__', '')
    if module_name and any(m in module_name for m in BLACK_MODULE_LIST):
        logger.debug('module %s in black list, skip', module_name)
        return False
    filename = getattr(module, '__file__', '')
    is_so = filename and filename.endswith('.so')
    if is_so:
        return library_filter(filename)
    logger.debug('allow module %s %s (%s)', module_name, module, filename)
    return True


def library_filter(lib_path):
    while_list_so = False
    while_list_so = while_list_so or any(lib_path.endswith(so) for so in WHITE_SO_LIST)
    while_list_so = while_list_so or any(path in lib_path for path in _package_names(WHITE_PACKAGES_SO_LIST))
    if not while_list_so:
        logger.debug('library %s is not in white list, skip', lib_path)
        return False
    logger.debug('allow library %s', lib_path)
    return True


def create_yt_client(yt_cluster, config=None, token=None):
    """ Creates and configures new yt client"""
    if isinstance(yt_cluster, YtCluster):
        yt_cluster = yt_cluster.value
    yt_client = default_yt.YtClient(proxy=yt_cluster, config=config)

    yt_client.config['token'] = token or default_yt.config['token'] or os.environ.get('YT_TOKEN')
    yt_client.config['pickling']['dynamic_libraries']['enable_auto_collection'] = True
    yt_client.config['pickling']['dynamic_libraries']['library_filter'] = library_filter
    yt_client.config['pickling']['force_using_py_instead_of_pyc'] = True
    yt_client.config['pickling']['module_filter'] = module_filter

    return yt_client


def create_all_yt_clients(config=None):
    """ Creates and configures new yt clients for all clusters"""
    return {
        cluster: create_yt_client(cluster, config=config)
        for cluster in YtCluster
    }
