"""Cost-Adjusted Expected Value (EV) Engine."""
from __future__ import annotations

from dataclasses import dataclass
from decimal import Decimal
from typing import Optional

from backend.app.config.settings import settings


@dataclass
class ExpectedValueResult:
    ev: float
    win_probability: float
    reward_pct: float
    risk_pct: float
    friction_pct: float
    is_positive: bool
    hurdle_passed: bool


class ExpectedValueCalculator:
    """Calculates net mathematical expectancy after exchange fees, spread, slippage, and uncertainty."""

    def __init__(
        self,
        min_ev_hurdle: float = 0.0015,  # 15 bps minimum net expected edge
        taker_fee_pct: Optional[float] = None,
        slippage_pct: Optional[float] = None,
        uncertainty_pct: Optional[float] = None,
    ) -> None:
        self.min_ev_hurdle = min_ev_hurdle
        self.taker_fee_pct = taker_fee_pct if taker_fee_pct is not None else settings.DEFAULT_TAKER_FEE_PCT
        self.slippage_pct = slippage_pct if slippage_pct is not None else settings.ESTIMATED_SLIPPAGE_PCT
        self.uncertainty_pct = uncertainty_pct if uncertainty_pct is not None else settings.UNCERTAINTY_BUFFER_PCT

    def calculate(
        self,
        win_probability: float,
        entry_price: Decimal,
        stop_loss: Decimal,
        take_profit: Decimal,
        spread_pct: float = 0.0001,
    ) -> ExpectedValueResult:
        entry_f = float(entry_price)
        stop_f = float(stop_loss)
        tp_f = float(take_profit)

        if entry_f <= 0:
            return ExpectedValueResult(0.0, 0.0, 0.0, 0.0, 0.0, False, False)

        reward_pct = abs(tp_f - entry_f) / entry_f
        risk_pct = abs(stop_f - entry_f) / entry_f

        # Total roundtrip friction: 2x taker fee + spread + slippage + conservative uncertainty buffer
        friction_pct = (2.0 * self.taker_fee_pct) + spread_pct + self.slippage_pct + self.uncertainty_pct

        # Mathematical Expectation: E[R] = P(win)*Reward - P(loss)*Risk - Friction
        loss_probability = 1.0 - win_probability
        net_ev = (win_probability * reward_pct) - (loss_probability * risk_pct) - friction_pct

        hurdle_passed = net_ev >= self.min_ev_hurdle

        return ExpectedValueResult(
            ev=net_ev,
            win_probability=win_probability,
            reward_pct=reward_pct,
            risk_pct=risk_pct,
            friction_pct=friction_pct,
            is_positive=net_ev > 0,
            hurdle_passed=hurdle_passed,
        )


ev_calculator = ExpectedValueCalculator()
