# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Logging related mixins and functions
"""

import logging
from logging import handlers as logging_handlers
# NullHandler doesn't exist in < 27. this workaround is from
# http://docs.python.org/release/2.6/library/logging.html#configuring-logging-for-a-library
try:
    from logging import NullHandler                                                                 # pylint: disable=unused-import
except ImportError:
    class NullHandler(logging.Handler):
        def emit(self, record):
            pass
from datetime import datetime


TASK_LOGGER_NAME = 'aria.executions.task'


_base_logger = logging.getLogger('aria')


class LoggerMixin(object):
    """
    Mixin Logger Class
    configuration (class members):
        logger_name: logger name [default: <class_name>]
        logger_level: logger level [default: logging.DEBUG]
        base_logger: This Mixing will create child logger from this base_logger
                    [default: root logger]
    """
    logger_name = None
    logger_level = logging.DEBUG

    def __init__(self, *args, **kwargs):
        self.logger_name = self.logger_name or self.__class__.__name__
        self.logger = logging.getLogger('{0}.{1}'.format(_base_logger.name, self.logger_name))
        # Set the logger handler of any object derived from LoggerMixing to NullHandler.
        # This is since the absence of a handler shows up while using the CLI in the form of:
        # `No handlers could be found for logger "..."`.
        self.logger.addHandler(NullHandler())
        self.logger.setLevel(self.logger_level)
        super(LoggerMixin, self).__init__(*args, **kwargs)

    @classmethod
    def with_logger(
            cls,
            logger_name=None,
            logger_level=logging.DEBUG,
            base_logger=logging.getLogger(),
            **kwargs):
        """
        Set the logger used by the consuming class
        """
        cls.logger_name = logger_name
        cls.logger_level = logger_level
        cls.base_logger = base_logger
        return cls(**kwargs)

    def __getstate__(self):
        obj_dict = vars(self).copy()
        del obj_dict['logger']
        return obj_dict

    def __setstate__(self, obj_dict):
        vars(self).update(
            logger=logging.getLogger('{0}.{1}'.format(_base_logger.name, obj_dict['logger_name'])),
            **obj_dict)


def create_logger(logger=_base_logger, handlers=(), **configs):
    """

    :param logging.Logger logger: The logger name [default: aria logger]
    :param list handlers: The logger handlers
    :param configs: The logger configurations
    :return: logger
    """
    logger.handlers = []
    for handler in handlers:
        logger.addHandler(handler)

    logger.setLevel(configs.get('level', logging.DEBUG))
    logger.debug('Logger {0} configured'.format(logger.name))
    return logger


def create_console_log_handler(level=logging.DEBUG, formatter=None):
    """

    :param level:
    :param formatter:
    :return:
    """
    console = logging.StreamHandler()
    console.setLevel(level)
    console.formatter = formatter or _DefaultConsoleFormat()
    return console


def create_sqla_log_handler(model, log_cls, execution_id, level=logging.DEBUG):

    # This is needed since the engine and session are entirely new we need to reflect the db
    # schema of the logging model into the engine and session.
    return _SQLAlchemyHandler(model=model, log_cls=log_cls, execution_id=execution_id, level=level)


class _DefaultConsoleFormat(logging.Formatter):
    """
    _DefaultConsoleFormat class
    Console logger formatter
     info level logs format: '%(message)s'
     every other log level are formatted: '%(levelname)s: %(message)s'
    """
    def format(self, record):
        try:
            if hasattr(record, 'prefix'):
                self._fmt = '<%(asctime)s: [%(levelname)s] @%(prefix)s> %(message)s'
            else:
                self._fmt = '<%(asctime)s: [%(levelname)s]> %(message)s'

        except AttributeError:
            return record.message
        return logging.Formatter.format(self, record)


def create_file_log_handler(
        file_path,
        level=logging.DEBUG,
        max_bytes=5 * 1000 * 1024,
        backup_count=10,
        formatter=None):
    """
    Create a logging.handlers.RotatingFileHandler
    """
    rotating_file = logging_handlers.RotatingFileHandler(
        filename=file_path,
        maxBytes=max_bytes,
        backupCount=backup_count,
        delay=True,
    )
    rotating_file.setLevel(level)
    rotating_file.formatter = formatter or _default_file_formatter
    return rotating_file


class _SQLAlchemyHandler(logging.Handler):

    def __init__(self, model, log_cls, execution_id, **kwargs):
        logging.Handler.__init__(self, **kwargs)
        self._model = model
        self._cls = log_cls
        self._execution_id = execution_id

    def emit(self, record):
        created_at = datetime.strptime(logging.Formatter('%(asctime)s').formatTime(record),
                                       '%Y-%m-%d %H:%M:%S,%f')
        log = self._cls(
            execution_fk=self._execution_id,
            task_fk=record.task_id,
            level=record.levelname,
            msg=str(record.msg),
            created_at=created_at,

            # Not mandatory.
            traceback=getattr(record, 'traceback', None)
        )
        self._model.log.put(log)


_default_file_formatter = logging.Formatter(
    '%(asctime)s [%(name)s:%(levelname)s] %(message)s <%(pathname)s:%(lineno)d>')
