"""
Unit Tests for State Machine

Tests the SystemStateMachine lifecycle management.
"""

import pytest
import time
from altrus.core.lifecycle import SystemState, SystemStateMachine, StateTransition


class TestSystemStateMachine:
    """Test suite for SystemStateMachine"""

    def test_initial_state(self):
        """Test that state machine starts in INIT state"""
        sm = SystemStateMachine()
        assert sm.current_state == SystemState.INIT

    def test_valid_transition(self):
        """Test valid state transitions"""
        sm = SystemStateMachine()

        # INIT -> READY
        result = sm.transition(SystemState.READY, "Initialization complete")
        assert result is True
        assert sm.current_state == SystemState.READY

        # READY -> RUNNING
        result = sm.transition(SystemState.RUNNING, "System started")
        assert result is True
        assert sm.current_state == SystemState.RUNNING

    def test_invalid_transition(self):
        """Test that invalid transitions are rejected"""
        sm = SystemStateMachine()

        # Cannot go directly from INIT to RUNNING
        from altrus.core.lifecycle import InvalidStateTransitionError
        with pytest.raises(InvalidStateTransitionError):
            sm.transition(SystemState.RUNNING, "Invalid transition")

        assert sm.current_state == SystemState.INIT

    def test_degraded_state(self):
        """Test transition to DEGRADED state"""
        sm = SystemStateMachine()
        sm.transition(SystemState.READY, "Ready")
        sm.transition(SystemState.RUNNING, "Running")

        # RUNNING -> DEGRADED
        result = sm.transition(SystemState.DEGRADED, "Partial failure")
        assert result is True
        assert sm.current_state == SystemState.DEGRADED

    def test_failed_state(self):
        """Test transition to FAILED state"""
        sm = SystemStateMachine()
        sm.transition(SystemState.READY, "Ready")
        sm.transition(SystemState.RUNNING, "Running")

        # RUNNING -> FAILED
        result = sm.transition(SystemState.FAILED, "Critical error")
        assert result is True
        assert sm.current_state == SystemState.FAILED

    def test_emergency_shutdown(self):
        """Test that emergency shutdown to FAILED is always allowed"""
        sm = SystemStateMachine()

        # Even from INIT, can go to FAILED
        result = sm.transition(SystemState.FAILED, "Emergency shutdown")
        assert result is True
        assert sm.current_state == SystemState.FAILED

    def test_transition_history(self):
        """Test that transition history is recorded"""
        sm = SystemStateMachine()

        sm.transition(SystemState.READY, "First transition")
        sm.transition(SystemState.RUNNING, "Second transition")

        history = sm.get_transition_history()
        assert len(history) >= 2

        # Check last transition
        last_transition = history[-1]
        assert last_transition.from_state == SystemState.READY
        assert last_transition.to_state == SystemState.RUNNING
        assert last_transition.reason == "Second transition"

    def test_state_callbacks(self):
        """Test that state change callbacks are invoked"""
        sm = SystemStateMachine()

        callback_invoked = []

        def callback(transition: StateTransition):
            callback_invoked.append(transition)

        sm.register_callback(callback)

        sm.transition(SystemState.READY, "Test callback")

        assert len(callback_invoked) == 1
        assert callback_invoked[0].to_state == SystemState.READY

    def test_time_in_state(self):
        """Test time_in_state tracking"""
        sm = SystemStateMachine()
        sm.transition(SystemState.READY, "Ready")

        time.sleep(0.1)

        time_in_state = sm.get_time_in_state()
        assert time_in_state >= 0.1

    def test_state_statistics(self):
        """Test state statistics tracking"""
        sm = SystemStateMachine()

        sm.transition(SystemState.READY, "First")
        sm.transition(SystemState.RUNNING, "Second")
        sm.transition(SystemState.DEGRADED, "Third")

        stats = sm.get_state_statistics()

        assert SystemState.READY in stats
        assert SystemState.RUNNING in stats
        assert SystemState.DEGRADED in stats

        # Check entry counts
        assert stats[SystemState.READY]["entry_count"] == 1
        assert stats[SystemState.RUNNING]["entry_count"] == 1


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
