"""Phase state machine for meeting flow control."""

from enum import Enum
from typing import Callable, Optional


class MeetingPhase(Enum):
    """Meeting phases."""

    IDLE = "idle"
    OPENING = "opening"
    STATUS_CHECK = "status_check"
    ISSUE_RESOLUTION = "issue_resolution"
    WORKTREE_EXECUTION = "worktree_execution"
    CLOSING = "closing"
    ENDED = "ended"


class PhaseEvent(Enum):
    """Events that trigger phase transitions."""

    START_MEETING = "start_meeting"
    OPENING_COMPLETE = "opening_complete"
    STATUS_CHECK_COMPLETE = "status_check_complete"
    ISSUE_RESOLUTION_COMPLETE = "issue_resolution_complete"
    WORKTREE_COMPLETE = "worktree_complete"
    CLOSING_COMPLETE = "closing_complete"
    FORCE_END = "force_end"
    SKIP_TO_CLOSING = "skip_to_closing"


class PhaseTransition:
    """Represents a phase transition."""

    def __init__(
        self,
        from_phase: MeetingPhase,
        to_phase: MeetingPhase,
        event: PhaseEvent,
        guard: Optional[Callable[[], bool]] = None,
    ):
        """Initialize phase transition.

        Args:
            from_phase: Source phase
            to_phase: Target phase
            event: Event that triggers this transition
            guard: Optional condition that must be true for transition
        """
        self.from_phase = from_phase
        self.to_phase = to_phase
        self.event = event
        self.guard = guard

    def can_transition(self) -> bool:
        """Check if transition can occur.

        Returns:
            True if guard condition is met (or no guard exists)
        """
        if self.guard is None:
            return True
        return self.guard()


class PhaseMachine:
    """State machine for managing meeting phases."""

    def __init__(self):
        """Initialize phase machine."""
        self.current_phase = MeetingPhase.IDLE
        self._transitions: list[PhaseTransition] = []
        self._on_enter_handlers: dict[MeetingPhase, list[Callable]] = {}
        self._on_exit_handlers: dict[MeetingPhase, list[Callable]] = {}
        self._setup_transitions()

    def _setup_transitions(self) -> None:
        """Set up phase transition rules."""
        # Normal flow
        self._add_transition(
            MeetingPhase.IDLE,
            MeetingPhase.OPENING,
            PhaseEvent.START_MEETING,
        )
        self._add_transition(
            MeetingPhase.OPENING,
            MeetingPhase.STATUS_CHECK,
            PhaseEvent.OPENING_COMPLETE,
        )
        self._add_transition(
            MeetingPhase.STATUS_CHECK,
            MeetingPhase.ISSUE_RESOLUTION,
            PhaseEvent.STATUS_CHECK_COMPLETE,
        )
        self._add_transition(
            MeetingPhase.ISSUE_RESOLUTION,
            MeetingPhase.WORKTREE_EXECUTION,
            PhaseEvent.ISSUE_RESOLUTION_COMPLETE,
        )
        self._add_transition(
            MeetingPhase.WORKTREE_EXECUTION,
            MeetingPhase.CLOSING,
            PhaseEvent.WORKTREE_COMPLETE,
        )
        self._add_transition(
            MeetingPhase.CLOSING,
            MeetingPhase.ENDED,
            PhaseEvent.CLOSING_COMPLETE,
        )

        # Exception paths
        # Force end from any phase except IDLE and ENDED
        for phase in MeetingPhase:
            if phase not in (MeetingPhase.IDLE, MeetingPhase.ENDED):
                self._add_transition(
                    phase,
                    MeetingPhase.ENDED,
                    PhaseEvent.FORCE_END,
                )

        # Skip to closing from any active phase
        for phase in [
            MeetingPhase.OPENING,
            MeetingPhase.STATUS_CHECK,
            MeetingPhase.ISSUE_RESOLUTION,
            MeetingPhase.WORKTREE_EXECUTION,
        ]:
            self._add_transition(
                phase,
                MeetingPhase.CLOSING,
                PhaseEvent.SKIP_TO_CLOSING,
            )

    def _add_transition(
        self,
        from_phase: MeetingPhase,
        to_phase: MeetingPhase,
        event: PhaseEvent,
        guard: Optional[Callable[[], bool]] = None,
    ) -> None:
        """Add a transition rule.

        Args:
            from_phase: Source phase
            to_phase: Target phase
            event: Event that triggers transition
            guard: Optional guard condition
        """
        self._transitions.append(
            PhaseTransition(from_phase, to_phase, event, guard)
        )

    def trigger(self, event: PhaseEvent) -> bool:
        """Trigger an event to transition phases.

        Args:
            event: The event to trigger

        Returns:
            True if transition occurred, False otherwise
        """
        for transition in self._transitions:
            if (
                transition.from_phase == self.current_phase
                and transition.event == event
                and transition.can_transition()
            ):
                # Call exit handlers for current phase
                self._call_handlers(
                    self._on_exit_handlers.get(self.current_phase, [])
                )

                # Transition
                old_phase = self.current_phase
                self.current_phase = transition.to_phase

                # Call enter handlers for new phase
                self._call_handlers(
                    self._on_enter_handlers.get(self.current_phase, [])
                )

                return True

        return False

    def _call_handlers(self, handlers: list[Callable]) -> None:
        """Call list of handlers.

        Args:
            handlers: List of handler functions to call
        """
        for handler in handlers:
            handler()

    def on_enter(self, phase: MeetingPhase, handler: Callable) -> None:
        """Register a handler for entering a phase.

        Args:
            phase: The phase to register handler for
            handler: The handler function
        """
        if phase not in self._on_enter_handlers:
            self._on_enter_handlers[phase] = []
        self._on_enter_handlers[phase].append(handler)

    def on_exit(self, phase: MeetingPhase, handler: Callable) -> None:
        """Register a handler for exiting a phase.

        Args:
            phase: The phase to register handler for
            handler: The handler function
        """
        if phase not in self._on_exit_handlers:
            self._on_exit_handlers[phase] = []
        self._on_exit_handlers[phase].append(handler)

    def get_available_events(self) -> list[PhaseEvent]:
        """Get available events for current phase.

        Returns:
            List of events that can be triggered
        """
        available = []
        for transition in self._transitions:
            if (
                transition.from_phase == self.current_phase
                and transition.can_transition()
            ):
                available.append(transition.event)
        return available

    def reset(self) -> None:
        """Reset state machine to initial state."""
        self.current_phase = MeetingPhase.IDLE
