"""
Value Betting Calculator
Expected Value (EV) ve stake önerileri hesaplar.
"""

from typing import Dict, Optional
from dataclasses import dataclass


@dataclass
class ValueBet:
    """Value bet analiz sonucu"""
    bet_type: str  # MS_1, AU25_Üst, KG_Var
    my_probability: float  # Bizim tahminimiz
    market_odds: float  # Bahis oranı
    implied_probability: float  # Oranın ima ettiği olasılık
    edge: float  # Fark (benim tahmin - implied)
    expected_value: float  # EV = (prob × odds) - 1
    is_value: bool  # EV > threshold mı?
    kelly_fraction: float  # Kelly stake oranı
    confidence_tier: str  # "banker", "strong", "value", "skip"
    
    def to_dict(self) -> Dict:
        return {
            'bet_type': self.bet_type,
            'my_probability': round(self.my_probability, 4),
            'market_odds': self.market_odds,
            'implied_probability': round(self.implied_probability, 4),
            'edge': round(self.edge, 4),
            'expected_value': round(self.expected_value, 4),
            'is_value': self.is_value,
            'kelly_fraction': round(self.kelly_fraction, 4),
            'confidence_tier': self.confidence_tier,
        }


class ValueCalculator:
    """
    Value Betting Calculator
    
    Tahminleri oranlarla karşılaştırarak EV hesaplar.
    """
    
    # Eşikler
    MIN_EDGE_FOR_VALUE = 0.05  # Minimum %5 edge
    MIN_EDGE_FOR_STRONG = 0.10  # %10+ edge = strong value
    MIN_EDGE_FOR_BANKER = 0.15  # %15+ edge = banker
    
    KELLY_FRACTION = 0.25  # 1/4 Kelly (güvenli)
    MAX_STAKE_PERCENT = 0.10  # Maksimum bank'ın %10'u
    
    def __init__(self):
        pass
    
    def calculate_implied_probability(self, odds: float) -> float:
        """Bahis oranından implied probability hesapla"""
        if odds <= 1:
            return 1.0
        return 1 / odds
    
    def calculate_ev(self, probability: float, odds: float) -> float:
        """
        Expected Value hesapla.
        
        EV = (Probability × Odds) - 1
        
        Pozitif EV = uzun vadede kar
        Negatif EV = uzun vadede zarar
        """
        return (probability * odds) - 1
    
    def calculate_kelly_stake(self, probability: float, odds: float) -> float:
        """
        Kelly Criterion stake hesapla.
        
        Kelly = (p × b - q) / b
        Burada:
        - p = kazanma olasılığı
        - q = kaybetme olasılığı (1 - p)
        - b = odds - 1 (net kar)
        """
        if odds <= 1:
            return 0
        
        b = odds - 1
        p = probability
        q = 1 - p
        
        kelly = (p * b - q) / b
        
        # Negatif veya çok yüksek değerleri sınırla
        kelly = max(0, min(kelly, self.MAX_STAKE_PERCENT))
        
        # Fractional Kelly (daha güvenli)
        return kelly * self.KELLY_FRACTION
    
    def analyze_bet(self, bet_type: str, my_probability: float, 
                    market_odds: float) -> ValueBet:
        """
        Tek bir bahis için value analizi yap.
        
        Args:
            bet_type: Bahis türü (MS_1, AU25_Üst, KG_Var vb.)
            my_probability: Bizim tahminimiz (0-1 arası)
            market_odds: Bahis oranı
        
        Returns:
            ValueBet: Analiz sonucu
        """
        if market_odds <= 1:
            return ValueBet(
                bet_type=bet_type,
                my_probability=my_probability,
                market_odds=market_odds,
                implied_probability=1.0,
                edge=0,
                expected_value=-1,
                is_value=False,
                kelly_fraction=0,
                confidence_tier="skip"
            )
        
        implied = self.calculate_implied_probability(market_odds)
        edge = my_probability - implied
        ev = self.calculate_ev(my_probability, market_odds)
        kelly = self.calculate_kelly_stake(my_probability, market_odds)
        
        # Tier belirleme
        if edge >= self.MIN_EDGE_FOR_BANKER and my_probability >= 0.70:
            tier = "banker"
        elif edge >= self.MIN_EDGE_FOR_STRONG:
            tier = "strong"
        elif edge >= self.MIN_EDGE_FOR_VALUE:
            tier = "value"
        else:
            tier = "skip"
        
        return ValueBet(
            bet_type=bet_type,
            my_probability=my_probability,
            market_odds=market_odds,
            implied_probability=implied,
            edge=edge,
            expected_value=ev,
            is_value=edge >= self.MIN_EDGE_FOR_VALUE,
            kelly_fraction=kelly,
            confidence_tier=tier
        )
    
    def analyze_match_predictions(self, predictions: Dict[str, float],
                                  odds: Dict[str, float]) -> Dict[str, ValueBet]:
        """
        Maç için tüm tahminleri analiz et.
        
        Args:
            predictions: Tahminler {'MS_1': 0.55, 'MS_X': 0.25, ...}
            odds: Oranlar {'MS_1': 1.80, 'MS_X': 3.50, ...}
        
        Returns:
            Dict[str, ValueBet]: Her bahis için value analizi
        """
        results = {}
        
        for bet_type, probability in predictions.items():
            if bet_type in odds and odds[bet_type] > 1:
                results[bet_type] = self.analyze_bet(
                    bet_type=bet_type,
                    my_probability=probability,
                    market_odds=odds[bet_type]
                )
        
        return results
    
    def get_best_value_bets(self, value_bets: Dict[str, ValueBet], 
                            top_n: int = 3) -> list:
        """En iyi value bet'leri döndür"""
        valid_bets = [vb for vb in value_bets.values() if vb.is_value]
        sorted_bets = sorted(valid_bets, key=lambda x: x.expected_value, reverse=True)
        return sorted_bets[:top_n]
    
    def calculate_stake(self, value_bet: ValueBet, bankroll: float,
                        use_kelly: bool = True) -> float:
        """
        Önerilen stake miktarını hesapla.
        
        Args:
            value_bet: Value bet analizi
            bankroll: Toplam bütçe
            use_kelly: Kelly criterion kullan mı?
        
        Returns:
            float: Önerilen stake miktarı
        """
        if not value_bet.is_value:
            return 0
        
        if use_kelly:
            return bankroll * value_bet.kelly_fraction
        else:
            # Tier bazlı sabit stake
            tier_stakes = {
                "banker": 0.05,
                "strong": 0.03,
                "value": 0.02,
                "skip": 0
            }
            return bankroll * tier_stakes.get(value_bet.confidence_tier, 0)


# Singleton
_calculator = None

def get_value_calculator() -> ValueCalculator:
    global _calculator
    if _calculator is None:
        _calculator = ValueCalculator()
    return _calculator


if __name__ == "__main__":
    calc = get_value_calculator()
    
    print("\n🧪 Value Calculator Test")
    print("=" * 50)
    
    # Test senaryoları
    test_cases = [
        {"bet": "MS_1", "prob": 0.70, "odds": 1.60},  # High prob, low odds
        {"bet": "MS_1", "prob": 0.55, "odds": 1.90},  # Medium prob, good odds
        {"bet": "MS_1", "prob": 0.60, "odds": 2.10},  # VALUE!
        {"bet": "AU25_Üst", "prob": 0.65, "odds": 1.85},  # VALUE!
        {"bet": "KG_Var", "prob": 0.50, "odds": 1.70},  # No value
    ]
    
    for tc in test_cases:
        result = calc.analyze_bet(tc["bet"], tc["prob"], tc["odds"])
        
        status_emoji = "✅" if result.is_value else "❌"
        tier_emoji = {"banker": "🎯", "strong": "💪", "value": "✓", "skip": "⏭️"}
        
        print(f"\n{status_emoji} {tc['bet']}")
        print(f"   Tahmin: {tc['prob']:.0%} | Oran: {tc['odds']:.2f} | Implied: {result.implied_probability:.0%}")
        print(f"   Edge: {result.edge:+.1%} | EV: {result.expected_value:+.1%}")
        print(f"   Tier: {tier_emoji.get(result.confidence_tier, '')} {result.confidence_tier.upper()}")
        print(f"   Kelly Stake: {result.kelly_fraction:.2%} of bankroll")
        
        if result.is_value:
            stake = calc.calculate_stake(result, 1000)
            print(f"   💰 Önerilen Stake (1000 TL bank): {stake:.2f} TL")
