# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

from datetime import datetime
from io import TextIOBase
import logging
import os
import sys
import time

log_level_map = {
    'fatal': logging.FATAL,
    'error': logging.ERROR,
    'warning': logging.WARNING,
    'info': logging.INFO,
    'debug': logging.DEBUG
}

_time_format = '%m/%d/%Y, %I:%M:%S %p'

# FIXME
# This hotfix the bug that querying installed tuners with `package_utils` will activate dispatcher logger.
# This behavior depends on underlying implementation of `nnictl` and is likely to break in future.
_logger_initialized = False

class _LoggerFileWrapper(TextIOBase):
    def __init__(self, logger_file):
        self.file = logger_file

    def write(self, s):
        if s != '\n':
            cur_time = datetime.now().strftime(_time_format)
            self.file.write('[{}] PRINT '.format(cur_time) + s + '\n')
            self.file.flush()
        return len(s)

def init_logger(logger_file_path, log_level_name='info'):
    """Initialize root logger.
    This will redirect anything from logging.getLogger() as well as stdout to specified file.
    logger_file_path: path of logger file (path-like object).
    """
    global _logger_initialized
    if _logger_initialized:
        return
    _logger_initialized = True

    if os.environ.get('NNI_PLATFORM') == 'unittest':
        return  # fixme: launching logic needs refactor

    log_level = log_level_map.get(log_level_name, logging.INFO)
    logger_file = open(logger_file_path, 'w')
    fmt = '[%(asctime)s] %(levelname)s (%(name)s/%(threadName)s) %(message)s'
    logging.Formatter.converter = time.localtime
    formatter = logging.Formatter(fmt, _time_format)
    handler = logging.StreamHandler(logger_file)
    handler.setFormatter(formatter)

    root_logger = logging.getLogger()
    root_logger.addHandler(handler)
    root_logger.setLevel(log_level)

    # these modules are too verbose
    logging.getLogger('matplotlib').setLevel(log_level)

    sys.stdout = _LoggerFileWrapper(logger_file)

def init_standalone_logger():
    """
    Initialize root logger for standalone mode.
    This will set NNI's log level to INFO and print its log to stdout.
    """
    global _logger_initialized
    if _logger_initialized:
        return
    _logger_initialized = True

    fmt = '[%(asctime)s] %(levelname)s (%(name)s) %(message)s'
    formatter = logging.Formatter(fmt, _time_format)
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(formatter)
    nni_logger = logging.getLogger('nni')
    nni_logger.addHandler(handler)
    nni_logger.setLevel(logging.INFO)
    nni_logger.propagate = False

    # Following line does not affect NNI loggers, but without this user's logger won't be able to
    # print log even it's level is set to INFO, so we do it for user's convenience.
    # If this causes any issue in future, remove it and use `logging.info` instead of
    # `logging.getLogger('xxx')` in all examples.
    logging.basicConfig()


_multi_thread = False
_multi_phase = False

def enable_multi_thread():
    global _multi_thread
    _multi_thread = True

def multi_thread_enabled():
    return _multi_thread

def enable_multi_phase():
    global _multi_phase
    _multi_phase = True

def multi_phase_enabled():
    return _multi_phase
