"""
Fault Injection Component

Automatically injects faults into the system for recovery testing.
"""

import threading
import time
import random
from typing import List, Dict, Optional, Any

class FaultInjector:
    """
    Component that automatically injects faults based on configuration.

    Fault Types:
    - MODULE_CRASH: Stops a module's heartbeat
    - BATTERY_DRAIN: Sets module battery to zero
    - LATENCY: Adds artificial delay to module response
    - DATA_TAMPER: Modifies blockchain data (simulated)
    """

    def __init__(self, kernel, config: Optional[Dict[str, Any]] = None):
        self.kernel = kernel
        self.config = config or {
            "injection_frequency": 10.0,  # seconds
            "fault_types": ["crash", "battery", "latency"],
            "probability": 0.5
        }
        self._running = False
        self._thread: Optional[threading.Thread] = None

    def start(self):
        """Start the injection loop"""
        self._running = True
        self._thread = threading.Thread(target=self._loop, daemon=True)
        self._thread.start()
        print("💉 Fault Injector started")

    def stop(self):
        """Stop the injection loop"""
        self._running = False
        if self._thread:
            self._thread.join(timeout=2.0)
        print("💉 Fault Injector stopped")

    def _loop(self):
        while self._running:
            time.sleep(self.config.get("injection_frequency", 10.0))

            if random.random() < self.config.get("probability", 0.5):
                self._inject_random_fault()

    def _inject_random_fault(self):
        """Select and inject a random fault"""
        active_modules = [m for m in self.kernel.registry.list_modules() if m.state.name == "ACTIVE"]
        if not active_modules:
            return

        module = random.choice(active_modules)
        fault_type = random.choice(self.config["fault_types"])

        print(f"💉 Injecting {fault_type} into {module.module_id}")

        if fault_type == "crash":
            # Simulate a crash by removing from registry or updating state
            from altrus.core.registry.module import ModuleState
            self.kernel.registry.update_state(module.module_id, ModuleState.FAILED)
            self.kernel.fault_engine.handle_fault(module.module_id, "CRASH_DETECTED", {"source": "injector"})

        elif fault_type == "battery":
            # Simulate battery drain
            self.kernel.fault_engine.handle_fault(module.module_id, "BATTERY_CRITICAL", {"level": 0.0})

        elif fault_type == "latency":
            # Just log it, the fault engine should pick it up if it takes too long
            self.kernel.fault_engine.handle_fault(module.module_id, "HIGH_LATENCY", {"latency": 5.5})

    def inject_specific_fault(self, module_id: str, fault_type: str, metadata: Optional[Dict] = None):
        """Manually inject a specific fault for testing"""
        print(f"💉 Manual injection: {fault_type} -> {module_id}")
        self.kernel.fault_engine.handle_fault(module_id, fault_type, metadata or {})
