from typing import Optional, cast

from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
from isar.state_machine.state_machine import StateMachine
from robot_interface.models.mission.status import MissionStatus, RobotStatus


def test_lockdown_transitions_to_home(
    sync_state_machine: StateMachine,
) -> None:
    sync_state_machine.shared_state.robot_battery_level.trigger_event(80.0)
    sync_state_machine.state = sync_state_machine.lockdown_state.name  # type: ignore

    lockdown_state: EventHandlerBase = cast(
        EventHandlerBase, sync_state_machine.lockdown_state
    )
    event_handler: Optional[EventHandlerMapping] = (
        lockdown_state.get_event_handler_by_name("release_from_lockdown")
    )

    assert event_handler is not None

    event_handler.event.trigger_event(True)
    transition = event_handler.handler(event_handler.event)

    assert transition is sync_state_machine.release_from_lockdown  # type: ignore
    assert sync_state_machine.events.api_requests.release_from_lockdown.response.check()
    transition()
    assert sync_state_machine.state is sync_state_machine.home_state.name  # type: ignore


def test_state_machine_with_return_home_failure_successful_retries(
    sync_state_machine: StateMachine,
) -> None:
    sync_state_machine.shared_state.robot_battery_level.trigger_event(80.0)
    sync_state_machine.state = sync_state_machine.returning_home_state.name  # type: ignore

    returning_home_state: EventHandlerBase = cast(
        EventHandlerBase, sync_state_machine.returning_home_state
    )
    event_handler: Optional[EventHandlerMapping] = (
        returning_home_state.get_event_handler_by_name("mission_status_event")
    )

    # We do not retry return home missions if the robot is not ready for another mission
    sync_state_machine.shared_state.robot_status.trigger_event(RobotStatus.Available)

    assert event_handler is not None

    event_handler.event.trigger_event(MissionStatus.Failed)
    transition = event_handler.handler(event_handler.event)

    assert transition is None  # type: ignore
    assert sync_state_machine.returning_home_state.failed_return_home_attempts == 1

    event_handler.event.trigger_event(MissionStatus.Successful)
    transition = event_handler.handler(event_handler.event)

    assert transition is sync_state_machine.returned_home  # type: ignore

    transition()
    assert sync_state_machine.state is sync_state_machine.home_state.name  # type: ignore


def test_intervention_needed_transitions_to_home_if_robot_is_home(
    sync_state_machine: StateMachine,
) -> None:
    sync_state_machine.state = sync_state_machine.intervention_needed_state.name  # type: ignore

    intervention_needed_state: EventHandlerBase = cast(
        EventHandlerBase, sync_state_machine.intervention_needed_state
    )
    event_handler: Optional[EventHandlerMapping] = (
        intervention_needed_state.get_event_handler_by_name("robot_status_event")
    )
    assert event_handler is not None

    sync_state_machine.shared_state.robot_status.trigger_event(RobotStatus.Home)

    event_handler.event.trigger_event(True)
    transition = event_handler.handler(event_handler.event)

    assert transition is sync_state_machine.go_to_home  # type: ignore
    transition()
    assert sync_state_machine.state is sync_state_machine.home_state.name  # type: ignore


def test_recharging_goes_to_home_when_battery_high(
    sync_state_machine: StateMachine,
) -> None:
    recharging_state: EventHandlerBase = cast(
        EventHandlerBase, sync_state_machine.recharging_state
    )
    event_handler: Optional[EventHandlerMapping] = (
        recharging_state.get_event_handler_by_name("robot_battery_update_event")
    )

    assert event_handler is not None

    event_handler.event.trigger_event(99.9)
    transition = event_handler.handler(event_handler.event)

    assert transition is sync_state_machine.robot_recharged  # type: ignore
