from dataclasses import dataclass
import math

from .base_calculator import BaseCalculator, CalculationContext
from .match_result_calculator import MatchResultPrediction


@dataclass
class OtherMarketsPrediction:
    total_corners_pred: float
    corner_pick: str | None

    total_cards_pred: float
    card_pick: str
    cards_over_prob: float
    cards_under_prob: float
    cards_confidence: float

    handicap_pick: str
    handicap_home_prob: float
    handicap_draw_prob: float
    handicap_away_prob: float
    handicap_confidence: float

    odd_even_pick: str
    odd_prob: float
    even_prob: float


class OtherMarketsCalculator(BaseCalculator):
    def calculate(  # type: ignore[override]
        self,
        ctx: CalculationContext,
        ms_result: MatchResultPrediction,
    ) -> OtherMarketsPrediction:
        if "handicap_ms" in ctx.xgboost_preds:
            handicap_payload = ctx.xgboost_preds["handicap_ms"]
            handicap_home_prob = float(handicap_payload.get("h1", 0.33))
            handicap_draw_prob = float(handicap_payload.get("hx", 0.34))
            handicap_away_prob = float(handicap_payload.get("h2", 0.33))
        else:
            xg_diff = ctx.home_xg - ctx.away_xg
            threshold = float(self.config.get("handicap.xg_diff_threshold", 1.2))
            if xg_diff > threshold:
                handicap_home_prob, handicap_draw_prob, handicap_away_prob = 0.58, 0.24, 0.18
            elif xg_diff < -threshold:
                handicap_home_prob, handicap_draw_prob, handicap_away_prob = 0.18, 0.24, 0.58
            else:
                handicap_home_prob, handicap_draw_prob, handicap_away_prob = 0.28, 0.44, 0.28

        handicap_confidence = max(
            handicap_home_prob,
            handicap_draw_prob,
            handicap_away_prob,
        ) * 100.0
        if handicap_home_prob >= handicap_draw_prob and handicap_home_prob >= handicap_away_prob:
            handicap_pick = "H 1 (Ev -1)"
        elif handicap_away_prob >= handicap_home_prob and handicap_away_prob >= handicap_draw_prob:
            handicap_pick = "H 2 (Dep -1)"
        else:
            handicap_pick = "H 0 (Beraberlik)"

        total_corners = 0.0
        corner_pick = None

        card_line = float(self.config.get("cards.line", 4.5))
        if "cards_ou45" in ctx.xgboost_preds:
            cards_over_prob = float(ctx.xgboost_preds["cards_ou45"])
            total_cards = 5.0 if cards_over_prob > 0.50 else 3.5
        else:
            referee_average = float(ctx.referee_pred.avg_yellow_cards)
            match_heat = 1.0
            is_derby = bool(
                ctx.upset_factors.reasoning
                and "DERBY" in str(ctx.upset_factors.reasoning[0]),
            )
            if is_derby:
                match_heat = float(self.config.get("cards.derby_heat_factor", 1.3))
            total_cards = referee_average * match_heat
            delta = total_cards - card_line
            cards_over_prob = 1.0 / (1.0 + math.exp(-delta * 0.9))

        cards_over_prob = max(0.02, min(0.98, cards_over_prob))
        cards_under_prob = 1.0 - cards_over_prob
        cards_confidence = max(cards_over_prob, cards_under_prob) * 100.0
        card_pick = f"{card_line} Ust" if cards_over_prob > 0.50 else f"{card_line} Alt"

        lambda_total = ctx.total_xg
        even_prob = math.exp(-lambda_total) * math.cosh(lambda_total)
        if "odd_even" in ctx.xgboost_preds:
            xgb_weight = float(self.config.get("xgboost.weight_ou", 0.60))
            xgb_even_prob = float(ctx.xgboost_preds["odd_even"])
            even_prob = even_prob * (1 - xgb_weight) + xgb_even_prob * xgb_weight

        even_prob = max(0.02, min(0.98, even_prob))
        odd_prob = 1.0 - even_prob
        odd_even_pick = "Cift" if even_prob > 0.5 else "Tek"

        return OtherMarketsPrediction(
            total_corners_pred=total_corners,
            corner_pick=corner_pick,
            total_cards_pred=total_cards,
            card_pick=card_pick,
            cards_over_prob=cards_over_prob,
            cards_under_prob=cards_under_prob,
            cards_confidence=cards_confidence,
            handicap_pick=handicap_pick,
            handicap_home_prob=handicap_home_prob,
            handicap_draw_prob=handicap_draw_prob,
            handicap_away_prob=handicap_away_prob,
            handicap_confidence=handicap_confidence,
            odd_even_pick=odd_even_pick,
            odd_prob=odd_prob,
            even_prob=even_prob,
        )
