"""
Size Classifier - Advanced whale trade classification system

This module provides sophisticated classification of whale trades based on size,
urgency, and trading patterns to enable intelligent following strategies.
"""

import logging
from typing import Dict, Optional, List, Tuple
from datetime import datetime, timedelta
from dataclasses import dataclass, field

from ..core_types import WhaleTier, EnhancedTrade, WhaleBotConfig, TradeUrgency

logger = logging.getLogger(__name__)

@dataclass
class SizeClassification:
    """Classification result for a whale trade"""
    tier: WhaleTier
    urgency: TradeUrgency
    urgency_score: float  # 0.0 to 1.0
    size_score: float  # Normalized size score
    total_score: float  # Combined score for decision making
    classification_time: datetime = field(default_factory=datetime.now)
    
    def __post_init__(self):
        """Validate classification scores"""
        for score_name, score_value in [
            ('urgency_score', self.urgency_score),
            ('size_score', self.size_score), 
            ('total_score', self.total_score)
        ]:
            if not 0.0 <= score_value <= 1.0:
                raise ValueError(f"{score_name} must be between 0.0 and 1.0, got {score_value}")

class SizeClassifier:
    """
    Advanced size classifier for whale trades.
    
    This classifier provides:
    - Tier classification based on size thresholds
    - Urgency assessment based on market conditions
    - Historical context analysis
    - Adaptive scoring system
    """
    
    def __init__(self, config: WhaleBotConfig):
        """
        Initialize the size classifier.
        
        Args:
            config: Whale bot configuration with thresholds and parameters
        """
        self.config = config
        self.trade_history: List[EnhancedTrade] = []
        self.size_thresholds = {
            WhaleTier.MINNOW: config.min_whale_threshold * 0.1,      # $100K
            WhaleTier.DOLPHIN: config.min_whale_threshold,            # $1M  
            WhaleTier.WHALE: config.mega_whale_threshold,             # $5M
            WhaleTier.MEGA_WHALE: config.giant_whale_threshold,       # $10M
            WhaleTier.GIANT_WHALE: float('inf')                      # Unlimited
        }
        self._logger = logger
        
        # Market context tracking
        self.last_hour_trades: Dict[str, List[EnhancedTrade]] = {}
        self.coin_volumes: Dict[str, float] = {}  # Track coin volumes for context
        
    def classify_trade(self, trade: EnhancedTrade) -> SizeClassification:
        """
        Classify a whale trade based on size, urgency, and market context.
        
        Args:
            trade: Enhanced trade to classify
            
        Returns:
            SizeClassification: Complete classification with scores
        """
        try:
            # Add to history for context
            self._add_to_history(trade)
            
            # Basic size classification
            tier = self._classify_tier(trade.size_usd)
            size_score = self._calculate_size_score(trade.size_usd, tier)
            
            # Urgency assessment
            urgency, urgency_score = self._assess_urgency(trade)
            
            # Context-aware adjustments
            context_multiplier = self._calculate_context_multiplier(trade)
            
            # Calculate total score
            total_score = (size_score * 0.6 + urgency_score * 0.4) * context_multiplier
            
            classification = SizeClassification(
                tier=tier,
                urgency=urgency,
                urgency_score=urgency_score,
                size_score=size_score,
                total_score=min(total_score, 1.0)  # Cap at 1.0
            )
            
            self._logger.debug(f"Classified trade {trade.coin} ${trade.size_usd:,.0f}: "
                              f"{tier.value}, urgency: {urgency}, score: {total_score:.3f}")
            
            return classification
            
        except Exception as e:
            self._logger.error(f"Error classifying trade: {e}")
            # Return safe default classification
            return SizeClassification(
                tier=WhaleTier.MINNOW,
                urgency=TradeUrgency.MEDIUM,
                urgency_score=0.5,
                size_score=0.1,
                total_score=0.2
            )
    
    def _classify_tier(self, size_usd: float) -> WhaleTier:
        """Classify trade size into whale tier"""
        if size_usd < self.size_thresholds[WhaleTier.MINNOW]:
            return WhaleTier.MINNOW
        elif size_usd < self.size_thresholds[WhaleTier.DOLPHIN]:
            return WhaleTier.DOLPHIN
        elif size_usd < self.size_thresholds[WhaleTier.WHALE]:
            return WhaleTier.WHALE
        elif size_usd < self.size_thresholds[WhaleTier.MEGA_WHALE]:
            return WhaleTier.MEGA_WHALE
        else:
            return WhaleTier.GIANT_WHALE
    
    def _calculate_size_score(self, size_usd: float, tier: WhaleTier) -> float:
        """
        Calculate normalized size score from 0.0 to 1.0
        
        Args:
            size_usd: Trade size in USD
            tier: Classified tier
            
        Returns:
            float: Normalized score
        """
        # Base score from tier
        tier_scores = {
            WhaleTier.MINNOW: 0.1,
            WhaleTier.DOLPHIN: 0.4,
            WhaleTier.WHALE: 0.7,
            WhaleTier.MEGA_WHALE: 0.85,
            WhaleTier.GIANT_WHALE: 1.0
        }
        
        base_score = tier_scores[tier]
        
        # Extra scoring for very large trades within tier
        if tier == WhaleTier.GIANT_WHALE and size_usd > 50_000_000:  # >$50M
            base_score = 1.0
        elif tier == WhaleTier.MEGA_WHALE and size_usd > 15_000_000:  # >$15M
            base_score = 0.95
        elif tier == WhaleTier.WHALE and size_usd > 8_000_000:  # >$8M
            base_score = 0.8
            
        return base_score
    
    def _assess_urgency(self, trade: EnhancedTrade) -> Tuple[TradeUrgency, float]:
        """
        Assess urgency level and score based on multiple factors.
        
        Args:
            trade: Trade to assess
            
        Returns:
            Tuple[TradeUrgency, float]: Urgency level and score (0.0-1.0)
        """
        urgency_factors = []
        
        # Size factor - larger trades are more urgent
        size_factor = min(trade.size_usd / self.config.mega_whale_threshold, 1.0)
        urgency_factors.append(size_factor * 0.3)
        
        # Velocity factor - recent high-volume trades increase urgency
        velocity_factor = self._calculate_velocity_factor(trade.coin)
        urgency_factors.append(velocity_factor * 0.25)
        
        # Market context factor - unusual market conditions
        context_factor = self._calculate_market_context_factor(trade)
        urgency_factors.append(context_factor * 0.25)
        
        # Timing factor - certain times are more urgent
        timing_factor = self._calculate_timing_factor()
        urgency_factors.append(timing_factor * 0.2)
        
        # Combine factors
        total_score = sum(urgency_factors)
        total_score = min(total_score, 1.0)
        
        # Map to urgency levels
        if total_score >= 0.8:
            urgency = TradeUrgency.CRITICAL
        elif total_score >= 0.6:
            urgency = TradeUrgency.HIGH
        elif total_score >= 0.4:
            urgency = TradeUrgency.MEDIUM
        else:
            urgency = TradeUrgency.LOW
            
        return urgency, total_score
    
    def _calculate_velocity_factor(self, coin: str) -> float:
        """Calculate velocity factor based on recent trading activity"""
        try:
            now = datetime.now()
            recent_trades = [
                t for t in self.trade_history 
                if t.coin == coin and (now - t.timestamp).total_seconds() < 300  # 5 minutes
            ]
            
            if not recent_trades:
                return 0.0
                
            # Calculate velocity based on number and size of recent trades
            total_volume = sum(t.size_usd for t in recent_trades)
            trade_count = len(recent_trades)
            
            # Higher volume + higher count = higher velocity
            volume_factor = min(total_volume / 10_000_000, 1.0)  # $10M threshold
            count_factor = min(trade_count / 5, 1.0)  # 5 trades threshold
            
            return (volume_factor * 0.7 + count_factor * 0.3)
            
        except Exception as e:
            self._logger.debug(f"Error calculating velocity factor: {e}")
            return 0.0
    
    def _calculate_market_context_factor(self, trade: EnhancedTrade) -> float:
        """Calculate market context factor"""
        try:
            # Check if this is unusual activity for the coin
            coin_trades = [t for t in self.trade_history if t.coin == trade.coin]
            
            if len(coin_trades) < 5:
                return 0.5  # Neutral if insufficient data
                
            # Calculate average trade size for this coin
            avg_size = sum(t.size_usd for t in coin_trades[-20:]) / len(coin_trades[-20:])
            if avg_size == 0:
                return 0.5
                
            # Compare current trade size to average
            size_ratio = trade.size_usd / avg_size
            
            # If trade is 3x larger than average, high urgency
            if size_ratio >= 5.0:
                return 0.9
            elif size_ratio >= 3.0:
                return 0.7
            elif size_ratio >= 1.5:
                return 0.5
            else:
                return 0.3
                
        except Exception as e:
            self._logger.debug(f"Error calculating market context factor: {e}")
            return 0.5
    
    def _calculate_timing_factor(self) -> float:
        """Calculate timing factor based on current market conditions"""
        try:
            now = datetime.now()
            hour = now.hour
            
            # High activity periods (market hours)
            if 9 <= hour <= 16:  # Standard trading hours
                return 0.8
            elif 16 <= hour <= 20:  # Extended hours
                return 0.7
            elif 20 <= hour <= 23 or 0 <= hour <= 2:  # Asian hours
                return 0.6
            else:  # Low activity hours
                return 0.4
                
        except Exception as e:
            self._logger.debug(f"Error calculating timing factor: {e}")
            return 0.5
    
    def _calculate_context_multiplier(self, trade: EnhancedTrade) -> float:
        """Calculate context-based multiplier for total score"""
        try:
            # Market volatility context
            volatility_factor = self._assess_volatility(trade.coin)
            
            # Correlation context (trades across multiple coins simultaneously)
            correlation_factor = self._assess_correlation(trade.timestamp)
            
            # Combine factors
            multiplier = (volatility_factor * 0.6 + correlation_factor * 0.4)
            return min(max(multiplier, 0.5), 1.5)  # Keep between 0.5x and 1.5x
            
        except Exception as e:
            self._logger.debug(f"Error calculating context multiplier: {e}")
            return 1.0
    
    def _assess_volatility(self, coin: str) -> float:
        """Assess market volatility for the coin"""
        try:
            # Simple volatility assessment based on recent price movements
            # This would be enhanced with actual market data
            return 1.0  # Default neutral
        except:
            return 1.0
    
    def _assess_correlation(self, timestamp: datetime) -> float:
        """Assess if there are correlated trades happening"""
        try:
            # Check for trades within a short time window (30 seconds)
            window_start = timestamp - timedelta(seconds=30)
            correlated_trades = [
                t for t in self.trade_history 
                if t.timestamp >= window_start and t.timestamp <= timestamp
            ]
            
            # More correlated trades = higher correlation factor
            if len(correlated_trades) >= 3:
                return 1.2
            elif len(correlated_trades) >= 2:
                return 1.1
            else:
                return 1.0
                
        except Exception as e:
            self._logger.debug(f"Error assessing correlation: {e}")
            return 1.0
    
    def _add_to_history(self, trade: EnhancedTrade):
        """Add trade to internal history for context"""
        try:
            self.trade_history.append(trade)
            
            # Keep only recent trades (last 1000 trades)
            if len(self.trade_history) > 1000:
                self.trade_history = self.trade_history[-1000:]
                
            # Update per-coin tracking
            now = datetime.now()
            if trade.coin not in self.last_hour_trades:
                self.last_hour_trades[trade.coin] = []
                
            self.last_hour_trades[trade.coin].append(trade)
            
            # Clean old entries
            cutoff_time = now - timedelta(hours=1)
            self.last_hour_trades[trade.coin] = [
                t for t in self.last_hour_trades[trade.coin] 
                if t.timestamp > cutoff_time
            ]
            
        except Exception as e:
            self._logger.error(f"Error adding to history: {e}")
    
    def get_classification_summary(self) -> Dict:
        """Get summary of recent classifications"""
        try:
            if not self.trade_history:
                return {"message": "No trades classified yet"}
            
            recent_trades = self.trade_history[-100:]  # Last 100 trades
            tier_counts = {}
            urgency_counts = {}
            
            for trade in recent_trades:
                # This would need classification - for now return basic stats
                tier = self._classify_tier(trade.size_usd)
                tier_counts[tier.value] = tier_counts.get(tier.value, 0) + 1
            
            return {
                "total_trades": len(self.trade_history),
                "recent_trades": len(recent_trades),
                "tier_distribution": tier_counts,
                "coins_tracked": list(self.last_hour_trades.keys()),
                "avg_daily_trades": len(self.trade_history) / max(1, len(set(
                    t.timestamp.date() for t in self.trade_history
                )))
            }
            
        except Exception as e:
            self._logger.error(f"Error generating classification summary: {e}")
            return {"error": str(e)}
    
    def reset_history(self):
        """Reset trade history (useful for testing or starting fresh)"""
        self.trade_history.clear()
        self.last_hour_trades.clear()
        self.coin_volumes.clear()
        self._logger.info("Trade history reset")
    
    def classify_size(self, size_usd: float) -> WhaleTier:
        """
        Convenient method to classify trade size only (without full trade object).
        
        Args:
            size_usd: Trade size in USD
            
        Returns:
            WhaleTier: The classified tier
        """
        return self._classify_tier(size_usd)