"""
Player Predictor Engine - V20 Ensemble Component
Analyzes squad quality, key players, and missing player impact.

Weight: 25% in ensemble
"""

import os
import sys
from typing import Dict, Optional, List
from dataclasses import dataclass

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))

from features.squad_analysis_engine import get_squad_analysis_engine
from features.sidelined_analyzer import get_sidelined_analyzer


@dataclass
class PlayerPrediction:
    """Player engine prediction output."""
    home_squad_quality: float = 50.0  # 0-100
    away_squad_quality: float = 50.0
    squad_diff: float = 0.0  # -100 to +100
    home_key_players: int = 0
    away_key_players: int = 0
    home_missing_impact: float = 0.0  # 0-1, how much weaker due to missing players
    away_missing_impact: float = 0.0
    home_goals_form: int = 0  # Goals in last 5 matches
    away_goals_form: int = 0
    lineup_available: bool = False
    confidence: float = 0.0
    
    def to_dict(self) -> dict:
        return {
            "home_squad_quality": round(self.home_squad_quality, 1),
            "away_squad_quality": round(self.away_squad_quality, 1),
            "squad_diff": round(self.squad_diff, 1),
            "home_key_players": self.home_key_players,
            "away_key_players": self.away_key_players,
            "home_missing_impact": round(self.home_missing_impact, 2),
            "away_missing_impact": round(self.away_missing_impact, 2),
            "home_goals_form": self.home_goals_form,
            "away_goals_form": self.away_goals_form,
            "lineup_available": self.lineup_available,
            "confidence": round(self.confidence, 1)
        }


class PlayerPredictorEngine:
    """
    Player/Squad-based prediction engine.
    
    Analyzes:
    - Starting 11 quality
    - Key player availability (top scorers)
    - Missing player impact
    - Recent goalscoring form per player
    """
    
    def __init__(self):
        self.squad_engine = get_squad_analysis_engine()
        self.sidelined_analyzer = get_sidelined_analyzer()
        print("✅ PlayerPredictorEngine initialized")
    
    def predict(self,
                match_id: str,
                home_team_id: str,
                away_team_id: str,
                home_lineup: List[str] = None,
                away_lineup: List[str] = None,
                sidelined_data: Dict = None) -> PlayerPrediction:
        """
        Generate player-based prediction.
        
        Args:
            match_id: Match ID for lineup lookup
            home_team_id: Home team ID
            away_team_id: Away team ID
            home_lineup: Optional list of home player IDs
            away_lineup: Optional list of away player IDs
            
        Returns:
            PlayerPrediction with squad analysis
        """
        
        # Get squad features
        if home_lineup and away_lineup:
            # Use provided lineups (for live matches)
            home_analysis = self.squad_engine.analyze_squad_from_list(
                home_lineup, home_team_id
            )
            away_analysis = self.squad_engine.analyze_squad_from_list(
                away_lineup, away_team_id
            )
            lineup_available = True
            # Build features dict from analysis objects
            features = {
                "home_starting_11": home_analysis.starting_count or 11,
                "home_goals_last_5": home_analysis.total_goals_last_5,
                "home_assists_last_5": home_analysis.total_assists_last_5,
                "home_key_players": home_analysis.key_players_count,
                "away_starting_11": away_analysis.starting_count or 11,
                "away_goals_last_5": away_analysis.total_goals_last_5,
                "away_assists_last_5": away_analysis.total_assists_last_5,
                "away_key_players": away_analysis.key_players_count,
            }
        elif match_id:
            # Try to get from database
            try:
                features = self.squad_engine.get_features(
                    match_id, home_team_id, away_team_id
                )
                lineup_available = (
                    features.get("home_starting_11", 0) >= 11 and
                    features.get("away_starting_11", 0) >= 11
                )
            except Exception:
                features = self.squad_engine.get_features_without_match(
                    home_team_id, away_team_id
                )
                lineup_available = False
        else:
            features = self.squad_engine.get_features_without_match(
                home_team_id, away_team_id
            )
            lineup_available = False
        
        # Extract features
        home_goals = features.get("home_goals_last_5", 0)
        away_goals = features.get("away_goals_last_5", 0)
        home_key = features.get("home_key_players", 0)
        away_key = features.get("away_key_players", 0)
        
        # Calculate squad quality (0-100)
        # Based on: goals scored, key players, assists
        home_quality = min(100, 50 + (home_goals * 3) + (home_key * 5) + 
                          features.get("home_assists_last_5", 0) * 2)
        away_quality = min(100, 50 + (away_goals * 3) + (away_key * 5) + 
                          features.get("away_assists_last_5", 0) * 2)
        
        # Squad difference
        squad_diff = home_quality - away_quality
        
        # Missing player impact
        # Priority: sidelined data (position-weighted) > lineup count (basic)
        if sidelined_data:
            home_impact, away_impact = self.sidelined_analyzer.analyze_match(sidelined_data)
            home_missing = home_impact.impact_score
            away_missing = away_impact.impact_score
            sidelined_available = True
        else:
            # Fallback: basic lineup count method
            expected_xi = 11
            actual_home_xi = features.get("home_starting_11", 11)
            actual_away_xi = features.get("away_starting_11", 11)
            home_missing = (expected_xi - actual_home_xi) / expected_xi if actual_home_xi < expected_xi else 0
            away_missing = (expected_xi - actual_away_xi) / expected_xi if actual_away_xi < expected_xi else 0
            sidelined_available = False
        
        # Confidence: more data sources = higher confidence
        confidence = 70.0 if lineup_available else 35.0
        if home_goals + away_goals > 10:
            confidence += 15
        if sidelined_available:
            confidence += self.sidelined_analyzer.config.get("sidelined.confidence_boost", 10)
        if not lineup_available:
            confidence -= 5.0
        
        return PlayerPrediction(
            home_squad_quality=home_quality,
            away_squad_quality=away_quality,
            squad_diff=squad_diff,
            home_key_players=home_key,
            away_key_players=away_key,
            home_missing_impact=home_missing,
            away_missing_impact=away_missing,
            home_goals_form=home_goals,
            away_goals_form=away_goals,
            lineup_available=lineup_available,
            confidence=max(5.0, confidence)
        )
    
    def get_1x2_modifier(self, prediction: PlayerPrediction) -> Dict[str, float]:
        """
        Calculate 1X2 probability modifiers based on squad analysis.
        
        Returns modifiers to apply to base probabilities.
        """
        diff = prediction.squad_diff / 100  # -1 to +1
        
        return {
            "home_modifier": 1.0 + (diff * 0.3),  # Up to +/-30%
            "away_modifier": 1.0 - (diff * 0.3),
            "draw_modifier": 1.0 - abs(diff) * 0.2  # Less draw if big diff
        }


# Singleton
_engine: Optional[PlayerPredictorEngine] = None


def get_player_predictor() -> PlayerPredictorEngine:
    global _engine
    if _engine is None:
        _engine = PlayerPredictorEngine()
    return _engine


if __name__ == "__main__":
    engine = get_player_predictor()
    
    print("\n🧪 Player Predictor Engine Test")
    print("=" * 50)
    
    pred = engine.predict(
        match_id=None,
        home_team_id="test_home",
        away_team_id="test_away"
    )
    
    print(f"\n📊 Prediction:")
    for k, v in pred.to_dict().items():
        print(f"   {k}: {v}")
