"""
Unit tests for Simulation components
"""
import pytest
import time
from pathlib import Path
from altrus.simulation.fault_injector import FaultInjector
from altrus.simulation.stress_tester import StressTester
from altrus.simulation.reporter import SimulationReporter
from altrus.core.kernel import AltrusKernel
from altrus.core.observability.server import stop_metrics_server
from altrus.core.registry.module import Module, ModuleHealth, ModuleState

@pytest.fixture
def kernel(tmp_path):
    k = AltrusKernel(storage_dir=tmp_path)
    yield k
    k.shutdown()
    stop_metrics_server()

def test_fault_injector(kernel):
    """Test fault injection into kernel"""
    injector = FaultInjector(kernel)

    # Register a dummy module
    m = Module("m1", "M1", "1.0", ["cap.a"])
    kernel.registry.register(m)
    kernel.start()

    # Inject fault using the method found in fault_injector.py
    injector.inject_specific_fault("m1", "crash")

    # FaultEngine.handle_fault should process it
    # We wait a tiny bit for processing if needed, but it's usually sync
    module = kernel.registry.get("m1")
    # The injector calls handle_fault, which should update health to CRITICAL
    assert module.health == ModuleHealth.CRITICAL

def test_fault_injector_loop(kernel):
    """Test background fault injector loop"""
    # Use high frequency and probability for testing
    injector = FaultInjector(kernel, config={
        "injection_frequency": 0.1,
        "fault_types": ["crash"],
        "probability": 1.0
    })

    m = Module("m1", "M1", "1.0", ["cap.a"])
    kernel.registry.register(m)
    kernel.registry.activate("m1")
    kernel.start()

    injector.start()
    time.sleep(0.5)
    injector.stop()

    # At least one injection should have happened
    module = kernel.registry.get("m1")
    assert module.health == ModuleHealth.CRITICAL or module.state == ModuleState.FAILED

def test_simulation_reporter(tmp_path):
    """Test reporter generation"""
    reporter = SimulationReporter(output_dir=tmp_path)

    stats = {
        "submitted_total": 10,
        "failed_total": 2,
        "avg_submission_latency_ms": 5.0
    }

    history = [
        {"detector": "HEARTBEAT", "details": {"recovery_duration": 1.2}},
        {"detector": "MANUAL", "details": {"recovery_duration": 0.5}}
    ]

    report_path = reporter.generate_summary(stats, history, ledger_len=100)
    assert report_path.exists()
    assert "MTTR" in report_path.read_text()

def test_stress_tester(kernel):
    """Test stress tester basic submission loop"""
    m = Module("m1", "M1", "1.0", ["task.a"])
    kernel.registry.register(m)
    kernel.start()

    tester = StressTester(kernel)
    # Trigger a submission manually or via start/stop
    # Since worker_loop is a loop, we can just call the core logic if it was exposed
    # or just start it for a very short time.
    tester.start(workers=1, intensity=0.01)
    time.sleep(0.5)
    tester.stop()

    report = tester.get_report()
    assert report["submitted_total"] > 0
