"""Tests for Phase state machine."""

import pytest

from thetable_poc.meeting import MeetingPhase, PhaseEvent, PhaseMachine


class TestPhaseMachine:
    """Test phase state machine."""

    def test_initial_state(self):
        """Test initial state is IDLE."""
        machine = PhaseMachine()
        assert machine.current_phase == MeetingPhase.IDLE

    def test_normal_flow(self):
        """Test normal meeting flow."""
        machine = PhaseMachine()

        # Start meeting
        assert machine.trigger(PhaseEvent.START_MEETING) is True
        assert machine.current_phase == MeetingPhase.OPENING

        # Complete opening
        assert machine.trigger(PhaseEvent.OPENING_COMPLETE) is True
        assert machine.current_phase == MeetingPhase.STATUS_CHECK

        # Complete status check
        assert machine.trigger(PhaseEvent.STATUS_CHECK_COMPLETE) is True
        assert machine.current_phase == MeetingPhase.ISSUE_RESOLUTION

        # Complete issue resolution
        assert machine.trigger(PhaseEvent.ISSUE_RESOLUTION_COMPLETE) is True
        assert machine.current_phase == MeetingPhase.WORKTREE_EXECUTION

        # Complete worktree
        assert machine.trigger(PhaseEvent.WORKTREE_COMPLETE) is True
        assert machine.current_phase == MeetingPhase.CLOSING

        # Complete closing
        assert machine.trigger(PhaseEvent.CLOSING_COMPLETE) is True
        assert machine.current_phase == MeetingPhase.ENDED

    def test_invalid_transition(self):
        """Test invalid phase transitions are rejected."""
        machine = PhaseMachine()

        # Cannot go directly to closing from idle
        assert machine.trigger(PhaseEvent.CLOSING_COMPLETE) is False
        assert machine.current_phase == MeetingPhase.IDLE

    def test_skip_to_closing(self):
        """Test skip to closing from any active phase."""
        machine = PhaseMachine()

        # Start meeting
        machine.trigger(PhaseEvent.START_MEETING)
        assert machine.current_phase == MeetingPhase.OPENING

        # Skip to closing
        assert machine.trigger(PhaseEvent.SKIP_TO_CLOSING) is True
        assert machine.current_phase == MeetingPhase.CLOSING

    def test_force_end(self):
        """Test force end from any phase."""
        machine = PhaseMachine()

        # Start meeting
        machine.trigger(PhaseEvent.START_MEETING)
        machine.trigger(PhaseEvent.OPENING_COMPLETE)
        assert machine.current_phase == MeetingPhase.STATUS_CHECK

        # Force end
        assert machine.trigger(PhaseEvent.FORCE_END) is True
        assert machine.current_phase == MeetingPhase.ENDED

    def test_get_available_events(self):
        """Test getting available events for current phase."""
        machine = PhaseMachine()

        # In IDLE, can start meeting
        events = machine.get_available_events()
        assert PhaseEvent.START_MEETING in events

        # In OPENING, can complete or skip
        machine.trigger(PhaseEvent.START_MEETING)
        events = machine.get_available_events()
        assert PhaseEvent.OPENING_COMPLETE in events
        assert PhaseEvent.SKIP_TO_CLOSING in events
        assert PhaseEvent.FORCE_END in events

    def test_phase_handlers(self):
        """Test enter and exit handlers."""
        machine = PhaseMachine()
        enter_called = []
        exit_called = []

        # Register handlers
        machine.on_enter(
            MeetingPhase.OPENING,
            lambda: enter_called.append("opening"),
        )
        machine.on_exit(
            MeetingPhase.IDLE,
            lambda: exit_called.append("idle"),
        )

        # Trigger transition
        machine.trigger(PhaseEvent.START_MEETING)

        # Verify handlers were called
        assert "idle" in exit_called
        assert "opening" in enter_called

    def test_reset(self):
        """Test resetting state machine."""
        machine = PhaseMachine()

        # Move through phases
        machine.trigger(PhaseEvent.START_MEETING)
        machine.trigger(PhaseEvent.OPENING_COMPLETE)
        assert machine.current_phase == MeetingPhase.STATUS_CHECK

        # Reset
        machine.reset()
        assert machine.current_phase == MeetingPhase.IDLE

    def test_guard_conditions(self):
        """Test guard conditions on transitions."""
        machine = PhaseMachine()
        allow_transition = False

        # Add transition with guard
        from thetable_poc.meeting.phase_machine import PhaseTransition

        guarded = PhaseTransition(
            MeetingPhase.OPENING,
            MeetingPhase.STATUS_CHECK,
            PhaseEvent.OPENING_COMPLETE,
            guard=lambda: allow_transition,
        )

        # Transition is not allowed
        assert guarded.can_transition() is False

        # Now allow it
        allow_transition = True
        assert guarded.can_transition() is True


class TestPhaseEnum:
    """Test phase enum values."""

    def test_all_phases_defined(self):
        """Test all expected phases are defined."""
        expected_phases = {
            "idle",
            "opening",
            "status_check",
            "issue_resolution",
            "worktree_execution",
            "closing",
            "ended",
        }

        actual_phases = {phase.value for phase in MeetingPhase}
        assert actual_phases == expected_phases


class TestPhaseEventEnum:
    """Test phase event enum values."""

    def test_all_events_defined(self):
        """Test all expected events are defined."""
        expected_events = {
            "start_meeting",
            "opening_complete",
            "status_check_complete",
            "issue_resolution_complete",
            "worktree_complete",
            "closing_complete",
            "force_end",
            "skip_to_closing",
        }

        actual_events = {event.value for event in PhaseEvent}
        assert actual_events == expected_events
