from __future__ import annotations

from openpoker.types import EVResult, PotOddsResult


def calculate_pot_odds(
    pot_size: int,
    bet_to_call: int,
    win_probability: float,
) -> PotOddsResult:
    if bet_to_call <= 0:
        raise ValueError("Bet to call must be positive")
    if pot_size < 0:
        raise ValueError("Pot size cannot be negative")
    if not 0 <= win_probability <= 1:
        raise ValueError("Win probability must be between 0 and 1")

    total_pot_after_call = pot_size + bet_to_call
    pot_odds = bet_to_call / total_pot_after_call if total_pot_after_call > 0 else 1
    required_equity = pot_odds
    equity_diff = win_probability - required_equity
    expected_value = (win_probability * total_pot_after_call) - bet_to_call

    return PotOddsResult(
        pot_odds=round(pot_odds, 4),
        pot_odds_ratio=f"{bet_to_call}:{pot_size}",
        pot_odds_percentage=round(pot_odds * 100, 2),
        required_equity=round(required_equity, 4),
        required_equity_percentage=round(required_equity * 100, 2),
        equity=round(win_probability, 4),
        equity_percentage=round(win_probability * 100, 2),
        equity_difference=round(equity_diff, 4),
        expected_value=round(expected_value, 2),
    )


def calculate_expected_value(
    pot_size: int,
    bet_to_call: int,
    win_probability: float,
    your_stack: int,
    action: str,
) -> EVResult:
    normalized_action = action.lower()

    if normalized_action == "fold":
        return EVResult(
            action="fold",
            ev=0.0,
            message="Folding has 0 EV (baseline)",
        )

    if normalized_action == "call":
        if bet_to_call > your_stack:
            raise ValueError("Insufficient stack to call")

        total_pot_after_call = pot_size + bet_to_call
        ev = (win_probability * total_pot_after_call) - bet_to_call
        return EVResult(
            action="call",
            cost=bet_to_call,
            potential_win=total_pot_after_call,
            ev=round(ev, 2),
            message=f"Calling costs {bet_to_call} with EV of {ev:+.2f}",
        )

    raise ValueError(f"Invalid action: {normalized_action}. Must be fold or call")
