#!/usr/bin/python3
"""
Log manager for easy and fast log compliancy

This library is for educational purposes only.
Do no evil, do not break local or internation laws!
By using this code, you take full responisbillity for your actions.
The author have granted code access for educational purposes and is
not liable for any missuse.
"""
__author__ = "Jonas Werme"
__copyright__ = "Copyright (c) 2021 Jonas Werme"
__credits__ = ["Marcus Wallgren", "nsahq"]
__license__ = "MIT"
__version__ = "1.0.0"
__maintainer__ = "Jonas Werme"
__email__ = "jonas[dot]werme[at]nsahq[dot]se"
__status__ = "Prototype"

import logging
from typing import Type, Union

from pywrapid.config import WrapidConfig
from pywrapid.config.exceptions import ConfigurationError
from pywrapid.utils import dict_merge


def _generate_default(cfg: dict) -> dict:
    """Generate default config dict for logging

    Args:
        cfg (dict): Logging configuration

    Raises:
        ConfigurationError

    Returns:
        dict: Default logging configuration
    """
    if not isinstance(cfg, dict):
        raise ConfigurationError("Invalid application logging configuration type")

    default = {
        "console": {
            "format": "[%(levelname)s] (%(name)s) %(message)s",
            "level": logging.INFO,
        },
        "file": {
            "format": "%(asctime)-15s [%(levelname)s] (%(name)s) %(message)s",
            "level": logging.INFO,
            "location": "",
        },
    }

    if not cfg:
        return default

    if "default" in cfg and cfg["default"]:
        if not isinstance(cfg["default"], dict):
            raise ConfigurationError("Invalid object in configuration section: default")
        default = dict_merge(default, cfg["default"])

    return default


# flake8: noqa: C901
def application_logging(config: Union[Type[WrapidConfig], dict]) -> None:
    """Sets up loggers for application

    Configuration used for setting up all specified loggers
    as well as the root logger.

    Args:
        config (WrapidConfig|dict): Wrapid config object or dict of modules and options

    """
    if isinstance(config, WrapidConfig):
        cfg = config.cfg
    elif isinstance(config, dict):
        cfg = config
    else:
        raise ConfigurationError("Invalid application logging configuration type")

    logging.root.setLevel(logging.NOTSET)

    default = _generate_default(cfg=cfg)

    cfg["root"] = default
    for module in cfg:
        if module == "default":
            continue

        log = logging.getLogger(module) if module != "root" else logging.getLogger()

        log.propagate = False
        # if log.hasHandlers():
        #     continue
        cfg[module] = dict_merge(default, cfg[module]) if cfg[module] is not None else default
        for log_type in ["console", "file"]:
            formatter = logging.Formatter(cfg[module].get("format", default[log_type]["format"]))
            level = cfg[module][log_type].get("level", default[log_type]["level"])

            if level == 0:
                continue

            if log_type == "console":
                handler: logging.Handler = logging.StreamHandler()
            elif log_type == "file":
                if not cfg[module][log_type]["location"]:
                    continue
                handler = logging.FileHandler(
                    cfg[module].get("location", default[log_type]["location"])
                )
            handler.setLevel(level)
            handler.setFormatter(formatter)
            log.addHandler(handler)
            if log.getEffectiveLevel() > level:
                log.setLevel(level)
            if log.getEffectiveLevel() == 0:
                log.setLevel(10)
            # if log.root.getEffectiveLevel() > level:
            #     log.root.setLevel(level)
