#
# SPDX-FileCopyrightText: 2021 Splunk, Inc. <sales@splunk.com>
# SPDX-License-Identifier: LicenseRef-Splunk-8-2021
#
#
import logging
import logging.handlers as handlers
import os
import os.path as op
import time

try:
    from splunk.clilib.bundle_paths import make_splunkhome_path
except ImportError:
    from splunk.appserver.mrsparkle.lib.util import make_splunkhome_path

logging.Formatter.converter = time.gmtime

__LOG_FORMAT__ = (
    "%(asctime)s +0000 log_level=%(levelname)s, pid=%(process)d, "
    "tid=%(threadName)s, file=%(filename)s, "
    "func_name=%(funcName)s, code_line_no=%(lineno)d | %(message)s"
)


class Log(object):
    def __init__(self, namespace=None, default_level=logging.INFO):
        self._loggers = {}
        self._default_level = default_level
        if namespace is None:
            namespace = self._get_appname_from_path(op.abspath(__file__))

        if namespace:
            namespace = namespace.lower()
        self._namespace = namespace

    def get_logger(self, name, level=None, maxBytes=25000000, backupCount=5):
        """
        Set up a default logger.

        :param name: The log file name.
        :param level: The logging level.
        :param maxBytes: The maximum log file size before rollover.
        :param backupCount: The number of log files to retain.
        """

        # Strip ".py" from the log file name if auto-generated by a script.
        if level is None:
            level = self._default_level

        name = self._get_log_name(name)
        if name in self._loggers:
            return self._loggers[name]

        logger = logging.getLogger(name)

        logfile = make_splunkhome_path(["var", "log", "splunk", name])
        handler_exists = any(
            [True for h in logger.handlers if h.baseFilename == logfile]
        )
        if not handler_exists:
            file_handler = handlers.RotatingFileHandler(
                logfile, mode="a", maxBytes=maxBytes, backupCount=backupCount
            )
            formatter = logging.Formatter(__LOG_FORMAT__)
            file_handler.setFormatter(formatter)
            logger.addHandler(file_handler)
            logger.setLevel(level)
            logger.propagate = False

        self._loggers[name] = logger
        return logger

    def set_level(self, level, name=None):
        """
        Change the log level of the logging

        :param level: the level of the logging to be setLevel
        :param name: the name of the logging to set, in case it is not set,
                     all the loggers will be affected
        """

        if name is not None:
            name = self._get_log_name(name)
            logger = self._loggers.get(name)
            if logger is not None:
                logger.setLevel(level)
        else:
            self._default_level = level
            for logger in self._loggers.values():
                logger.setLevel(level)

    def _get_log_name(self, name):
        if name.endswith(".py"):
            name = name.replace(".py", "")

        if self._namespace:
            name = "{}_{}.log".format(self._namespace, name)
        else:
            name = "{}.log".format(name)
        return name

    def _get_appname_from_path(self, absolute_path):
        absolute_path = op.normpath(absolute_path)
        parts = absolute_path.split(os.path.sep)
        parts.reverse()
        for key in ("apps", "slave-apps", "master-apps"):
            try:  # nosemgrep: gitlab.bandit.B112
                idx = parts.index(key)
            except ValueError:
                continue
            else:
                try:  # nosemgrep: gitlab.bandit.B110
                    if parts[idx + 1] == "etc":
                        return parts[idx - 1]
                except IndexError:
                    pass
                continue
        # return None
        return "-"
