import os
import logging
from logging.handlers import RotatingFileHandler
from .abstract_classes import SingletonMeta  # Your singleton metaclass
from .path_utils import mkdirs  # A helper to ensure directories exist

class AbstractLogManager(metaclass=SingletonMeta):
    """
    A singleton log manager that can configure and return loggers
    with rotating file handlers and optional console handlers.
    """
    def __init__(self, name: str = "AbstractLogManager"):
        self.logger = logging.getLogger(name)
        # Set logger's level to DEBUG so that all messages pass to handlers,
        # which will filter according to their own levels.
        self.logger.setLevel(logging.DEBUG)
        # We'll hold references to our handlers to update their levels later if needed.
        self.handlers = {}
    
    def add_file_handler(self, bpName: str, maxBytes: int, backupCount: int) -> None:
        """Add a rotating file handler if not already added."""
        if "file" not in self.handlers:
            log_dir = mkdirs("logs")
            log_path = os.path.join(log_dir, f"{bpName}.log")
            file_handler = RotatingFileHandler(log_path, maxBytes=maxBytes, backupCount=backupCount)
            file_handler.setLevel(logging.INFO)
            formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
            file_handler.setFormatter(formatter)
            self.logger.addHandler(file_handler)
            self.handlers["file"] = file_handler

    def add_console_handler(self, level: int) -> None:
        """Add a console handler with the given level if not already added."""
        if "console" not in self.handlers:
            console_handler = logging.StreamHandler()
            console_handler.setLevel(level)
            formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
            console_handler.setFormatter(formatter)
            self.logger.addHandler(console_handler)
            self.handlers["console"] = console_handler
        else:
            # If the console handler exists, update its level.
            self.handlers["console"].setLevel(level)

    def get_logger(self) -> logging.Logger:
        """Return the managed logger."""
        return self.logger

def get_logFile(
    bpName: str,
    maxBytes: int = 100000,
    backupCount: int = 3,
    console: bool = True,
    debug: bool = True,
    info: bool = False,
    warning: bool = False
) -> logging.Logger:
    """
    Returns a logger with a rotating file handler and optional console handler.
    
    Parameters:
      bpName (str): Base name for the logger (also used for the log filename).
      maxBytes (int): Maximum bytes before the log file rotates.
      backupCount (int): Number of rotated files to keep.
      console (bool): Whether to add console logging.
      debug (bool): If True, console logging will be set to DEBUG level.
      info (bool): If True (and debug is False), console logging is set to INFO.
      warning (bool): If True (and debug and info are False), console logging is set to WARNING.
    
    Returns:
      logging.Logger: The configured logger.
    """
    # Instantiate the log manager (singleton) using bpName as the logger name.
    log_mgr = AbstractLogManager(bpName)
    
    # Always add the file handler.
    log_mgr.add_file_handler(bpName, maxBytes, backupCount)
    
    # Determine which console level to use.
    if console:
        if debug:
            console_level = logging.DEBUG
        elif info:
            console_level = logging.INFO
        elif warning:
            console_level = logging.WARNING
        else:
            # If none are True, you can default to not adding a console handler or set to ERROR.
            console_level = logging.ERROR
        log_mgr.add_console_handler(console_level)
    
    return log_mgr.get_logger()

