import sys
import logging.config
import logging
from enum import Enum
from ylog.format import QloudJsonFormatter


__all__ = [
    'LogLevel',
    'ConsoleStream',
    'ConsoleFormatter',
    'configure_logging',
    'get_qloud_formatter'
]


logger = logging.getLogger(__name__)


LOG_FORMAT = '[%(asctime)s] %(levelname)s %(name)s:%(lineno)d %(message)s'


class LogLevel(Enum):
    NOTSET = 'NOTSET'
    DEBUG = 'DEBUG'
    INFO = 'INFO'
    WARNING = 'WARNING'
    ERROR = 'ERROR'
    CRITICAL = 'CRITICAL'


class ConsoleStream(Enum):
    STDOUT = 'stdout'
    STDERR = 'stderr'


class ConsoleFormatter(Enum):
    QLOUD_JSON = 'qloud_json'
    PLAIN = 'plain'


def _to_value(obj):
    if isinstance(obj, Enum):
        return obj.value
    return obj


def get_qloud_formatter(qloud_format):
    """ Converts Qloud format name to constants """
    if qloud_format == 'line':
        return ConsoleFormatter.PLAIN
    elif qloud_format == 'json':
        return ConsoleFormatter.QLOUD_JSON
    else:
        raise KeyError('unknown format name %r' % qloud_format)


def _to_stream(obj):
    if ConsoleStream(obj) is ConsoleStream.STDOUT:
        return sys.stdout
    elif ConsoleStream(obj) is ConsoleStream.STDERR:
        return sys.stderr
    raise KeyError('unknown stream %s' % obj)


def _build_global_config(global_log_level, debug_modules, console_stream, console_formatter):
    global_log_level = _to_value(global_log_level)
    console_formatter = _to_value(console_formatter)
    console_stream = _to_stream(console_stream)

    return {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'plain': {
                'format': LOG_FORMAT,
            },
            'qloud_json': {
                '()': 'ylog.format.QloudJsonFormatter',
            },
        },
        'handlers': {
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
                'stream': console_stream,
                'formatter': console_formatter,
            }
        },
        'root': {
            'handlers': ['console'],
            'propagate': True,
            'level': global_log_level,
        },
        'loggers': {name: {'handlers': ['console'], 'propagate': False, 'level': 'DEBUG'} for name in debug_modules},
    }


def _configure_yt_logger(level, stream, formatter):
    stream = _to_stream(stream)
    if ConsoleFormatter(formatter) is ConsoleFormatter.PLAIN:
        formatter = logging.Formatter(fmt=LOG_FORMAT)
    elif ConsoleFormatter(formatter) is ConsoleFormatter.QLOUD_JSON:
        formatter = QloudJsonFormatter()

    yt_logger = logging.getLogger("Yt")
    yt_logger.setLevel(level=_to_value(level))

    for handler in list(yt_logger.handlers):
        yt_logger.removeHandler(handler)

    handler = logging.StreamHandler(stream=stream)
    handler.setFormatter(formatter)
    yt_logger.addHandler(handler)


def configure_logging(log_level=LogLevel.INFO, debug_modules=(),
                      console_stream=ConsoleStream.STDERR, console_formatter=ConsoleFormatter.PLAIN,
                      reconfigure_yt=False, configure_yql_stderr=True):
    logging.config.dictConfig(_build_global_config(
        global_log_level=log_level,
        debug_modules=debug_modules,
        console_stream=console_stream,
        console_formatter=console_formatter,
    ))
    if reconfigure_yt:
        _configure_yt_logger(
            level=log_level,
            stream=console_stream,
            formatter=console_formatter,
        )
    if configure_yql_stderr:
        try:
            from yql.config import config
            config.progress_on_stderr = False
        except ImportError:
            # yql lib not installed
            pass
