"""
Logging Configuration for BrighterTrading.

Provides structured logging with consistent formatting across all modules.
"""

import logging
import sys
from typing import Optional, Dict, Any
from datetime import datetime
import json


class StructuredFormatter(logging.Formatter):
    """
    Formatter that outputs structured JSON logs for production use.
    """

    def format(self, record: logging.LogRecord) -> str:
        log_record = {
            'timestamp': datetime.utcnow().isoformat() + 'Z',
            'level': record.levelname,
            'logger': record.name,
            'message': record.getMessage(),
            'module': record.module,
            'function': record.funcName,
            'line': record.lineno,
        }

        # Add exception info if present
        if record.exc_info:
            log_record['exception'] = self.formatException(record.exc_info)

        # Add extra fields if present
        if hasattr(record, 'extra_data'):
            log_record.update(record.extra_data)

        return json.dumps(log_record)


class ColoredFormatter(logging.Formatter):
    """
    Formatter with colored output for development use.
    """

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

    def format(self, record: logging.LogRecord) -> str:
        color = self.COLORS.get(record.levelname, self.RESET)
        formatted = super().format(record)
        return f"{color}{formatted}{self.RESET}"


def configure_logging(
    level: str = 'INFO',
    structured: bool = False,
    log_file: Optional[str] = None,
) -> None:
    """
    Configure logging for the application.

    :param level: Log level ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
    :param structured: Use structured JSON logging (for production).
    :param log_file: Optional log file path.
    """
    root_logger = logging.getLogger()
    root_logger.setLevel(getattr(logging, level.upper()))

    # Remove existing handlers
    for handler in root_logger.handlers[:]:
        root_logger.removeHandler(handler)

    # Console handler
    console_handler = logging.StreamHandler(sys.stdout)

    if structured:
        console_handler.setFormatter(StructuredFormatter())
    else:
        console_handler.setFormatter(ColoredFormatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        ))

    root_logger.addHandler(console_handler)

    # File handler if specified
    if log_file:
        file_handler = logging.FileHandler(log_file)
        file_handler.setFormatter(StructuredFormatter())
        root_logger.addHandler(file_handler)


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

    :param name: Logger name (typically __name__).
    :return: Logger instance.
    """
    return logging.getLogger(name)


class TradingLogger:
    """
    Specialized logger for trading operations with structured fields.
    """

    def __init__(self, logger: logging.Logger):
        self._logger = logger

    def _log_with_context(
        self,
        level: int,
        message: str,
        user_id: Optional[int] = None,
        strategy_id: Optional[str] = None,
        order_id: Optional[str] = None,
        symbol: Optional[str] = None,
        **kwargs
    ) -> None:
        """Log message with trading context."""
        extra = {
            'user_id': user_id,
            'strategy_id': strategy_id,
            'order_id': order_id,
            'symbol': symbol,
        }
        extra.update(kwargs)

        # Filter out None values
        extra = {k: v for k, v in extra.items() if v is not None}

        record = self._logger.makeRecord(
            self._logger.name,
            level,
            '',
            0,
            message,
            (),
            None,
        )
        record.extra_data = extra
        self._logger.handle(record)

    def order_placed(
        self,
        user_id: int,
        strategy_id: str,
        order_id: str,
        symbol: str,
        side: str,
        size: float,
        price: Optional[float] = None,
        order_type: str = 'market',
    ) -> None:
        """Log order placement."""
        self._log_with_context(
            logging.INFO,
            f"Order placed: {side} {size} {symbol}",
            user_id=user_id,
            strategy_id=strategy_id,
            order_id=order_id,
            symbol=symbol,
            side=side,
            size=size,
            price=price,
            order_type=order_type,
        )

    def order_filled(
        self,
        user_id: int,
        strategy_id: str,
        order_id: str,
        symbol: str,
        side: str,
        size: float,
        price: float,
        commission: float = 0.0,
    ) -> None:
        """Log order fill."""
        self._log_with_context(
            logging.INFO,
            f"Order filled: {side} {size} {symbol} @ {price}",
            user_id=user_id,
            strategy_id=strategy_id,
            order_id=order_id,
            symbol=symbol,
            side=side,
            size=size,
            fill_price=price,
            commission=commission,
        )

    def order_cancelled(
        self,
        user_id: int,
        strategy_id: str,
        order_id: str,
        reason: Optional[str] = None,
    ) -> None:
        """Log order cancellation."""
        self._log_with_context(
            logging.INFO,
            f"Order cancelled: {order_id}",
            user_id=user_id,
            strategy_id=strategy_id,
            order_id=order_id,
            cancel_reason=reason,
        )

    def strategy_started(
        self,
        user_id: int,
        strategy_id: str,
        strategy_name: str,
        mode: str,
    ) -> None:
        """Log strategy start."""
        self._log_with_context(
            logging.INFO,
            f"Strategy started: {strategy_name} ({mode} mode)",
            user_id=user_id,
            strategy_id=strategy_id,
            strategy_name=strategy_name,
            mode=mode,
        )

    def strategy_stopped(
        self,
        user_id: int,
        strategy_id: str,
        reason: Optional[str] = None,
    ) -> None:
        """Log strategy stop."""
        self._log_with_context(
            logging.INFO,
            f"Strategy stopped: {strategy_id}",
            user_id=user_id,
            strategy_id=strategy_id,
            stop_reason=reason,
        )

    def error(
        self,
        message: str,
        user_id: Optional[int] = None,
        strategy_id: Optional[str] = None,
        error_type: Optional[str] = None,
        **kwargs
    ) -> None:
        """Log error."""
        self._log_with_context(
            logging.ERROR,
            message,
            user_id=user_id,
            strategy_id=strategy_id,
            error_type=error_type,
            **kwargs
        )


def get_trading_logger(name: str) -> TradingLogger:
    """
    Get a trading-specific logger.

    :param name: Logger name.
    :return: TradingLogger instance.
    """
    return TradingLogger(logging.getLogger(name))
