"""
System Lifecycle Management

Defines global system states and state machine for the ALTRUS kernel.
"""

from enum import Enum, auto
from typing import Optional, Callable, Dict, List
from dataclasses import dataclass
import time


class SystemState(Enum):
    """Global system lifecycle states"""
    INIT = "INIT"              # System initializing
    READY = "READY"            # System ready but not running
    RUNNING = "RUNNING"        # System operational
    DEGRADED = "DEGRADED"      # System running with reduced capability
    FAILED = "FAILED"          # System failed, requires intervention


@dataclass
class StateTransition:
    """Represents a state transition event"""
    from_state: SystemState
    to_state: SystemState
    timestamp: float
    reason: str
    metadata: Optional[Dict] = None


class SystemStateMachine:
    """
    Manages system-wide state transitions with validation.

    Valid transitions:
    - INIT -> READY (initialization complete)
    - READY -> RUNNING (system started)
    - RUNNING -> DEGRADED (fault detected)
    - RUNNING -> FAILED (critical fault)
    - DEGRADED -> RUNNING (recovery successful)
    - DEGRADED -> FAILED (recovery failed)
    - FAILED -> INIT (system restart)
    - Any state -> FAILED (emergency shutdown)
    """

    # Define valid state transitions
    VALID_TRANSITIONS = {
        SystemState.INIT: [SystemState.READY, SystemState.FAILED],
        SystemState.READY: [SystemState.RUNNING, SystemState.FAILED],
        SystemState.RUNNING: [SystemState.DEGRADED, SystemState.FAILED],
        SystemState.DEGRADED: [SystemState.RUNNING, SystemState.FAILED],
        SystemState.FAILED: [SystemState.INIT, SystemState.RUNNING],
    }

    def __init__(self, initial_state: SystemState = SystemState.INIT):
        self._current_state = initial_state
        self._transition_history: List[StateTransition] = []
        self._state_change_callbacks: List[Callable[[StateTransition], None]] = []

        # Record initial state
        self._transition_history.append(
            StateTransition(
                from_state=initial_state,
                to_state=initial_state,
                timestamp=time.time(),
                reason="Initial state"
            )
        )

    @property
    def current_state(self) -> SystemState:
        """Get current system state"""
        return self._current_state

    def register_callback(self, callback: Callable[[StateTransition], None]):
        """Register a callback to be called on state transitions"""
        self._state_change_callbacks.append(callback)

    def can_transition(self, to_state: SystemState) -> bool:
        """Check if transition to target state is valid"""
        # Emergency shutdown to FAILED is always allowed
        if to_state == SystemState.FAILED:
            return True

        valid_targets = self.VALID_TRANSITIONS.get(self._current_state, [])
        return to_state in valid_targets

    def transition(self, to_state: SystemState, reason: str, metadata: Optional[Dict] = None) -> bool:
        """
        Attempt to transition to a new state.

        Args:
            to_state: Target state
            reason: Human-readable reason for transition
            metadata: Optional additional context

        Returns:
            True if transition successful, False otherwise
        """
        # Check if already in target state
        if self._current_state == to_state:
            return True

        # Validate transition
        if not self.can_transition(to_state):
            raise InvalidStateTransitionError(
                f"Invalid transition from {self._current_state.value} to {to_state.value}"
            )

        # Create transition record
        transition = StateTransition(
            from_state=self._current_state,
            to_state=to_state,
            timestamp=time.time(),
            reason=reason,
            metadata=metadata or {}
        )

        # Update state
        old_state = self._current_state
        self._current_state = to_state
        self._transition_history.append(transition)

        # Notify callbacks
        for callback in self._state_change_callbacks:
            try:
                callback(transition)
            except Exception as e:
                # Don't let callback errors prevent state transition
                print(f"Error in state change callback: {e}")

        return True

    def get_transition_history(self) -> List[StateTransition]:
        """Get complete state transition history"""
        return self._transition_history.copy()

    def get_time_in_state(self) -> float:
        """Get time elapsed in current state (seconds)"""
        if not self._transition_history:
            return 0.0

        last_transition = self._transition_history[-1]
        return time.time() - last_transition.timestamp

    def get_state_statistics(self) -> Dict[SystemState, Dict[str, float]]:
        """
        Calculate statistics for each state.

        Returns:
            Dict mapping state to {total_time, entry_count}
        """
        stats: Dict[SystemState, Dict[str, float]] = {
            state: {"total_time": 0.0, "entry_count": 0}
            for state in SystemState
        }

        for i in range(len(self._transition_history) - 1):
            current = self._transition_history[i]
            next_trans = self._transition_history[i + 1]

            duration = next_trans.timestamp - current.timestamp
            stats[current.to_state]["total_time"] += duration
            stats[current.to_state]["entry_count"] += 1

        # Add current state duration
        if self._transition_history:
            current = self._transition_history[-1]
            current_duration = time.time() - current.timestamp
            stats[self._current_state]["total_time"] += current_duration
            stats[self._current_state]["entry_count"] += 1

        return stats


class InvalidStateTransitionError(Exception):
    """Raised when an invalid state transition is attempted"""
    pass
