"""
Tests for Monte Carlo Simulator
"""

import pytest
from kernel_service.monte_carlo.simulator import MonteCarloSimulator


class TestMonteCarloSimulator:
    """Test Monte Carlo simulation engine"""

    def test_simulator_initialization(self):
        """Test simulator initializes with num_simulations"""
        simulator = MonteCarloSimulator(num_simulations=1000)
        assert simulator.num_simulations == 1000

    def test_simulator_random_seed(self):
        """Test simulator is reproducible with random seed"""
        sim1 = MonteCarloSimulator(num_simulations=100, random_seed=42)
        sim2 = MonteCarloSimulator(num_simulations=100, random_seed=42)
        
        result1 = sim1.forecast_recovery(1000.0, 0.8, 0.2)
        result2 = sim2.forecast_recovery(1000.0, 0.8, 0.2)
        
        assert result1["mean"] == result2["mean"]
        assert result1["median"] == result2["median"]

    def test_forecast_recovery(self):
        """Test recovery amount forecasting"""
        simulator = MonteCarloSimulator(num_simulations=1000, random_seed=42)
        result = simulator.forecast_recovery(
            base_amount=1000.0,
            confidence=0.8,
            volatility=0.2,
        )
        
        assert "mean" in result
        assert "median" in result
        assert "p5" in result
        assert "p25" in result
        assert "p75" in result
        assert "p95" in result
        assert "std_dev" in result
        assert "confidence_interval_95" in result
        
        # Mean should be close to base_amount * confidence
        assert 700 <= result["mean"] <= 900
        assert result["p5"] <= result["p25"] <= result["median"] <= result["p75"] <= result["p95"]

    def test_forecast_statistics(self):
        """Test forecast returns correct statistics"""
        simulator = MonteCarloSimulator(num_simulations=1000, random_seed=42)
        result = simulator.forecast_recovery(1000.0, 0.8, 0.2)
        
        # All statistics should be present
        assert isinstance(result["mean"], float)
        assert isinstance(result["median"], float)
        assert isinstance(result["std_dev"], float)
        assert isinstance(result["confidence_interval_95"], tuple)
        assert len(result["confidence_interval_95"]) == 2

    def test_forecast_confidence_interval(self):
        """Test 95% confidence interval calculation"""
        simulator = MonteCarloSimulator(num_simulations=1000, random_seed=42)
        result = simulator.forecast_recovery(1000.0, 0.8, 0.2)
        
        ci = result["confidence_interval_95"]
        assert ci[0] == result["p5"]
        assert ci[1] == result["p95"]
        assert ci[0] < ci[1]

    def test_forecast_clamps_bounds(self):
        """Test forecast clamps recovery to [0, base_amount]"""
        simulator = MonteCarloSimulator(num_simulations=100, random_seed=42)
        result = simulator.forecast_recovery(
            base_amount=1000.0,
            confidence=0.8,
            volatility=1.0,  # High volatility
        )
        
        # All values should be within bounds
        assert result["p5"] >= 0.0
        assert result["p95"] <= 1000.0
        assert result["mean"] >= 0.0
        assert result["mean"] <= 1000.0

    def test_simulate_denial_scenarios(self):
        """Test denial scenario simulation"""
        simulator = MonteCarloSimulator(num_simulations=100, random_seed=42)
        result = simulator.simulate_denial_scenarios(
            claim_amount=1000.0,
            denial_probability=0.5,
            num_scenarios=100,
        )
        
        assert "expected_recovery" in result
        assert "denial_rate" in result
        assert "scenarios_simulated" in result
        assert result["scenarios_simulated"] == 100
        assert 0.0 <= result["denial_rate"] <= 1.0
        assert result["expected_recovery"] >= 0.0

    def test_simulate_expected_recovery(self):
        """Test expected recovery calculation"""
        simulator = MonteCarloSimulator(num_simulations=100, random_seed=42)
        result = simulator.simulate_denial_scenarios(
            claim_amount=1000.0,
            denial_probability=0.8,
            num_scenarios=100,
        )
        
        # With 80% denial probability, expected recovery should be significant
        assert result["expected_recovery"] > 0.0
        assert result["denial_rate"] > 0.0

    def test_risk_distribution(self):
        """Test risk distribution calculation"""
        simulator = MonteCarloSimulator(num_simulations=1000, random_seed=42)
        result = simulator.risk_distribution(
            base_confidence=0.5,
            risk_factors=[0.2, 0.1, 0.15],
        )
        
        assert "mean_risk" in result
        assert "median_risk" in result
        assert "p95_risk" in result
        assert "combined_risk" in result
        
        assert 0.0 <= result["mean_risk"] <= 1.0
        assert 0.0 <= result["combined_risk"] <= 1.0
        assert result["p95_risk"] >= result["mean_risk"]

    def test_risk_combines_factors(self):
        """Test risk distribution combines multiple factors"""
        simulator = MonteCarloSimulator(num_simulations=100, random_seed=42)
        result = simulator.risk_distribution(
            base_confidence=0.3,
            risk_factors=[0.2, 0.3],
        )
        
        # Combined risk should be higher than base
        assert result["combined_risk"] >= 0.3
        # But clamped to 1.0
        assert result["combined_risk"] <= 1.0

