"""Log handler configuration and setup utilities."""

import logging
import sys
from logging.handlers import RotatingFileHandler

from .api_handler import LoggerHandler
from .config import LogConfig
from .formatter import CustomFormatter, StructuredJsonFormatter

__all__ = ("get_handlers_data", "GracefulShutdownFilter")


class _NonErrorFilter(logging.Filter):
    """Filter that allows only DEBUG, INFO, and WARNING level logs.

    Used to route non-error logs to stdout when using JSON logging,
    allowing log aggregators to color them appropriately based on the level field.
    """

    def filter(self, record: logging.LogRecord) -> bool:
        """Return True if the log level is below ERROR."""
        return record.levelno < logging.ERROR


class _ErrorFilter(logging.Filter):
    """Filter that allows only ERROR and CRITICAL level logs.

    Used to route error logs to stderr when using JSON logging,
    ensuring they are visually distinguished in log viewers.
    """

    def filter(self, record: logging.LogRecord) -> bool:
        """Return True if the log level is ERROR or higher."""
        return record.levelno >= logging.ERROR


class GracefulShutdownFilter(logging.Filter):
    """Filter that downgrades graceful shutdown messages from ERROR to WARNING.

    This filter intercepts log messages related to graceful shutdown (SIGTERM,
    shutdown notifications) and downgrades them from ERROR to WARNING level.
    This prevents cloud platforms like Railway from flagging normal shutdown
    sequences as errors.

    Patterns matched (case-insensitive):
        - "SIGTERM" - Worker termination signals
        - "Shutting down" - Master shutdown notifications
        - "Worker exiting" - Worker exit messages
    """

    # Patterns that indicate graceful shutdown (not real errors)
    _SHUTDOWN_PATTERNS = (
        "sigterm",
        "shutting down",
        "worker exiting",
        "handling signal",
        "received signal",
    )

    def filter(self, record: logging.LogRecord) -> bool:
        """Downgrade shutdown-related ERROR logs to WARNING.

        Args:
            record: The log record to filter.

        Returns:
            Always True (allows all records through after potential modification).
        """
        if record.levelno >= logging.ERROR:
            message = record.getMessage().lower()
            for pattern in self._SHUTDOWN_PATTERNS:
                if pattern in message:
                    record.levelno = logging.WARNING
                    record.levelname = "WARNING"
                    break
        return True


def get_handlers_data(config: LogConfig) -> tuple[list[logging.Handler], int]:
    """Configure and return a list of log handlers based on the provided
    config.

    This function sets up handlers for API logging, console output, and file
    rotation, depending on the settings in the LogConfig object. Each handler
    is configured with the appropriate formatter and log level.

    Args:
        config: The LogConfig object containing the logging configuration.

    Returns:
        A tuple containing:
            - A list of configured logging handlers (may be empty if no handlers enabled).
            - The resolved log level as a logging module constant (e.g., logging.INFO).
    """
    formatter = CustomFormatter()
    log_level = getattr(logging, config.get("log_level", default="INFO"))

    handlers: list[logging.Handler] = []

    # Configure API handler if API URL and key are provided in the config
    # This handler will send logs to a remote API endpoint, and can be set to
    # only send logs marked as "footprints" if 'only_footprint_mode' is enabled
    # This allows for flexible log management, where detailed logs can be sent to
    # the API while less critical logs can be filtered out when desired
    logging_api_url = config.get("api_url")
    logging_api_key = config.get("api_key")
    only_footprint_mode = config.get("only_footprint_mode", True)
    if logging_api_url and logging_api_key:
        api_handler = LoggerHandler(
            logging_api_url=logging_api_url,
            logging_api_key=logging_api_key,
            only_footprint_mode=only_footprint_mode,
        )
        api_handler.setLevel(log_level)
        api_handler.setFormatter(formatter)
        handlers.append(api_handler)

    # Configure console handler if log_print is enabled in the config
    # Default is False, so console logging is opt-in
    # This allows users to enable console logging during development or
    # debugging without affecting production logs
    log_print = config.get("log_print", default=False)
    if log_print:
        # Check if JSON format is enabled (default: True)
        json_log_print = config.get("json_log_print", default=True)

        if json_log_print:
            # JSON mode: use dual handlers for proper stderr/stdout routing
            # This ensures ERROR/CRITICAL logs go to stderr (often shown in red)
            # while other logs go to stdout
            json_formatter = StructuredJsonFormatter()

            # stdout handler for DEBUG, INFO, WARNING (non-error logs)
            stdout_handler = logging.StreamHandler(sys.stdout)
            stdout_handler.setLevel(log_level)
            stdout_handler.setFormatter(json_formatter)
            stdout_handler.addFilter(_NonErrorFilter())
            handlers.append(stdout_handler)

            # stderr handler for ERROR, CRITICAL (error logs)
            stderr_handler = logging.StreamHandler(sys.stderr)
            stderr_handler.setLevel(log_level)
            stderr_handler.setFormatter(json_formatter)
            stderr_handler.addFilter(_ErrorFilter())
            handlers.append(stderr_handler)
        else:
            # Traditional text format: single handler with CustomFormatter
            console_handler = logging.StreamHandler()
            console_handler.setLevel(log_level)
            console_handler.setFormatter(formatter)
            handlers.append(console_handler)

    # Configure file handler if log_store is enabled in the config
    # Default file name is 'app.log', with a max size of 10 MB and 1 backup file
    # These defaults can be overridden in the config with 'log_file_name',
    # 'log_file_max_size', and 'log_file_backup_count'
    log_store = config.get("log_store", default=False)
    if log_store:
        log_file_name = config.get("log_file_name", default="app.log")
        log_file_backup_count = config.get("log_file_backup_count", default=1) or 1
        log_file_max_size = config.get("log_file_max_size", default=(10 * 1024 * 1024))
        rotating_handler = RotatingFileHandler(
            log_file_name, maxBytes=log_file_max_size, backupCount=log_file_backup_count
        )
        rotating_handler.setLevel(log_level)
        rotating_handler.setFormatter(formatter)
        handlers.append(rotating_handler)

    return handlers, log_level
