"""
Structured logger module.

This module defines the StructuredLogger class, which extends Python's
logging.Logger class with additional functionality for handling logging
scopes, categories, and structured logging.

Classes:
    StructuredLogger(logging.Logger): A logger that supports structured
                                      logging with scopes and categories.
"""


import logging

from jt_logger import _util


class StructuredLogger(logging.Logger):
    """
    A structured logger that supports scoped and categorized logging.

    Attributes:
        name (str): The name of the logger.
    """

    def __init__(self, name=None):
        """
        Initialize the StructuredLogger instance.

        Args:
            name (Optional[str]): Name of the logger. Defaults to the module's name.
        """

        name = name if name else __name__
        super().__init__(name)

    @staticmethod
    def push_scope(scope):
        """
        Push a scope onto the scope stack for structured logging.

        Args:
            scope (str): Scope string to be added to the scope stack.
        """

        _util._push_scope(scope)

    @staticmethod
    def pop_scope():
        """
        Pop the most recent scope from the scope stack.
        """

        _util._pop_scope()

    @staticmethod
    def clear_scope():
        """
        Clear all scopes from the scope stack.
        """

        _util._clear_scope()

    @staticmethod
    def set_category(category):
        """
        Set the logging category.

        Args:
            category (str): The logging category to set.
        """

        _util._set_category(category)

    def _setup_record(self, msg, event_id, extra, kwargs):
        """
        Set up the log record with message formatting and state.

        Args:
            msg (str): The message to be logged.
            event_id (int): The event ID associated with the log.
            extra (Optional[dict]): Extra data for the log record.
            kwargs (dict): Additional arguments for message formatting.

        Returns:
            tuple: The formatted message and the extra dictionary for the record.
        """

        extra = extra if extra else {}
        extra['event_id'] = event_id
        formatted_message, extra['state'] = self._format_message_and_state(msg, kwargs)
        return formatted_message, extra

    @staticmethod
    def _format_message_and_state(msg, kwargs):
        """
        Format the message and create a state dictionary.

        Args:
            msg (str): The message template.
            kwargs (dict): The keyword arguments to format the message.

        Returns:
            tuple: The formatted message and a state dictionary.
        """

        formatted_message = msg.format(**kwargs)
        state = {
            "Message": formatted_message,
            "{OriginalFormat}": msg,
            **kwargs
        }
        return formatted_message, state

    def debug(self, msg: str, *args, event_id=0, extra=None, **kwargs):
        """
        Log a message with DEBUG level.

        Args:
            msg (str): Message template.
            event_id (int): Event ID for the log entry.
            extra (Optional[dict]): Extra fields for the log entry.
            kwargs (dict): Arguments for formatting the message.
        """

        msg, extra = self._setup_record(msg, event_id, extra, kwargs)
        super().debug(msg, *args, extra=extra)

    def info(self, msg: str, *args, event_id=0, extra=None, **kwargs):
        """
        Log a message with INFO level.

        Args:
            msg (str): Message template.
            event_id (int): Event ID for the log entry.
            extra (Optional[dict]): Extra fields for the log entry.
            kwargs (dict): Arguments for formatting the message.
        """

        msg, extra = self._setup_record(msg, event_id, extra, kwargs)
        super().info(msg, *args, extra=extra)

    def warning(self, msg: str, *args, event_id=0, extra=None, **kwargs):
        """
        Log a message with WARNING level.

        Args:
            msg (str): Message template.
            event_id (int): Event ID for the log entry.
            extra (Optional[dict]): Extra fields for the log entry.
            kwargs (dict): Arguments for formatting the message.
        """

        msg, extra = self._setup_record(msg, event_id, extra,  kwargs)
        super().warning(msg, *args, extra=extra)

    def error(self, msg: str, *args, event_id=0, extra=None, **kwargs):
        """
        Log a message with ERROR level.

        Args:
            msg (str): Message template.
            event_id (int): Event ID for the log entry.
            extra (Optional[dict]): Extra fields for the log entry.
            kwargs (dict): Arguments for formatting the message.
        """

        msg, extra = self._setup_record(msg, event_id, extra, kwargs)
        super().error(msg, *args, extra=extra)

    def critical(self, msg: str, *args, event_id=0, extra=None, **kwargs):
        """
        Log a message with CRITICAL level.

        Args:
            msg (str): Message template.
            event_id (int): Event ID for the log entry.
            extra (Optional[dict]): Extra fields for the log entry.
            kwargs (dict): Arguments for formatting the message.
        """

        msg, extra = self._setup_record(msg, event_id, extra, kwargs)
        super().critical(msg, *args, extra=extra)


# That's all folks...
