# --- START OF FILE logging_config.py ---

# logging_config.py
"""
THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

Configures logging for the application.

Includes a custom filter (DebugControlFilter) to control DEBUG messages based on
flags in the config module, and a setup function (setup_logging) to configure
the root logger, handlers, formatters, and apply the filter.
"""

# Standard library imports
import logging
import sys

# Local application imports
import config  # For DEBUG flags and logging levels


# --- Custom Logging Filter ---
class DebugControlFilter(logging.Filter):
    """
    Filters log messages based on level and specific DEBUG flags in `config`.

    Allows all messages with level > DEBUG.
    Filters DEBUG messages based on message prefixes and corresponding
    boolean flags defined in the `config` module.
    """

    def filter(self, record):
        """
        Determines if the specified log record should be processed.

        Args:
            record (logging.LogRecord): The log record to check.

        Returns:
            bool: True if the record should be logged, False otherwise.
        """
        # Allow levels higher than DEBUG unconditionally
        if record.levelno > logging.DEBUG:
            return True

        # Block levels lower than DEBUG (shouldn't happen if root is DEBUG)
        if record.levelno < logging.DEBUG:
            return False

        # --- Filter DEBUG messages based on prefixes and config flags ---
        if record.levelno == logging.DEBUG:
            msg = record.getMessage()  # Get the formatted message content

            # Check Map related prefixes first
            map_prefixes = (
                "[Map",  # Cattura [MapTileManager], [MapIntegrationManager], [MapUtils], [MapService], [MapDisplay]
                # Aggiungi altri prefissi specifici se necessario (es. da helper interni)
            )
            if msg.startswith(map_prefixes):
                # Se il messaggio inizia con un prefisso mappa E il flag è True, mostralo
                if config.DEBUG_MAP_DETAILS:
                    return True
                else:
                    # Altrimenti, se il flag è False, blocca questo messaggio DEBUG mappa
                    return False

            # Check prefixes against corresponding config flags
            # App General & Lifecycle
            if msg.startswith("[App Init]") and config.DEBUG_APP_LIFECYCLE:
                return True
            elif msg.startswith("[App Shutdown]") and config.DEBUG_APP_LIFECYCLE:
                return True
            elif msg.startswith("[App Status]") and config.DEBUG_APP_STATUS:
                return True
            elif msg.startswith("[AppState") and config.DEBUG_APP_LIFECYCLE:
                return True  # AppState logs
            elif msg.startswith("[App MainThread") and config.DEBUG_APP_LIFECYCLE:
                return True  # Main thread processing logs

            # App Callbacks & Processing
            elif msg.startswith("[App CB") and config.DEBUG_APP_CALLBACKS:
                if msg.startswith("[App CB MFD Param]") and config.DEBUG_APP_MFD_PARAMS:
                    return True
                elif not msg.startswith("[App CB MFD Param]"):
                    return True  # Allow general CB if not MFD specific
            elif msg.startswith("[App QProc") and config.DEBUG_APP_QUEUE_PROCESSING:
                return True
            elif msg.startswith("[App Proc") and config.DEBUG_APP_IMG_PROCESSING:
                return True

            # App Specific Features
            elif msg.startswith("[App Test") and config.DEBUG_APP_TEST_MODE:
                return True
            elif msg.startswith("[App GeoCalc]") and config.DEBUG_APP_GEO_CALC:
                return True
            elif msg.startswith("[MFD LUT Update]") and config.DEBUG_APP_MFD_PARAMS:
                return True
            elif msg.startswith("[App Trigger") and config.DEBUG_APP_TRIGGER:
                return True

            # Map related App logs
            elif msg.startswith("[App Init Map") and config.DEBUG_APP_LIFECYCLE:
                return True
            elif msg.startswith("[App Map Update]") and config.DEBUG_APP_LIFECYCLE:
                return True

            # Receiver Related
            elif msg.startswith("[Receiver Loop]") and config.DEBUG_RECEIVER_LOOP:
                return True
            elif msg.startswith("[Receiver ACK]") and config.DEBUG_RECEIVER_ACK:
                return True
            elif msg.startswith("[Receiver Cleanup]") and config.DEBUG_RECEIVER_CLEANUP:
                return True
            elif "Rcvd: Key=" in msg and config.DEBUG_RECEIVER_PACKETS:
                return True  # Raw packet header
            elif (
                msg.startswith("[Worker")
                or msg.startswith("[Receiver Reassembly]")
                or "Reassembling" in msg
                or "Identified" in msg
                or "reassemble" in msg.lower()
                or "New TX" in msg
                or "All frags" in msg
                or "Cleaned Key=" in msg
                or "Submit" in msg
                or "pixel data offset" in msg
                or "cleanup" in msg.lower()
            ) and config.DEBUG_RECEIVER_REASSEMBLY:
                return True  # Reassembly logs
            elif (
                msg.startswith("[Geo extract]")
                or "GeoInfo:" in msg
                or "Invalid GeoInfo" in msg
                or "Invalid SAR meta" in msg
                or "Invalid MFD meta" in msg
                or "GeoData extraction" in msg
            ) and config.DEBUG_RECEIVER_GEO:
                return True  # Geo extraction logs

            # Display/UI Related
            elif msg.startswith("[DisplayMgr]") and config.DEBUG_DISPLAY_MANAGER:
                return True
            elif msg.startswith("[MapDisplay]") and config.DEBUG_DISPLAY_MANAGER:
                return True
            elif msg.startswith("[UI Setup]") and config.DEBUG_APP_LIFECYCLE:
                return True  # UI creation logs
            elif msg.startswith("[UI Update]") and config.DEBUG_APP_CALLBACKS:
                return True  # General UI updates
            elif msg.startswith("[UI Status]") and config.DEBUG_APP_STATUS:
                return True  # Status bar updates

            # Utility Modules
            elif msg.startswith("[Utils") and config.DEBUG_UTILS:
                return True
            elif msg.startswith("[Network") and config.DEBUG_NETWORK:
                return True
            elif msg.startswith("[ImageProcessing") and config.DEBUG_IMAGE_PROCESSING:
                return True
            elif msg.startswith("[MapUtils") and config.DEBUG_UTILS:
                return True
            elif msg.startswith("[MapTileManager") and config.DEBUG_UTILS:
                return True
            elif msg.startswith("[MapService") and config.DEBUG_UTILS:
                return True

            # Default: Block DEBUG message if no specific flag allows it
            return False

        # Should not be reached if handler level > DEBUG, but return False defensively
        return False


# --- Logging Setup Function ---
def setup_logging():
    """Configures the root logger for the application using DebugControlFilter."""
    log_prefix = "[Log Setup]"  # Prefix for this function's messages

    # Check if logging is already configured (simple check based on handlers)
    root_logger = logging.getLogger()
    if root_logger.hasHandlers():
        # Check if our specific handler/filter is already present
        has_our_filter = any(
            isinstance(f, DebugControlFilter)
            for h in root_logger.handlers
            for f in h.filters
        )
        if has_our_filter:
            logging.debug(
                f"{log_prefix} Logging seems already configured with DebugControlFilter. Skipping setup."
            )
            return  # Avoid re-configuring if already done

    # Include thread name in the log format
    log_format = "%(asctime)s - %(levelname)s - [%(threadName)s] - %(filename)s:%(lineno)d - %(message)s"
    log_formatter = logging.Formatter(log_format)

    # Re-configure root logger if needed (e.g., level changed)
    # Ensure root level is low enough to allow filter to work on DEBUG messages
    root_logger.setLevel(config.LOG_ROOT_LEVEL)

    # Remove existing handlers before adding new ones to prevent duplication
    # (More robust reconfiguration)
    # Use print here as logging might be in an intermediate state
    if root_logger.handlers:
        print(
            f"{log_prefix} Removing existing logging handlers before reconfiguration."
        )
        for handler in root_logger.handlers[:]:  # Iterate over a copy
            root_logger.removeHandler(handler)
            handler.close()  # Close the handler properly

    # Configure console handler
    # Use stderr by default for logs? Or keep stdout? Default is stderr for StreamHandler.
    console_handler = logging.StreamHandler(
        sys.stdout
    )  # Explicitly use stdout for visibility? Or stderr?
    console_handler.setLevel(config.LOG_HANDLER_LEVEL)  # Use level from config
    console_handler.setFormatter(log_formatter)

    # Add custom filter
    debug_filter = DebugControlFilter()
    console_handler.addFilter(debug_filter)

    # Add the configured handler to the root logger
    root_logger.addHandler(console_handler)

    # Use INFO level for confirmation messages after setup
    logging.info(f"{log_prefix} Console log handler added and configured.")
    logging.info(
        f"{log_prefix} Logging configured: Root Level={logging.getLevelName(root_logger.level)}, "
        f"Handler Level={logging.getLevelName(console_handler.level)}"
    )
    # Log status of all current debug flags
    log_flags_status = (
        f"{log_prefix} Debug Flags: Rcv["
        f"Pkt:{config.DEBUG_RECEIVER_PACKETS},"
        f"Rsm:{config.DEBUG_RECEIVER_REASSEMBLY},"
        f"Geo:{config.DEBUG_RECEIVER_GEO},"
        f"Loop:{config.DEBUG_RECEIVER_LOOP},"
        f"Ack:{config.DEBUG_RECEIVER_ACK},"
        f"Cln:{config.DEBUG_RECEIVER_CLEANUP}], "
        f"App["
        f"Life:{config.DEBUG_APP_LIFECYCLE},"
        f"CB:{config.DEBUG_APP_CALLBACKS},"
        f"Q:{config.DEBUG_APP_QUEUE_PROCESSING},"
        f"Proc:{config.DEBUG_APP_IMG_PROCESSING},"
        f"Test:{config.DEBUG_APP_TEST_MODE},"
        f"GeoCalc:{config.DEBUG_APP_GEO_CALC},"
        f"MFDParam:{config.DEBUG_APP_MFD_PARAMS},"
        f"Stat:{config.DEBUG_APP_STATUS},"
        f"Trig:{config.DEBUG_APP_TRIGGER}], "
        f"Disp:{config.DEBUG_DISPLAY_MANAGER}, "
        f"Map:{config.DEBUG_MAP_DETAILS}, "
        f"Util:{config.DEBUG_UTILS}, "
        f"Net:{config.DEBUG_NETWORK}, "
        f"ImgProc:{config.DEBUG_IMAGE_PROCESSING}"
        "]"
    )
    logging.info(log_flags_status)


# --- END OF FILE logging_config.py ---
