from __future__ import annotations

from dataclasses import dataclass
from enum import Enum


class State(str, Enum):
    IDLE = "IDLE"
    ENTER = "ENTER"
    PATROL = "PATROL"
    RETURN = "RETURN"
    FAULT = "FAULT"


class Event(str, Enum):
    START_PATROL = "START_PATROL"
    ENTERED_ROUTE = "ENTERED_ROUTE"
    PATROL_COMPLETED = "PATROL_COMPLETED"
    RETURNED_HOME = "RETURNED_HOME"
    ABORT = "ABORT"
    SAFETY_TIMEOUT = "SAFETY_TIMEOUT"
    RESET = "RESET"


TRANSITIONS: dict[tuple[State, Event], State] = {
    (State.IDLE, Event.START_PATROL): State.ENTER,
    (State.ENTER, Event.ENTERED_ROUTE): State.PATROL,
    (State.ENTER, Event.ABORT): State.RETURN,
    (State.PATROL, Event.PATROL_COMPLETED): State.RETURN,
    (State.PATROL, Event.ABORT): State.RETURN,
    (State.RETURN, Event.RETURNED_HOME): State.IDLE,
    (State.ENTER, Event.SAFETY_TIMEOUT): State.FAULT,
    (State.PATROL, Event.SAFETY_TIMEOUT): State.FAULT,
    (State.RETURN, Event.SAFETY_TIMEOUT): State.FAULT,
    (State.FAULT, Event.RESET): State.IDLE,
}


class InvalidTransition(ValueError):
    """Raised when an event is not allowed from the current state."""


@dataclass(frozen=True)
class PatrolStateMachine:
    state: State = State.IDLE

    def dispatch(self, event: Event) -> "PatrolStateMachine":
        next_state = TRANSITIONS.get((self.state, event))
        if next_state is None:
            raise InvalidTransition(f"{event} is not allowed from {self.state}")
        return PatrolStateMachine(next_state)
