########
# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved
#
# Licensed 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.
############


import os
import copy
import json
import uuid
import click
import logging
import logging.config

import colorama

from cloudify import logs

from . import env
from .config.config import is_use_colors
from .config.config import CloudifyConfig
from .colorful_event import ColorfulEvent

DEFAULT_LOG_FILE = os.path.join(env.CLOUDIFY_WORKDIR, 'logs', 'cli.log')

HIGH_VERBOSE = 3
MEDIUM_VERBOSE = 2
LOW_VERBOSE = 1
NO_VERBOSE = 0
QUIET = -1

verbosity_level = NO_VERBOSE
json_output = False

_lgr = None


LOGGER = {
    "version": 1,
    "formatters": {
        "file": {
            "format": "%(asctime)s [%(levelname)s] %(message)s"
        },
        "console": {
            "format": "%(message)s"
        }
    },
    "handlers": {
        "file": {
            "class": "logging.handlers.RotatingFileHandler",
            "formatter": "file",
            "maxBytes": 5000000,
            "backupCount": 20
        },
        "console": {
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout",
            "formatter": "console"
        }
    },
    "loggers": {
        "cloudify.cli.main": {
            "handlers": ["console", "file"],
            "level": "INFO"
        }
    }
}
# logger that goes only to the file, for use when logging table data
logfile_logger = logging.getLogger('logfile')


def get_logger():
    if not _lgr:
        configure_loggers()
    return _lgr


def configure_loggers():
    # first off, configure defaults
    # to enable the use of the logger
    # even before the init was executed.
    logger_config = copy.deepcopy(LOGGER)
    _configure_defaults(logger_config)

    if env.is_initialized():
        # init was already called
        # use the configuration file.
        _configure_from_file(logger_config)
    _set_loggers_verbosity(logger_config)
    logging.config.dictConfig(logger_config)

    global _lgr
    _lgr = logging.getLogger('cloudify.cli.main')

    # configuring events/logs loggers
    # (this will also affect local workflow loggers, which don't use
    # the get_events_logger method of this module)
    if is_use_colors():
        logs.EVENT_CLASS = ColorfulEvent
        # refactor this elsewhere if colorama is further used in CLI
        colorama.init(autoreset=True)


def _set_loggers_verbosity(logger_config):
    if get_global_json_output():
        logger_config['loggers']['cloudify.cli.main']['level'] = 'ERROR'
    for logger in logger_config['loggers'].values():
        if verbosity_level >= HIGH_VERBOSE:
            logger['level'] = logging.DEBUG
        elif verbosity_level == LOW_VERBOSE:
            logger['level'] = logging.INFO
        elif verbosity_level <= QUIET:
            logger['level'] = logging.ERROR


def _configure_defaults(logger_config):
    if get_global_json_output():
        logger_config['loggers']['logfile'] = {
            "level": "DEBUG",
            "propagate": False,
            "handlers": ["file"]
        }
        logger_config['handlers']['console']['stream'] = 'ext://sys.stderr'

    logger_config['handlers']['file']['filename'] = DEFAULT_LOG_FILE
    logfile_dir = os.path.dirname(DEFAULT_LOG_FILE)
    if not os.path.exists(logfile_dir):
        os.makedirs(logfile_dir)


def _configure_from_file(loggers_config):
    config = CloudifyConfig()

    # set filename on file handler
    logger_dict = copy.deepcopy(LOGGER)
    loggers_config['handlers']['file']['filename'] = config.logging.filename
    logfile_dir = os.path.dirname(config.logging.filename)
    if not os.path.exists(logfile_dir):
        os.makedirs(logfile_dir)

    # add handlers to every logger specified in the file
    for logger_name, logging_level in config.logging.loggers.items():
        loggers_config['loggers'][logger_name] = {
            'handlers': list(logger_dict['handlers'].keys()),
            'level': logging_level.upper()
        }


def get_events_logger(json_output):
    json_output = json_output or get_global_json_output()

    def json_events_logger(events):
        """The json events logger prints events as consumable JSON formatted
        entries. Each event appears in its own line.

        :param events: The events to print.
        :return:
        """
        for event in events:
            click.echo(json.dumps(event))

    def text_events_logger(events):
        """The default events logger prints events as short messages.

        :param events: The events to print.
        :return:
        """
        for event in events:
            output = logs.create_event_message_prefix(event)
            if output:
                click.echo(output)

    return json_events_logger if json_output else text_events_logger


def set_global_verbosity_level(verbose):
    """Set the global verbosity level.
    """
    global verbosity_level
    verbosity_level = verbose
    logs.EVENT_VERBOSITY_LEVEL = verbosity_level


def get_global_verbosity():
    """Return the globally set verbosity
    """
    return verbosity_level


def set_global_json_output(enabled=False):
    global json_output
    json_output = enabled


def get_global_json_output():
    return json_output


def output(line):
    logfile_logger.info(line)
    click.echo(line)


class CloudifyJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, uuid.UUID):
            return obj.hex
        return super(CloudifyJSONEncoder, self).default(obj)