"""
logging_sync.py

Synchronized logging wrapper for multiprocessing environments.

This module provides a SynchronizedLogger that wraps lupin_logger instances
with a multiprocessing.Lock to prevent log messages from being interleaved
when multiple processes write to stdout/stderr simultaneously.
"""

from multiprocessing import Lock, Manager
from typing import Optional
from lupin_logger import get_logger, CustomLogger

# Global lock shared across all processes
# Must be initialized in the main process before spawning workers
_global_log_lock: Optional[Lock] = None
_lock_manager: Optional[Manager] = None


def initialize_log_lock(manager: Optional[Manager] = None) -> Lock:
    """
    Initialize the global shared lock.

    This should be called in the main process before spawning workers.
    If a Manager is provided, use it. Otherwise, create a new one.

    Args:
        manager: Optional Manager instance (if None, creates a new one)

    Returns:
        multiprocessing.Lock instance shared across all processes
    """
    global _global_log_lock, _lock_manager

    if _global_log_lock is None:
        if manager is None:
            _lock_manager = Manager()
            _global_log_lock = _lock_manager.Lock()
        else:
            _lock_manager = manager
            _global_log_lock = manager.Lock()

    return _global_log_lock


def _get_global_lock() -> Lock:
    """
    Get the global shared lock, creating it if necessary.

    WARNING: If called in a worker process before initialization in main,
    this will create a new Manager which won't be shared. Use initialize_log_lock()
    in the main process first.

    Returns:
        multiprocessing.Lock instance shared across all processes
    """
    global _global_log_lock  # noqa: F824

    if _global_log_lock is None:
        # Fallback: create a Manager if not initialized
        # This should ideally not happen if initialize_log_lock() is called first
        # Note: initialize_log_lock() assigns _global_log_lock and _lock_manager
        initialize_log_lock()

    return _global_log_lock


class SynchronizedLogger:
    """
    Wrapper around a logger that synchronizes all logging calls with a lock.

    This ensures that log messages from multiple processes don't get interleaved
    when writing to stdout/stderr.
    """

    def __init__(self, logger: CustomLogger, lock: Lock):
        """
        Initialize the synchronized logger.

        Args:
            logger: The underlying logger instance to wrap
            lock: multiprocessing.Lock to use for synchronization
        """
        self._logger = logger
        self._lock = lock

    def _sync_call(self, method_name: str, *args, **kwargs):
        """
        Call a logger method with synchronization.

        Args:
            method_name: Name of the logger method to call
            *args: Positional arguments for the method
            **kwargs: Keyword arguments for the method
        """
        with self._lock:
            method = getattr(self._logger, method_name)
            return method(*args, **kwargs)

    def info(self, *args, **kwargs):
        """Log an info message with synchronization."""
        return self._sync_call("info", *args, **kwargs)

    def error(self, *args, **kwargs):
        """Log an error message with synchronization."""
        return self._sync_call("error", *args, **kwargs)

    def notice(self, *args, **kwargs):
        """Log a notice message with synchronization."""
        return self._sync_call("notice", *args, **kwargs)

    def warning(self, *args, **kwargs):
        """Log a warning message with synchronization."""
        return self._sync_call("warning", *args, **kwargs)

    def debug(self, *args, **kwargs):
        """Log a debug message with synchronization."""
        return self._sync_call("debug", *args, **kwargs)

    def exception(self, *args, **kwargs):
        """Log an exception with synchronization."""
        return self._sync_call("exception", *args, **kwargs)


def get_synchronized_logger(name: str, app: str = "error_map") -> SynchronizedLogger:
    """
    Replacement for get_logger() that always returns a synchronized logger.

    This function should be used instead of get_logger() to ensure all logs
    are synchronized when using multiprocessing.

    Args:
        name: Name of the logger
        app: Name of the application

    Returns:
        SynchronizedLogger instance that wraps the real logger
    """
    logger = get_logger(name, app=app)
    lock = _get_global_lock()
    return SynchronizedLogger(logger, lock)
