"""Tests for stress testing module."""

import pytest
from horizon._horizon import SimPosition
from horizon.stress import (
    ALL_RESOLVE_NO,
    CORRELATION_SPIKE,
    LIQUIDITY_SHOCK,
    TAIL_RISK,
    ScenarioResult,
    StressScenario,
    StressTestResult,
    stress_test,
)


class TestStressScenario:
    def test_basic(self):
        s = StressScenario(name="test", correlation_override=0.9)
        assert s.name == "test"
        assert s.correlation_override == 0.9
        assert s.price_shocks == {}

    def test_with_shocks(self):
        s = StressScenario(name="crash", price_shocks={"mkt1": 0.01})
        assert s.price_shocks["mkt1"] == 0.01


class TestStressTest:
    def _positions(self):
        return [
            SimPosition("mkt1", "yes", 100.0, 0.50, 0.60),
            SimPosition("mkt2", "yes", 50.0, 0.40, 0.55),
        ]

    def test_default_scenarios(self):
        result = stress_test(self._positions(), n_simulations=100, seed=42)
        assert isinstance(result, StressTestResult)
        assert len(result.scenarios) == 4

    def test_custom_scenario(self):
        s = StressScenario(name="custom", price_shocks={"mkt1": 0.01})
        result = stress_test(self._positions(), scenarios=[s], n_simulations=100, seed=42)
        assert len(result.scenarios) == 1
        assert result.scenarios[0].scenario.name == "custom"

    def test_correlation_spike(self):
        result = stress_test(
            self._positions(),
            scenarios=[CORRELATION_SPIKE],
            n_simulations=1000,
            seed=42,
        )
        assert result.scenarios[0].sim.std_dev > 0.0

    def test_all_resolve_no(self):
        result = stress_test(
            self._positions(),
            scenarios=[ALL_RESOLVE_NO],
            n_simulations=1000,
            seed=42,
        )
        # With yes positions and all resolving to NO, mean PnL should be negative
        assert result.scenarios[0].sim.mean_pnl < 0.0

    def test_worst_scenario(self):
        result = stress_test(self._positions(), n_simulations=1000, seed=42)
        assert result.worst_scenario != ""
        assert result.worst_pnl <= 0.0 or isinstance(result.worst_pnl, float)

    def test_summary(self):
        result = stress_test(self._positions(), n_simulations=100, seed=42)
        summary = result.summary()
        assert summary["n_scenarios"] == 4
        assert "worst_scenario" in summary
        assert "scenarios" in summary

    def test_empty_positions(self):
        result = stress_test([], n_simulations=100, seed=42)
        assert len(result.scenarios) == 4
        for sr in result.scenarios:
            assert sr.sim.mean_pnl == 0.0

    def test_single_position(self):
        pos = [SimPosition("mkt1", "yes", 100.0, 0.50, 0.60)]
        result = stress_test(pos, scenarios=[TAIL_RISK], n_simulations=100, seed=42)
        # Single position: no correlation effect
        assert len(result.scenarios) == 1

    def test_deterministic(self):
        pos = self._positions()
        r1 = stress_test(pos, scenarios=[CORRELATION_SPIKE], n_simulations=1000, seed=42)
        r2 = stress_test(pos, scenarios=[CORRELATION_SPIKE], n_simulations=1000, seed=42)
        assert r1.scenarios[0].sim.mean_pnl == pytest.approx(
            r2.scenarios[0].sim.mean_pnl, abs=1e-10
        )
