from __future__ import annotations

from typing import TYPE_CHECKING, List

from aasm.intermediate.action import ModifySelfAction, SendMessageAction
from aasm.utils.validation import is_valid_name, print_invalid_names

if TYPE_CHECKING:
    from aasm.parsing.state import State


def op_ACTION(state: State, name: str, category: str, args: List[str]) -> None:
    state.require(
        state.in_behaviour, 
        'Actions must be definied inside behaviours.', 
        'Try defining new behaviours using BEHAV.'
    )
    state.require(
        not state.in_action, 
        'Cannot define an action in another action.', 
        'Try finishing current action using EACTION.'
    )
    state.require(not state.last_behaviour.action_exists(name), f'Action {name} already exists in current behaviour.')
    state.require(
        is_valid_name(name), 
        f'{name} is not a correct name.', 
        f'Names can only contain alphanumeric characters, underscores and cannot be: {print_invalid_names()}.'
    )
    
    match category, args:
        case 'modify_self', [ ]:
            state.last_behaviour.add_action(ModifySelfAction(name))
            
        case 'send_msg', [ msg_type, msg_performative ]:
            state.require(
                state.message_exists(msg_type, msg_performative), 
                f'Message {msg_type}/{msg_performative} does not exist.', 
                'Try defining new messages using MESSAGE.'
            )

            state.last_behaviour.add_action(SendMessageAction(name, state.get_message_instance(msg_type, msg_performative)))
            
        case _:
            state.panic(f'Incorrect operation: ACTION {category} {args}')
    
    state.in_action = True


def op_EACTION(state: State) -> None:            
    state.require(state.in_action, 'Not inside any action.', 'Try defining new actions using ACTION.')
    state.require(
        state.last_action.nested_blocks_count == 0, 
        'There are unclosed blocks.', 
        'Try closing them using EBLOCK.'
    )
    
    state.in_action = False
