from typing import List

import structlog

from rasa.dialogue_understanding.commands import (
    Command,
)

structlogger = structlog.get_logger()


class CommandParserValidatorSingleton:
    """Singleton class to validate the command parser.

    This class is used to validate the command parser. It keeps track of the number of
    consecutive turns where no commands are parsed by the command parser. If the
    number of consecutive turns exceeds a certain threshold, a warning is logged.
    The prompt can use a DSL syntax that can be incompatible with the command syntax
    used by the command parser. This class helps to detect such incompatibilities.
    """

    MAX_CONSECUTIVE_TURNS_NO_COMMAND_PREDICTED = 5
    _NO_COMMAND_PREDICTED_TURN_COUNTER = 0
    _command_parser_validated = False

    @classmethod
    def get_no_command_predicted_turn_counter(cls) -> int:
        return cls._NO_COMMAND_PREDICTED_TURN_COUNTER

    @classmethod
    def should_validate_command_parser(cls) -> bool:
        return not cls._command_parser_validated

    @classmethod
    def reset_command_parser_validation(cls) -> None:
        cls._NO_COMMAND_PREDICTED_TURN_COUNTER = 0
        cls._command_parser_validated = False

    @classmethod
    def validate_if_commands_are_parsed_from_llm_response(
        cls, commands: List[Command], llm_response: str
    ) -> None:
        if llm_response and not commands:
            cls._NO_COMMAND_PREDICTED_TURN_COUNTER += 1
        else:
            # Reset the counter if commands are generated, and mark
            # the command parser as validated.
            cls._NO_COMMAND_PREDICTED_TURN_COUNTER = 0
            cls._command_parser_validated = True
            return

        if (
            cls._NO_COMMAND_PREDICTED_TURN_COUNTER
            >= cls.MAX_CONSECUTIVE_TURNS_NO_COMMAND_PREDICTED
        ):
            structlogger.warning(
                "llm_command_generator.predict_commands.command_parser_not_working",
                event_info=(
                    f"No commands were generated by the command parser for the last "
                    f"{cls._NO_COMMAND_PREDICTED_TURN_COUNTER} times. Check if you "
                    "are running incompatible prompt and LLM command generator."
                ),
            )
