"""Logging configuration for the Trax platform.

This module provides centralized logging configuration with support for:
- Structured JSON logging
- File rotation based on size and time
- Environment-based configuration
- Performance metrics integration
- Debug mode with verbose logging
"""

import json
import logging
import logging.handlers
import os
import sys
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Union

from ..config import config


@dataclass
class LoggingConfig:
    """Configuration for the logging system."""
    
    # Log levels
    level: str = "INFO"
    debug_mode: bool = False
    
    # Output configuration
    log_to_console: bool = True
    log_to_file: bool = True
    log_to_json: bool = True
    
    # File configuration
    log_dir: str = "logs"
    log_filename: str = "trax.log"
    max_file_size: int = 10 * 1024 * 1024  # 10MB
    backup_count: int = 5
    rotate_when: str = "midnight"
    
    # Format configuration
    include_timestamp: bool = True
    include_module: bool = True
    include_function: bool = True
    include_line_number: bool = True
    include_process_id: bool = True
    include_thread_id: bool = True
    
    # Performance metrics
    enable_performance_logging: bool = True
    performance_threshold_ms: int = 1000  # Log operations taking > 1 second
    
    # Error tracking
    enable_error_tracking: bool = True
    error_context_depth: int = 3
    
    # Structured logging
    include_context: bool = True
    include_correlation_id: bool = True
    
    def __post_init__(self):
        """Post-initialization setup."""
        # Set debug mode based on environment
        if os.getenv("TRAX_DEBUG", "false").lower() == "true":
            self.debug_mode = True
            self.level = "DEBUG"
        
        # Override with environment variables
        if level := os.getenv("TRAX_LOG_LEVEL"):
            self.level = level.upper()
        
        if log_dir := os.getenv("TRAX_LOG_DIR"):
            self.log_dir = log_dir
        
        if max_size := os.getenv("TRAX_LOG_MAX_SIZE"):
            self.max_file_size = int(max_size)
        
        if backup_count := os.getenv("TRAX_LOG_BACKUP_COUNT"):
            self.backup_count = int(backup_count)


class StructuredFormatter(logging.Formatter):
    """Structured formatter for JSON logging."""
    
    def __init__(self, config: LoggingConfig):
        super().__init__()
        self.config = config
    
    def format(self, record: logging.LogRecord) -> str:
        """Format log record as structured JSON."""
        log_entry = {
            "timestamp": datetime.utcnow().isoformat() + "Z",
            "level": record.levelname,
            "message": record.getMessage(),
            "logger": record.name,
        }
        
        # Add contextual information
        if self.config.include_module:
            log_entry["module"] = record.module
        
        if self.config.include_function:
            log_entry["function"] = record.funcName
        
        if self.config.include_line_number:
            log_entry["line"] = record.lineno
        
        if self.config.include_process_id:
            log_entry["pid"] = record.process
        
        if self.config.include_thread_id:
            log_entry["thread"] = record.thread
        
        # Add exception information
        if record.exc_info:
            log_entry["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 extra fields from record (avoid conflicts with standard fields)
        for key, value in record.__dict__.items():
            if key not in ["name", "msg", "args", "levelname", "levelno", "pathname", 
                          "filename", "module", "lineno", "funcName", "created", 
                          "msecs", "relativeCreated", "thread", "threadName", 
                          "processName", "process", "getMessage", "exc_info", 
                          "exc_text", "stack_info", "message"]:
                log_entry[key] = value
        
        return json.dumps(log_entry, default=str)


class HumanReadableFormatter(logging.Formatter):
    """Human-readable formatter for console output."""
    
    def __init__(self, config: LoggingConfig):
        format_parts = []
        
        if config.include_timestamp:
            format_parts.append("%(asctime)s")
        
        format_parts.append("%(levelname)s")
        
        if config.include_module:
            format_parts.append("[%(name)s]")
        
        if config.include_function:
            format_parts.append("%(funcName)s")
        
        if config.include_line_number:
            format_parts.append(":%(lineno)d")
        
        format_parts.append("- %(message)s")
        
        super().__init__(" ".join(format_parts))
        self.config = config


def setup_logging(config: Optional[LoggingConfig] = None) -> None:
    """Setup the logging system with the given configuration."""
    if config is None:
        config = LoggingConfig()
    
    # Create log directory
    log_path = Path(config.log_dir)
    log_path.mkdir(exist_ok=True)
    
    # Get root logger
    root_logger = logging.getLogger()
    root_logger.setLevel(getattr(logging, config.level))
    
    # Clear existing handlers
    root_logger.handlers.clear()
    
    # Console handler
    if config.log_to_console:
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setLevel(getattr(logging, config.level))
        
        if config.log_to_json:
            console_formatter = StructuredFormatter(config)
        else:
            console_formatter = HumanReadableFormatter(config)
        
        console_handler.setFormatter(console_formatter)
        root_logger.addHandler(console_handler)
    
    # File handler with rotation
    if config.log_to_file:
        log_file = log_path / config.log_filename
        
        if config.rotate_when == "size":
            file_handler = logging.handlers.RotatingFileHandler(
                log_file,
                maxBytes=config.max_file_size,
                backupCount=config.backup_count
            )
        else:
            file_handler = logging.handlers.TimedRotatingFileHandler(
                log_file,
                when=config.rotate_when,
                backupCount=config.backup_count
            )
        
        file_handler.setLevel(getattr(logging, config.level))
        
        if config.log_to_json:
            file_formatter = StructuredFormatter(config)
        else:
            file_formatter = HumanReadableFormatter(config)
        
        file_handler.setFormatter(file_formatter)
        root_logger.addHandler(file_handler)
    
    # Set specific logger levels
    logging.getLogger("asyncio").setLevel(logging.WARNING)
    logging.getLogger("urllib3").setLevel(logging.WARNING)
    logging.getLogger("openai").setLevel(logging.INFO)
    
    # Log configuration
    logger = logging.getLogger(__name__)
    logger.info("Logging system initialized", extra={
        "config": {
            "level": config.level,
            "debug_mode": config.debug_mode,
            "log_to_console": config.log_to_console,
            "log_to_file": config.log_to_file,
            "log_to_json": config.log_to_json,
            "log_dir": str(log_path),
            "max_file_size": config.max_file_size,
            "backup_count": config.backup_count
        }
    })


def get_logger(name: str) -> logging.Logger:
    """Get a logger with the given name."""
    return logging.getLogger(name)


def set_log_level(level: str) -> None:
    """Set the log level for all loggers."""
    logging.getLogger().setLevel(getattr(logging, level.upper()))
    
    logger = logging.getLogger(__name__)
    logger.info(f"Log level changed to {level.upper()}")


def enable_debug_mode() -> None:
    """Enable debug mode with verbose logging."""
    set_log_level("DEBUG")
    
    logger = logging.getLogger(__name__)
    logger.debug("Debug mode enabled")


def disable_debug_mode() -> None:
    """Disable debug mode."""
    set_log_level("INFO")
    
    logger = logging.getLogger(__name__)
    logger.info("Debug mode disabled")
