"""
Unit Test for NEW Skip Logic in BetRecommender
==============================================
Run with: python ai-engine/tests/test_skip_logic.py
"""

import os
import sys
import unittest
from dataclasses import dataclass
from typing import Optional

# Add paths
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))

from core.calculators.bet_recommender import BetRecommender, RecommendationResult, MarketPredictionDTO
from core.calculators.risk_assessor import RiskAnalysis
from core.calculators.match_result_calculator import MatchResultPrediction
from core.calculators.over_under_calculator import OverUnderPrediction
from config.config_loader import get_config

@dataclass
class DummyContext:
    """Minimal mock for CalculationContext"""
    odds_data: dict

class TestSkipLogic(unittest.TestCase):

    def setUp(self):
        # Mock config to pass into BetRecommender
        self.mock_config = {
            "recommendations.market_weights": {"MS": 1.0, "ÇŞ": 0.9, "BTTS": 0.9, "2.5 Üst/Alt": 0.9},
            "recommendations.safe_markets": ["ÇŞ", "1.5 Üst/Alt"],
            "recommendations.market_accuracy": {"MS": 65, "ÇŞ": 75, "BTTS": 60, "2.5 Üst/Alt": 65},
            "recommendations.baseline_accuracy": 65.0,
            "recommendations.confidence_threshold": 60,
            "recommendations.value_confidence_min": 45,
            "recommendations.value_confidence_max": 60,
            "recommendations.value_edge_margin": 0.03,
            "recommendations.value_upgrade_edge": 5.0,
            "recommendations.risk_safe_boost": 1.2,
            "recommendations.risk_ms_penalty_high": 0.5,
            "recommendations.risk_other_penalty": 0.7,
            "recommendations.risk_ms_penalty_medium": 0.8,
        }
        self.recommender = BetRecommender(self.mock_config)

    def _make_risk(self, level="MEDIUM", is_surprise=False):
        return RiskAnalysis(risk_level=level, is_surprise_risk=is_surprise, risk_score=0.5)

    def _make_ms_pred(self, pick, conf):
        # pick: "1", "X", "2"
        probs = {"1": {"ms_home_prob": 0.5, "ms_draw_prob": 0.3, "ms_away_prob": 0.2},
                 "X": {"ms_home_prob": 0.2, "ms_draw_prob": 0.5, "ms_away_prob": 0.3},
                 "2": {"ms_home_prob": 0.2, "ms_draw_prob": 0.3, "ms_away_prob": 0.5}}
        p = probs.get(pick, probs["1"])
        return MatchResultPrediction(
            ms_pick=pick, ms_confidence=conf,
            dc_pick="1X", dc_confidence=0,
            dc_1x_prob=0.7, dc_x2_prob=0.7, dc_12_prob=0.7,
            **p
        )

    def _make_ou_pred(self):
        return OverUnderPrediction(
            ou25_pick="2.5 Üst", ou25_confidence=50.0,
            over_25_prob=0.55, under_25_prob=0.45,
            
            btts_pick="Var", btts_confidence=50.0,
            btts_yes_prob=0.55, btts_no_prob=0.45,
            
            ou15_pick="1.5 Üst", ou15_confidence=60.0, over_15_prob=0.7, under_15_prob=0.3,
            ou35_pick="3.5 Alt", ou35_confidence=50.0, over_35_prob=0.3, under_35_prob=0.7
        )

    def test_low_confidence_should_skip(self):
        """Confidence < 45% should be SKIPPED"""
        ms_pred = self._make_ms_pred(pick="2", conf=40.0)
        ou_pred = self._make_ou_pred()
        risk = self._make_risk("MEDIUM")
        ctx = DummyContext(odds_data={"ms_2": 2.5})

        res = self.recommender.calculate(ctx, ms_pred, ou_pred, risk)
        
        # Check if MS bet is skipped
        ms_bet = next((b for b in res.skipped_bets if b.market_type == "MS"), None)
        self.assertIsNotNone(ms_bet, "MS bet with 40% conf should be skipped!")
        self.assertTrue(ms_bet.is_skip)

    def test_good_confidence_should_recommend(self):
        """Confidence > 60% and Good Odds should be RECOMMENDED"""
        ms_pred = self._make_ms_pred(pick="1", conf=70.0)
        ou_pred = self._make_ou_pred()
        risk = self._make_risk("MEDIUM")
        # Odds 1.80 for 70% prob = Good Value (Need real odds for MS to pass)
        ctx = DummyContext(odds_data={"ms_1": 1.80, "ou15_o": 1.50}) # Added ou15 odds

        res = self.recommender.calculate(ctx, ms_pred, ou_pred, risk)

        # Check if ANY bet is recommended (doesn't have to be MS, but usually is)
        self.assertGreater(len(res.recommended_bets), 0, "At least one bet should be recommended!")
        # Check that MS bet is NOT skipped
        ms_bet = next((b for b in res.recommended_bets if b.market_type == "MS"), None)
        if ms_bet:
            self.assertFalse(ms_bet.is_skip)

    def test_negative_edge_should_skip(self):
        """Even with high confidence, if Odds are too low (Bad Value), SKIP"""
        ms_pred = self._make_ms_pred(pick="1", conf=70.0) # 70% prob
        ou_pred = self._make_ou_pred()
        risk = self._make_risk("MEDIUM")
        # Odds 1.10 -> Implied 90%. Our prob is 70%. Edge is -20% -> SKIP
        ctx = DummyContext(odds_data={"ms_1": 1.10})

        res = self.recommender.calculate(ctx, ms_pred, ou_pred, risk)

        ms_bet = next((b for b in res.skipped_bets if b.market_type == "MS"), None)
        self.assertIsNotNone(ms_bet, "MS bet with terrible odds (Negative Edge) should be skipped!")
        self.assertTrue(ms_bet.is_skip)

    def test_no_bets_recommendation(self):
        """If all bets are low confidence, best_bet should be None"""
        ms_pred = self._make_ms_pred(pick="1", conf=30.0) # Very low conf
        ou_pred = self._make_ou_pred()
        # Reset ALL OU confs to low
        ou_pred.ou25_confidence = 30.0
        ou_pred.btts_confidence = 30.0
        ou_pred.ou15_confidence = 30.0 # This was 60 in setUp, causing the fail!
        ou_pred.ou35_confidence = 30.0
        
        risk = self._make_risk("MEDIUM")
        ctx = DummyContext(odds_data={"ms_1": 2.0})

        res = self.recommender.calculate(ctx, ms_pred, ou_pred, risk)

        self.assertIsNone(res.best_bet, "If everything is skipped, there should be no best_bet.")
        self.assertEqual(len(res.recommended_bets), 0, "No bets should be recommended!")

if __name__ == '__main__':
    print("🧪 Running Skip Logic Unit Tests...")
    print("="*50)
    unittest.main(verbosity=2)
