"""Unit Tests for Signal Generation & Cost-Adjusted Expected Value (EV)."""
from __future__ import annotations

import unittest
from decimal import Decimal

from backend.app.market_data.mock_client import MockBybitClient
from backend.app.schemas.signal import SignalAction
from backend.app.strategy.expected_value import ExpectedValueCalculator
from backend.app.strategy.signal_engine import SignalEngine


class TestSignalEngine(unittest.TestCase):
    def setUp(self) -> None:
        self.mock_client = MockBybitClient()
        self.ev_calc = ExpectedValueCalculator(min_ev_hurdle=0.0015, taker_fee_pct=0.00055, slippage_pct=0.00020, uncertainty_pct=0.00030)
        self.signal_engine = SignalEngine()

    def test_expected_value_hurdle_positive(self) -> None:
        """Verify positive expected value when win probability is 65% with 2.0 R:R."""
        entry = Decimal("60000.00")
        stop = Decimal("59000.00")  # 1.67% risk
        tp = Decimal("62000.00")    # 3.33% reward
        res = self.ev_calc.calculate(win_probability=0.65, entry_price=entry, stop_loss=stop, take_profit=tp)

        self.assertTrue(res.is_positive)
        self.assertTrue(res.hurdle_passed)
        # Net EV should comfortably beat 15 bps (0.0015)
        self.assertGreater(res.ev, 0.0015)

    def test_expected_value_hurdle_negative_produces_no_trade(self) -> None:
        """Verify negative expected value when win probability is 40% fails hurdle."""
        entry = Decimal("60000.00")
        stop = Decimal("59000.00")
        tp = Decimal("61000.00")
        res = self.ev_calc.calculate(win_probability=0.40, entry_price=entry, stop_loss=stop, take_profit=tp)

        self.assertFalse(res.hurdle_passed)

    def test_no_trade_is_successful_decision_on_flat_market(self) -> None:
        """Verify flat/choppy candles produce NO_TRADE decision to protect capital."""
        candles = self.mock_client.get_klines("BTCUSDT", "15m", 100)
        ticker = self.mock_client.get_ticker("BTCUSDT")
        signal = self.signal_engine.generate_signal(candles, ticker)

        self.assertIn(signal.action, [SignalAction.LONG, SignalAction.SHORT, SignalAction.NO_TRADE])
        if signal.action == SignalAction.NO_TRADE:
            self.assertGreater(len(signal.reason), 0)


if __name__ == "__main__":
    unittest.main()
