#!/usr/bin/env python3
"""
Logging Utilities

This module provides logging configuration and utilities for the Oracle MCP server.
"""

import os
import logging
import logging.handlers
import sys
from typing import Optional


def setup_logging(
    level: str = None,
    log_file: str = None,
    max_bytes: int = 10485760,  # 10MB
    backup_count: int = 5,
) -> None:
    """
    Setup logging configuration for the application.

    Args:
        level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
        log_file: Path to log file (optional, defaults to console only)
        max_bytes: Maximum log file size in bytes
        backup_count: Number of backup log files to keep
    """
    # Determine log level from environment or parameter
    if level is None:
        level = os.getenv("MCP_LOG_LEVEL", "INFO").upper()

    # Convert string level to logging constant
    numeric_level = getattr(logging, level, logging.INFO)

    # Create root logger
    logger = logging.getLogger()
    logger.setLevel(numeric_level)

    # Clear any existing handlers
    logger.handlers.clear()

    # Create formatter
    formatter = logging.Formatter(
        "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    # Console handler
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(numeric_level)
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)

    # File handler (if log file specified)
    if log_file or os.getenv("MCP_LOG_FILE"):
        log_path = log_file or os.getenv("MCP_LOG_FILE")
        try:
            # Use rotating file handler to manage log size
            file_handler = logging.handlers.RotatingFileHandler(
                log_path, maxBytes=max_bytes, backupCount=backup_count, encoding="utf-8"
            )
            file_handler.setLevel(numeric_level)
            file_handler.setFormatter(formatter)
            logger.addHandler(file_handler)
        except Exception as e:
            # If file handler fails, log to console
            console_handler.handle(
                logging.LogRecord(
                    name="util.log",
                    level=logging.WARNING,
                    pathname="",
                    lineno=0,
                    msg=f"Failed to create file handler for {log_path}: {e}",
                    args=(),
                    exc_info=None,
                )
            )

    # Set specific logger levels to reduce noise
    logging.getLogger("urllib3").setLevel(logging.WARNING)
    logging.getLogger("requests").setLevel(logging.WARNING)


def get_logger(name: str) -> logging.Logger:
    """
    Get a logger instance with the specified name.

    Args:
        name: Logger name (typically __name__ from calling module)

    Returns:
        logging.Logger: Logger instance
    """
    return logging.getLogger(name)


def log_query(logger: logging.Logger, query: str, params: dict = None) -> None:
    """
    Log a SQL query with parameters (without sensitive data).

    Args:
        logger: Logger instance
        query: SQL query to log
        params: Query parameters (optional)
    """
    # Truncate very long queries
    max_query_length = 500
    truncated_query = query[:max_query_length]
    if len(query) > max_query_length:
        truncated_query += "... [truncated]"

    # Log the query
    logger.info(f"Executing query: {truncated_query}")

    # Log parameters if provided (but filter out sensitive ones)
    if params:
        safe_params = _filter_sensitive_params(params)
        if safe_params:
            logger.debug(f"Query parameters: {safe_params}")


def log_error(logger: logging.Logger, error: Exception, context: str = None) -> None:
    """
    Log an error with context information.

    Args:
        logger: Logger instance
        error: Exception to log
        context: Additional context information (optional)
    """
    error_msg = f"Error: {str(error)}"
    if context:
        error_msg = f"{context} - {error_msg}"

    logger.error(error_msg, exc_info=True)


def log_performance(
    logger: logging.Logger, operation: str, duration: float, details: dict = None
) -> None:
    """
    Log performance information for an operation.

    Args:
        logger: Logger instance
        operation: Name of the operation
        duration: Duration in seconds
        details: Additional performance details (optional)
    """
    perf_msg = f"Performance: {operation} completed in {duration:.3f}s"

    if details:
        perf_msg += f" - {details}"

    logger.info(perf_msg)


def _filter_sensitive_params(params: dict) -> dict:
    """
    Filter out sensitive parameters from logging.

    Args:
        params: Original parameters

    Returns:
        dict: Filtered parameters safe for logging
    """
    if not params:
        return {}

    # List of sensitive parameter names
    sensitive_keys = ["password", "pass", "pwd", "secret", "token", "key"]

    filtered = {}
    for key, value in params.items():
        # Check if key contains any sensitive keywords (case insensitive)
        key_lower = key.lower()
        if any(sensitive in key_lower for sensitive in sensitive_keys):
            filtered[key] = "[REDACTED]"
        else:
            filtered[key] = value

    return filtered


class LoggerAdapter(logging.LoggerAdapter):
    """
    Custom logger adapter that adds context information to log records.
    """

    def __init__(self, logger: logging.Logger, extra: dict = None):
        """
        Initialize the adapter.

        Args:
            logger: Base logger
            extra: Extra context information
        """
        super().__init__(logger, extra or {})

    def process(self, msg: str, kwargs: dict) -> tuple:
        """
        Process the log message and kwargs.

        Args:
            msg: Log message
            kwargs: Logging kwargs

        Returns:
            tuple: Processed message and kwargs
        """
        # Add context information to the message
        if self.extra:
            context_str = " ".join(f"{k}={v}" for k, v in self.extra.items())
            msg = f"{msg} [{context_str}]"

        return msg, kwargs


def get_context_logger(name: str, context: dict = None) -> logging.LoggerAdapter:
    """
    Get a logger adapter with context information.

    Args:
        name: Logger name
        context: Context information to include in logs

    Returns:
        logging.LoggerAdapter: Logger adapter with context
    """
    logger = logging.getLogger(name)
    return LoggerAdapter(logger, context)


# Initialize logging when module is imported
setup_logging()
