import logging
from typing import List, Optional, Union

from colorlog import ColoredFormatter

from loralogger.handlers import LogToESHandler
from loralogger.instances import LoggerInstances
from loralogger.loggers.logger import LoraLoggerClass

# adapted from https://dock2learn.com/tech/create-a-reusable-logger-factory-for-python-projects/


class LoraLogger:
    @staticmethod
    def __create_logger(
        label: Optional[str] = "",
        format: Optional[str] = "",
        date_format: Optional[str] = "",
        level: Optional[str] = "",
        log_to_es: bool = False,
        log_to_console: bool = False,
        log_to_syslog: bool = False,
        skip_queue: bool = False,
        use_colors: bool = False,
    ) -> LoraLoggerClass:
        logger_name: str = label or "loralogger"

        logger_format: str = format or "| %(levelname)-9s | %(asctime)s | %(message)s"
        logger_style: str = "%"
        date_format = date_format or "%Y-%m-%dT%H:%M:%S"

        logger_level: str = level or "DEBUG"

        logger_mapper: dict = {
            "DEBUG": logging.DEBUG,
            "debug": logging.DEBUG,
            "INFO": logging.INFO,
            "info": logging.INFO,
            "WARNING": logging.WARNING,
            "warning": logging.WARNING,
            "ERROR": logging.ERROR,
            "error": logging.ERROR,
            "CRITICAL": logging.CRITICAL,
            "critical": logging.CRITICAL,
        }

        logger_handlers: List = []

        if log_to_es:
            es_handlers = LogToESHandler(logger_name, skip_queue)

            formatter = logging.Formatter(fmt=logger_format, datefmt=date_format)
            es_handlers.setFormatter(formatter)

            logger_handlers.append(es_handlers)

        if log_to_console:
            console_handler = logging.StreamHandler()

            if use_colors:
                logger_format = "{log_color} {levelname:^9}{reset} {asctime}\n{message}\n{log_color} END LOG  {reset}"
                logger_style = "{"

            formatter = ColoredFormatter(
                logger_format,
                datefmt=date_format,
                reset=True,
                log_colors={
                    "DEBUG": "black,bg_cyan",
                    "INFO": "black,bg_green",
                    "WARNING": "black,bg_yellow",
                    "ERROR": "black,bg_red",
                    "CRITICAL": "red,bg_white",
                },
                style=logger_style,
            )
            console_handler.setFormatter(formatter)

            logger_handlers.append(console_handler)

        if log_to_syslog:
            syslog_handler = logging.handlers.SysLogHandler()  # type: ignore
            logger_handlers.append(syslog_handler)

        # we register our logger class here, and add our custom record factory
        logging.setLoggerClass(LoraLoggerClass)

        # We create our own Logger instance here, and set the default level.
        logger = logging.getLogger(logger_name)
        logger.setLevel(logger_mapper[logger_level])

        # Add handlers for it, including the log format
        for handler in logger_handlers:
            logger.addHandler(handler)

        return logger  # type: ignore

    @staticmethod
    def get_logger(
        label: Union[LoggerInstances, str],
        format: Optional[str] = None,
        date_format: Optional[str] = None,
        level: Optional[str] = None,
        log_to_es: bool = True,
        log_to_console: bool = True,
        log_to_syslog: bool = False,
        skip_queue: bool = False,
        use_colors: bool = False,
    ) -> LoraLoggerClass:
        """Static method to generate a logger with specific label and format.

        Args:
            label (LoggerInstances | str): log label, will become the index in elasticsearch if log_to_es is True. Defaults to None.
            format (str, optional): default log format. Defaults to None.
            date_format (str, optional): date format for the log. Defaults to None.
            level (str, optional): default logger level. Defaults to None.
            log_to_es (bool, optional): send the log to Elasticsearch. Defaults to False.
            log_to_console (bool, optional): also log to console. Defaults to False.
            log_to_syslog (bool, optional): also log to syslog. Defaults to False.
            skip_queue (bool, optional): skip the logger from sending to RabbitMQ and send logs directly to ES instance
            use_colors (bool, optional): Whether to use colors on the log messages

        Returns:
            LoraLoggerClass: Lora's custom logger instance
        """

        if isinstance(label, LoggerInstances):
            label_str = label.value
        else:
            label_str = label

        logger = LoraLogger.__create_logger(
            label_str,
            format,
            date_format,
            level,
            log_to_es,
            log_to_console,
            log_to_syslog,
            skip_queue,
            use_colors,
        )

        return logger
