from dataclasses import dataclass
from datetime import datetime
from typing import Optional, Literal, Callable, Dict, Any

TradeType = Literal["FILL", "ORDER_PLACED", "ORDER_CANCELLED"]
TradeSide = Literal["BUY", "SELL"]

@dataclass
class Trade:
    timestamp: datetime
    address: str
    coin: str
    side: TradeSide
    size: float
    price: float
    trade_type: TradeType
    direction: Optional[str] = None
    tx_hash: Optional[str] = None
    fee: Optional[float] = None
    fee_token: Optional[str] = None
    start_position: Optional[float] = None
    closed_pnl: Optional[float] = None
    order_id: Optional[int] = None
    leverage: Optional[float] = None  # Leverage used for this trade

    def __post_init__(self):
        """Validate trade data after initialization"""
        if self.side not in ("BUY", "SELL"):
            raise ValueError(f"Invalid side: {self.side}. Must be 'BUY' or 'SELL'")
        
        if self.trade_type not in ("FILL", "ORDER_PLACED", "ORDER_CANCELLED"):
            raise ValueError(
                f"Invalid trade_type: {self.trade_type}. "
                "Must be 'FILL', 'ORDER_PLACED', or 'ORDER_CANCELLED'"
            )

@dataclass
class WhaleConfig:
    """Configuration for whale monitoring"""
    min_trade_size_usd: float = 100000  # Minimum trade size in USD to consider as whale trade
    alert_cooldown_seconds: int = 60    # Cooldown period between alerts for same address
    max_alerts_per_hour: int = 50       # Maximum alerts per hour per address
    enable_real_time_monitoring: bool = True
    enable_persistent_tracking: bool = False
    tracking_duration_hours: int = 24   # How long to track addresses after whale activity
    
    # Risk management
    max_position_risk_per_trade: float = 0.02  # Max 2% portfolio risk per trade
    max_total_exposure: float = 0.10           # Max 10% total portfolio exposure
    
    # Notification settings
    enable_telegram: bool = False
    enable_discord: bool = False
    alert_threshold: Literal["MINNOW", "DOLPHIN", "WHALE", "MEGA_WHALE", "GIANT_WHALE"] = "WHALE"
    
    # Database settings
    database_path: str = "whale_trades.db"
    enable_persistence: bool = True
    
    # API settings
    api_timeout: int = 30
    rate_limit_requests: int = 100
    rate_limit_window: int = 60  # seconds

@dataclass
class TradingPair:
    """Trading pair configuration"""
    symbol: str
    base_asset: str
    quote_asset: str
    is_active: bool = True
    min_order_size: Optional[float] = None
    max_order_size: Optional[float] = None
    price_precision: Optional[int] = None
    quantity_precision: Optional[int] = None
    
    @property
    def pair_id(self) -> str:
        """Get standardized pair ID"""
        return f"{self.base_asset}/{self.quote_asset}"
    
    @property
    def display_name(self) -> str:
        """Get display name for the pair"""
        return f"{self.base_asset}/{self.quote_asset}"

@dataclass
class WhaleAlert:
    """Whale trade alert data"""
    alert_id: str
    timestamp: datetime
    trade: Trade
    alert_type: Literal["WHALE_DETECTED", "LARGE_POSITION", "UNUSUAL_ACTIVITY", "FOLLOW_OPPORTUNITY"]
    severity: Literal["LOW", "MEDIUM", "HIGH", "CRITICAL"]
    message: str
    metadata: Optional[Dict[str, Any]] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert alert to dictionary"""
        return {
            "alert_id": self.alert_id,
            "timestamp": self.timestamp.isoformat(),
            "trade": {
                "timestamp": self.trade.timestamp.isoformat(),
                "address": self.trade.address,
                "coin": self.trade.coin,
                "side": self.trade.side,
                "size": self.trade.size,
                "price": self.trade.price,
                "trade_type": self.trade.trade_type
            },
            "alert_type": self.alert_type,
            "severity": self.severity,
            "message": self.message,
            "metadata": self.metadata or {}
        }

TradeCallback = Callable[[Trade], None]
