"""
Structured logging configuration for the Pixel API.

Provides JSON-formatted logging with contextual information including:
- Timestamp
- Log level
- Logger name
- Message
- Module, function, and line number
- Request ID (if available)
- User ID (if available)
- Exception information (if available)
"""
# Import logging module
import logging
import json
import sys
from datetime import datetime, timezone
from typing import Any, Dict


class JSONFormatter(logging.Formatter):
    """
    JSON formatter for structured logging.
    
    Outputs log records as JSON objects with consistent structure,
    making them easy to parse and analyze in log aggregation systems.
    """
    
    def format(self, record: logging.LogRecord) -> str:
        """ 格式化 a log record as JSON.
        
        Args:
            record: The log record to format
            
        Returns:
            JSON string representation of the log record
        """ 
        # Create base log data dictionary
        log_data: Dict[str, Any] = {
            "timestamp": datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z'),
            "level": record.levelname,
            "logger": record.name,
            "message": record.getMessage(),
            "module": record.module,
            "function": record.funcName,
            "line": record.lineno,
        }
        
        # Add request ID if available
        if hasattr(record, 'request_id'):
            log_data['request_id'] = record.request_id
        
        # Add user ID if available
        if hasattr(record, 'user_id'):
            log_data['user_id'] = record.user_id
        
        # Add any extra fields from the 'extra' parameter
        if hasattr(record, 'extra_fields'):
            log_data.update(record.extra_fields)
        
        # Add exception information if present
        if record.exc_info:
            log_data['exception'] = {
                'type': record.exc_info[0].__name__ if record.exc_info[0] else None,
                'message': str(record.exc_info[1]) if record.exc_info[1] else None,
                'traceback': self.formatException(record.exc_info)
            }
        
        # Add stack trace if present
        if record.stack_info:
            log_data['stack_trace'] = self.formatStack(record.stack_info)
        
        return json.dumps(log_data, ensure_ascii=False)


class ContextFilter(logging.Filter):
    """ 过滤 to add contextual information to log records.
    
    This filter can be used to add request-specific or user-specific
    information to all log records within a context.
    """
    
    def __init__(self, name: str = ''):
        super().__init__(name)
        self.context = {}
    
    def filter(self, record: logging.LogRecord) -> bool:
        """
        Add context information to the log record.
        
        Args:
            record: The log record to filter
            
        Returns:
            True to allow the record to be logged
        """
        # Add context fields to the record
        for key, value in self.context.items():
            setattr(record, key, value)
        
        # Ensure request_id always exists (even if empty)
        if not hasattr(record, 'request_id'):
            record.request_id = '-'
        
        # Ensure user_id always exists (even if empty)
        if not hasattr(record, 'user_id'):
            record.user_id = '-'
        
        return True
    
    def set_context(self, **kwargs):
        """ 集合 context information to be added to all log records.
        
        Args:
            **kwargs: Key-value pairs to add to the context
        """
        self.context.update(kwargs)
    
    def clear_context(self):
        """ 清除 all context information."""
        self.context.clear()


def setup_logging(
    level: str = "INFO",
    use_json: bool = True,
    log_file: str = None
):
    """ Setup structured logging for the application.
    
    Args:
        level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
        use_json: Whether to use JSON formatting (True) or standard formatting (False)
        log_file: Optional file path to write logs to (in addition to stdout)
    """
    # Get root logger
    root_logger = logging.getLogger()
    
    # 清除 any existing handlers
    root_logger.handlers.clear()
    
    # 集合 logging level
    log_level = getattr(logging, level.upper(), logging.INFO)
    root_logger.setLevel(log_level)
    
    # Create console handler
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(log_level)
    
    # Add context filter to all handlers
    console_handler.addFilter(context_filter)
    
    # 集合 formatter
    if use_json:
        formatter = JSONFormatter()
    else:
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - [%(request_id)s] - %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )
    
    console_handler.setFormatter(formatter)
    root_logger.addHandler(console_handler)
    
    # Add file handler if specified
    if log_file:
        file_handler = logging.FileHandler(log_file)
        file_handler.setLevel(log_level)
        file_handler.addFilter(context_filter)
        file_handler.setFormatter(formatter)
        root_logger.addHandler(file_handler)
    
    # 集合 logging level for third-party libraries
    logging.getLogger("uvicorn").setLevel(logging.WARNING)
    logging.getLogger("fastapi").setLevel(logging.WARNING)
    logging.getLogger("sqlalchemy").setLevel(logging.WARNING)
    logging.getLogger("dashscope").setLevel(logging.INFO)
    logging.getLogger("httpx").setLevel(logging.WARNING)
    logging.getLogger("openai").setLevel(logging.WARNING)  # Suppress OpenAI SDK debug logs
    logging.getLogger("httpcore").setLevel(logging.WARNING)  # Suppress HTTP connection pool logs
    logging.getLogger("urllib3").setLevel(logging.WARNING)  # Suppress urllib3 debug logs
    logging.getLogger("agentscope").setLevel(logging.INFO)  # AgentScope info only
    
    root_logger.info(
        "Logging configured",
        extra={
            'extra_fields': {
                'level': level,
                'json_format': use_json,
                'log_file': log_file
            }
        }
    )


def get_logger(name: str) -> logging.Logger:
    """ Get a logger instance with the specified name.
    
    Args:
        name: Name for the logger (typically __name__)
        
    Returns:
        Logger instance
    """ 
    # Get the logger instance with the specified name
    return logging.getLogger(name)


# Context filter instance for adding request/user context
context_filter = ContextFilter()


def set_log_context(**kwargs):
    """ 集合 context information to be added to all subsequent log records.
    
    Example:
        set_log_context(request_id="abc123", user_id="user456")
    
    Args:
        **kwargs: Key-value pairs to add to the logging context
    """
    context_filter.set_context(**kwargs)


def clear_log_context():
    """ 清除 all logging context information."""
    context_filter.clear_context()
