"""Custom exception hierarchy for ICT ML Trading System."""

from typing import Any, Dict, Optional


class ICTTradingException(Exception):
    """Base exception for all ICT Trading System errors."""

    def __init__(
        self,
        message: str,
        error_code: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ):
        """
        Initialize exception.

        Args:
            message: Error message
            error_code: Optional error code for programmatic handling
            context: Optional context dictionary with additional information
        """
        super().__init__(message)
        self.message = message
        self.error_code = error_code
        self.context = context or {}

    def __str__(self) -> str:
        """Return formatted error message."""
        if self.error_code:
            return f"[{self.error_code}] {self.message}"
        return self.message

    def to_dict(self) -> Dict[str, Any]:
        """Convert exception to dictionary for logging."""
        return {
            "error_type": self.__class__.__name__,
            "error_code": self.error_code,
            "message": self.message,
            "context": self.context,
        }


class DataError(ICTTradingException):
    """Raised when data loading, validation, or processing fails."""

    def __init__(
        self,
        message: str,
        error_code: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ):
        super().__init__(message, error_code or "DATA_ERROR", context)


class DetectorError(ICTTradingException):
    """Raised when pattern detection fails."""

    def __init__(
        self,
        message: str,
        error_code: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ):
        super().__init__(message, error_code or "DETECTOR_ERROR", context)


class ModelError(ICTTradingException):
    """Raised when ML model training, inference, or evaluation fails."""

    def __init__(
        self,
        message: str,
        error_code: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ):
        super().__init__(message, error_code or "MODEL_ERROR", context)


class ConfigurationError(ICTTradingException):
    """Raised when configuration is invalid or missing."""

    def __init__(
        self,
        message: str,
        error_code: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ):
        super().__init__(message, error_code or "CONFIG_ERROR", context)


class TradingError(ICTTradingException):
    """Raised when trading execution fails."""

    def __init__(
        self,
        message: str,
        error_code: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ):
        super().__init__(message, error_code or "TRADING_ERROR", context)


class ValidationError(ICTTradingException):
    """Raised when validation fails."""

    def __init__(
        self,
        message: str,
        error_code: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ):
        super().__init__(message, error_code or "VALIDATION_ERROR", context)

