# -*- coding: utf-8 -*-
'''Define a cli with dual logging to stderr and file
'''

# standard library imports
import functools
import logging
import sys
from datetime import datetime
from pathlib import Path
# third-party imports
import click
try:
    from importlib.metadata import distribution # python 3.8 and above
except ModuleNotFoundError:
    from importlib_metadata import distribution

# module defs
from .common import DEFAULT_FIRST_N

# global constants
DEFAULT_FILE_LOGLEVEL = logging.DEBUG
DEFAULT_STDERR_LOGLEVEL = logging.INFO
STARTTIME = datetime.now()

class CleanInfoFormatter(logging.Formatter):
    '''very clean logging formatter for terminal output
    '''
    def __init__(self, fmt='%(levelname)s: %(message)s'):
        logging.Formatter.__init__(self, fmt)

    def format(self, record):
        if record.levelno == logging.INFO:
            return record.getMessage()
        return logging.Formatter.format(self, record)


class Click_Multi(object):

    def __init__(self, option_list):
        self.option_list = option_list

def composed(self, *decs):
        def deco(f):
            for dec in reversed(decs):
                f = dec(f)
            return f
        return deco


def click_multi(func):
        return composed(
            click.option('--progress', is_flag=True, show_default=True,
                         default=False, help='Show a progress bar.')
            #click.option(*self.global_options_list[0]['args'],
            #             **self.global_options_list[0]['kwargs'])
        )(func)


class Logging_CLI_Builder(object):
    '''creates a cli function
    '''
    def __init__(self,
                 name,
                 logger,
                 check_func=None,
                 global_options_list=None):
        self.name = name
        self.logger = logger
        self.check_func = check_func
        self.global_options_list = global_options_list
        click_multi = Click_Multi(global_options_list)
        #self.multi_options = click_multi.click_multi
        dist = distribution(name).metadata
        self.version = dist['Version']
        self.author = dist['Author']
        self.email = dist['Author-email']
        self.maintainer = dist['Maintainer']
        self.maintainer_email = dist['Maintainer-email']
        self.home = dist['Home-page']
        self.summary = dist['Summary']
        self.licence = dist['License']
        self.copyright = 'Copyright (C) 2020. National Center for Genome Resources. All rights reserved.'
        self.cli_func = None

    def set_cli_func(self,cli_func):
        self.cli_func = cli_func

    def _ctx(self):
        '''private global context function'''
        return click.get_current_context

    def get_user_context_dict(self):
        '''Returns the user context dictionary.
        '''
        return self._ctx()().obj

    def init_user_context_obj(self, extra_args=None):
        '''Decorator that puts global options into context dictionary
        '''

        def decorator(f):
            @functools.wraps(f)
            def wrapper(*args, **kwargs):
                self._ctx()().obj = {}
                ctx_dict = self._ctx()().obj
                if self._ctx()().params['verbose']:
                    ctx_dict['logLevel'] = 'verbose'
                elif self._ctx()().params['quiet']:
                    ctx_dict['logLevel'] = 'quiet'
                else:
                    ctx_dict['logLevel'] = 'default'
                for key in extra_args:
                    ctx_dict[key] = self._ctx()().params[key]
                return f(*args, **kwargs)

            return wrapper

        return decorator

    def init_dual_logger(self,
                         file_log_level=DEFAULT_FILE_LOGLEVEL,
                         stderr_log_level=DEFAULT_STDERR_LOGLEVEL):
            '''Decorator to log to stderr and to logfile at different levels
            '''

            def decorator(f):
                @functools.wraps(f)
                def wrapper(*args, **kwargs):
                    # find the verbose/quiet levels from context
                    if self._ctx()().params['verbose']:
                        _log_level = logging.DEBUG
                    elif self._ctx()().params['quiet']:
                        _log_level = logging.ERROR
                    else:
                        _log_level = stderr_log_level
                    self.logger.setLevel(file_log_level)
                    stderrHandler = logging.StreamHandler(sys.stderr)
                    stderrFormatter = CleanInfoFormatter()
                    stderrHandler.setFormatter(stderrFormatter)
                    stderrHandler.setLevel(_log_level)
                    self.logger.addHandler(stderrHandler)
                    if self._ctx()().params['log']:  # start a log file
                        # If a subcommand was used, log to a file in the
                        # logs/ subdirectory of the current working directory
                        #  with the subcommand in the file name.
                        subcommand = self._ctx()().invoked_subcommand
                        if subcommand is not None:
                            logfile_name = self.name + '-' + subcommand + '.log'
                            logfile_path = Path('./logs/' + logfile_name)
                            if not logfile_path.parent.is_dir():  # create logs/ dir
                                try:
                                    logfile_path.parent.mkdir(mode=0o755, parents=True)
                                except OSError:
                                    self.logger.error(
                                        'Unable to create logfile directory "%s"',
                                        logfile_path.parent)
                                    raise OSError
                            else:
                                if logfile_path.exists():
                                    try:
                                        logfile_path.unlink()
                                    except OSError:
                                        self.logger.error(
                                            'Unable to remove existing logfile "%s"',
                                            logfile_path)
                                        raise OSError
                            logfileHandler = logging.FileHandler(str(logfile_path))
                            logfileFormatter = logging.Formatter(
                                '%(levelname)s: %(message)s')
                            logfileHandler.setFormatter(logfileFormatter)
                            logfileHandler.setLevel(file_log_level)
                            self.logger.addHandler(logfileHandler)
                    self.logger.debug('Command line: "%s"', ' '.join(sys.argv))
                    self.logger.debug('%s version %s', self.name, self.version)
                    self.logger.debug('Run started at %s', str(STARTTIME)[:-7])
                    return f(*args, **kwargs)

                return wrapper

            return decorator


    def log_elapsed_time(self):
        '''Decorator to log the elapsed time for command
        '''
        def decorator(f):
            @functools.wraps(f)
            def wrapper(*args, **kwargs):
                returnobj = f(*args, **kwargs)
                self.logger.debug(
                    'Elapsed time is %s', str(datetime.now() - STARTTIME)[:-7])
                return returnobj

            return wrapper

        return decorator

    def test_log_func(self):
        @self.cli_func.command()
        @self.log_elapsed_time()
        def test_logging():
            '''Log at different severity levels.
            '''
            self.logger.debug('debug message')
            self.logger.info('info message')
            self.logger.warning('warning message')
            self.logger.error('error message')

    def show_context_func(self):
        @self.cli_func.command()
        def show_context_dict():
            '''Print the global context dictionary.
            '''
            user_ctx = self.get_user_context_dict()
            self.logger.info('User context dictionary:')
            for key in user_ctx.keys():
                self.logger.info('   %s: %s', key, user_ctx[key])