"""Centralized Logging Configuration for Attune AI

Provides professional logging setup with:
- Console and file logging
- Structured logging with context
- Log rotation for production use
- Configurable log levels

Copyright 2025 Smart AI Memory, LLC
Licensed under the Apache License, Version 2.0
"""

import logging
import logging.handlers
import sys
from pathlib import Path


class StructuredFormatter(logging.Formatter):
    """Custom formatter for structured logging with context."""

    COLORS = {
        "DEBUG": "\033[36m",  # Cyan
        "INFO": "\033[32m",  # Green
        "WARNING": "\033[33m",  # Yellow
        "ERROR": "\033[31m",  # Red
        "CRITICAL": "\033[35m",  # Magenta
    }
    RESET = "\033[0m"
    BOLD = "\033[1m"

    def __init__(self, use_color: bool = True, include_context: bool = False):
        """Initialize formatter.

        Args:
            use_color: Whether to use colored output
            include_context: Whether to include contextual information

        """
        self.use_color = use_color and sys.stderr.isatty()
        self.include_context = include_context
        super().__init__()

    def format(self, record: logging.LogRecord) -> str:
        """Format log record with optional colors and context."""
        # Get color for this level
        color = self.COLORS.get(record.levelname, self.RESET) if self.use_color else ""
        reset = self.RESET if self.use_color else ""

        # Build the main log message
        timestamp = self.formatTime(record, "%Y-%m-%d %H:%M:%S")
        level_name = f"{color}{record.levelname}{reset}" if self.use_color else record.levelname

        # Format: [TIMESTAMP] [LEVEL] module.function: message
        log_msg = (
            f"[{timestamp}] [{level_name}] {record.name}:{record.funcName}: {record.getMessage()}"
        )

        # Add context if available
        if self.include_context and hasattr(record, "context"):
            context_str = " ".join(f"{k}={v}" for k, v in record.context.items())
            log_msg += f" [{context_str}]"

        # Add exception info if present
        if record.exc_info:
            log_msg += "\n" + self.formatException(record.exc_info)

        return log_msg


def create_logger(
    name: str,
    level: int = logging.INFO,
    log_file: str | None = None,
    log_dir: str | None = None,
    use_color: bool = True,
    include_context: bool = False,
    max_bytes: int = 10 * 1024 * 1024,  # 10MB
    backup_count: int = 5,
) -> logging.Logger:
    """Create a configured logger instance.

    Args:
        name: Logger name (typically __name__)
        level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
        log_file: Optional log file path
        log_dir: Optional log directory for file-based logging
        use_color: Whether to use colored console output
        include_context: Whether to include contextual information
        max_bytes: Max size of log file before rotation
        backup_count: Number of backup files to keep

    Returns:
        Configured logger instance

    Example:
        >>> logger = create_logger(__name__, level=logging.DEBUG)
        >>> logger.info("Application started")
        >>> logger.debug("Detailed debug information")

    """
    logger = logging.getLogger(name)

    # Avoid adding handlers multiple times
    if logger.handlers:
        return logger

    logger.setLevel(level)

    # Console handler
    console_handler = logging.StreamHandler(sys.stderr)
    console_handler.setLevel(level)
    console_formatter = StructuredFormatter(use_color=use_color, include_context=include_context)
    console_handler.setFormatter(console_formatter)
    logger.addHandler(console_handler)

    # File handler with rotation (if log_file or log_dir specified)
    if log_file or log_dir:
        if log_dir:
            log_dir_path = Path(log_dir)
            log_dir_path.mkdir(parents=True, exist_ok=True)
            log_file_path = log_dir_path / f"{name.replace('.', '_')}.log"
        else:
            log_file_path = Path(log_file)  # type: ignore[arg-type]
            log_file_path.parent.mkdir(parents=True, exist_ok=True)

        file_handler = logging.handlers.RotatingFileHandler(
            str(log_file_path),
            maxBytes=max_bytes,
            backupCount=backup_count,
        )
        file_handler.setLevel(level)
        file_formatter = StructuredFormatter(use_color=False, include_context=include_context)
        file_handler.setFormatter(file_formatter)
        logger.addHandler(file_handler)

    return logger


class LoggingConfig:
    """Centralized logging configuration manager."""

    _configured = False
    _loggers: dict[str, logging.Logger] = {}
    _level: int = logging.INFO
    _log_dir: str | None = None
    _use_color: bool = True
    _include_context: bool = False

    @classmethod
    def configure(
        cls,
        level: int = logging.INFO,
        log_dir: str | None = None,
        use_color: bool = True,
        include_context: bool = False,
    ) -> None:
        """Configure global logging settings.

        Args:
            level: Default logging level
            log_dir: Directory for log files
            use_color: Whether to use colored output
            include_context: Whether to include contextual information

        Example:
            >>> LoggingConfig.configure(
            ...     level=logging.DEBUG,
            ...     log_dir="./logs",
            ...     use_color=True
            ... )

        """
        cls._level = level
        cls._log_dir = log_dir
        cls._use_color = use_color
        cls._include_context = include_context
        cls._configured = True

    @classmethod
    def get_logger(
        cls,
        name: str,
        level: int | None = None,
    ) -> logging.Logger:
        """Get or create a logger instance.

        Args:
            name: Logger name (typically __name__)
            level: Optional override for logging level

        Returns:
            Configured logger instance

        Example:
            >>> logger = LoggingConfig.get_logger(__name__)
            >>> logger.info("Processing data")

        """
        if name not in cls._loggers:
            if not cls._configured:
                cls.configure()

            logger = create_logger(
                name,
                level=level or cls._level,
                log_dir=cls._log_dir,
                use_color=cls._use_color,
                include_context=cls._include_context,
            )
            cls._loggers[name] = logger

        return cls._loggers[name]

    @classmethod
    def set_level(cls, level: int) -> None:
        """Set logging level for all loggers."""
        for logger in cls._loggers.values():
            logger.setLevel(level)
            for handler in logger.handlers:
                handler.setLevel(level)


def get_logger(name: str) -> logging.Logger:
    """Convenience function to get a logger.

    This is the primary function to use throughout the codebase.

    Args:
        name: Logger name (typically __name__)

    Returns:
        Configured logger instance

    Example:
        >>> from attune.logging_config import get_logger
        >>> logger = get_logger(__name__)
        >>> logger.info("Starting process")
        >>> logger.debug("Processing item", extra={"context": {"item_id": 123}})

    """
    return LoggingConfig.get_logger(name)


# Initialize with environment variable support
def init_logging_from_env() -> None:
    """Initialize logging configuration from environment variables."""
    from attune.config.env_compat import get_attune_env

    log_level_str = (get_attune_env("LOG_LEVEL", "INFO") or "INFO").upper()
    log_level = getattr(logging, log_level_str, logging.INFO)

    log_dir = get_attune_env("LOG_DIR")
    use_color = (get_attune_env("LOG_COLOR", "true") or "true").lower() == "true"
    include_context = (get_attune_env("LOG_CONTEXT", "false") or "false").lower() == "true"

    LoggingConfig.configure(
        level=log_level,
        log_dir=log_dir,
        use_color=use_color,
        include_context=include_context,
    )
