"""The AaC Req QA plugin implementation module."""

# NOTE: It is safe to edit this file.
# This file is only initially generated by aac gen-plugin, and it won't be overwritten if the file already exists.

from aac.context.language_context import LanguageContext
from aac.context.definition import Definition
from aac.execute.aac_execution_result import (
    ExecutionResult,
    ExecutionStatus,
    ExecutionMessage,
    MessageLevel,
)

from aac_req_qa.ai_prompts import (
    REQ_PROMPT_TEMPLATE,
    SPEC_PROMPT_TEMPLATE
)
from aac_req_qa.ai_util import (
    get_client,
    generate,
    get_shall_statement,
    get_spec_summary
)

plugin_name = "Req QA"


def check_req(definition):
    """
    Check if the definition is a requirement.

    Args:
        definition: The definition to be checked.

    Returns:
        An ExecutionResult if the definition is not a requirement, otherwise None.
    """
    if definition.get_root_key() != "req":
        return ExecutionResult(
            plugin_name,
            "eval-req",
            ExecutionStatus.SUCCESS,
            [
                ExecutionMessage(
                    "No req to evaluate",
                    MessageLevel.INFO,
                    definition.source,
                    None,
                )
            ],
        )
    else:
        return None


def check_req_spec(definition):
    """
    Check if the definition is a requirement specification.

    Args:
        definition: The definition to be checked.

    Returns:
        An ExecutionResult if the definition is not a requirement specification, otherwise None.
    """
    if definition.get_root_key() != "req_spec":
        return ExecutionResult(
            plugin_name,
            "eval-spec",
            ExecutionStatus.SUCCESS,
            [
                ExecutionMessage(
                    "No req_spec to evaluate",
                    MessageLevel.INFO,
                    definition.source,
                    None,
                )
            ],
        )
    else:
        return None


def eval_req(architecture_file: str) -> ExecutionResult:
    """
     Business logic for allowing eval-req command to perform Perform AI analysis on requirements and provides feedback on each.

     Args:
         architecture_file (str): A path to a YAML file containing an AaC-defined requirements to evaluate.


    Returns:
         The results of the execution of the eval-req command.
    """
    context = LanguageContext()
    status = ExecutionStatus.SUCCESS
    messages = []
    for definition in context.parse_and_load(architecture_file):
        result = shall_statement_quality(definition)
        if not result.is_success():
            status = ExecutionStatus.GENERAL_FAILURE
        messages.extend(result.messages)

    return ExecutionResult(plugin_name, "eval-req", status, messages)


def eval_spec(architecture_file: str) -> ExecutionResult:
    """
     Business logic for allowing eval-spec command to perform Perform AI analysis on requirement specifications, evaluating each spec as a collection for broader consideration and feedback.

     Args:
         architecture_file (str): A path to a YAML file containing an AaC-defined requirement specification to evaluate.


    Returns:
         The results of the execution of the eval-spec command.
    """
    context = LanguageContext()
    status = ExecutionStatus.SUCCESS
    messages = []
    for definition in context.parse_and_load(architecture_file):
        result = req_spec_quality(definition)
        if not result.is_success():
            status = ExecutionStatus.GENERAL_FAILURE
        messages.extend(result.messages)

    return ExecutionResult(plugin_name, "eval-req", status, messages)


def shall_statement_quality(definition: Definition) -> ExecutionResult:
    """
     Business logic for the Shall statement quality assessment.

     Args:
         definition (Definition): The definition of the instance.

    Returns:
         The results of the execution of the Shall statement quality command.
    """

    # Only evaluate req root keys.
    is_req = check_req(definition)
    if is_req is not None:
        return is_req

    client, model, client_error, error_result = get_client(plugin_name)
    if client_error:
        return error_result

    shall, skip, skip_reason, shall_error, shall_result = get_shall_statement(plugin_name, definition)
    if shall_error:
        return shall_result

    id = getattr(definition.instance, "id", None)

    if skip:
        status = ExecutionStatus.SUCCESS
        messages: list[ExecutionMessage] = []

        success_msg = ExecutionMessage(
            f"Requirement {id} quality check skipped\n\nInput:  {shall}\n\nReason:  {skip_reason}",
            MessageLevel.INFO,
            definition.source,
            None,
        )
        messages.append(success_msg)

        return ExecutionResult(plugin_name, "Shall statement quality", status, messages)

    qa_prompt = f"{REQ_PROMPT_TEMPLATE}\n{shall}"

    result = generate(client, model, qa_prompt)

    if "REQ-QA-PASS" in result:

        status = ExecutionStatus.SUCCESS
        messages: list[ExecutionMessage] = []

        success_msg = ExecutionMessage(
            f"Requirement {id} passed quality check\n\nINPUT:  {shall}\n\n{result}",
            MessageLevel.INFO,
            definition.source,
            None,
        )
        messages.append(success_msg)

        return ExecutionResult(plugin_name, "Shall statement quality", status, messages)

    else:

        status = ExecutionStatus.GENERAL_FAILURE
        messages: list[ExecutionMessage] = []
        error_msg = ExecutionMessage(
            f"Requirement {id} failed quality check\n\nINPUT:  {shall}\n\n{result}",
            MessageLevel.ERROR,
            definition.source,
            None,
        )
        messages.append(error_msg)

        return ExecutionResult(plugin_name, "Shall statement quality", status, messages)


def req_spec_quality(definition: Definition) -> ExecutionResult:
    """
     Business logic for the requirement specification quality assessment.

     Args:
         definition (Definition): The definition of the instance.

    Returns:
         The results of the execution of the requirement specification quality check.
    """

    # Only evaluate req root keys.
    is_req = check_req_spec(definition)
    if is_req is not None:
        return is_req

    client, model, client_error, error_result = get_client(plugin_name)
    if client_error:
        return error_result

    spec_summary, qa_error, qa_result = get_spec_summary(plugin_name, definition)
    if qa_error:
        return qa_result

    spec_name = getattr(definition.instance, "name", None)

    qa_prompt = f"{SPEC_PROMPT_TEMPLATE}\n{spec_summary}"

    result = generate(client, model, qa_prompt)

    print(f"DEBUG:  req_spec_quality:  {result}")

    if "REQ-QA-PASS" in result:

        status = ExecutionStatus.SUCCESS
        messages: list[ExecutionMessage] = []

        success_msg = ExecutionMessage(
            f"Requirement specification {spec_name} passed quality check\n\nINPUT:  {spec_name}\n\n{result}",
            MessageLevel.INFO,
            definition.source,
            None,
        )
        messages.append(success_msg)

        return ExecutionResult(plugin_name, "eval-spec", status, messages)

    else:

        status = ExecutionStatus.GENERAL_FAILURE
        messages: list[ExecutionMessage] = []
        error_msg = ExecutionMessage(
            f"Requirement specification {spec_name} failed quality check\n\nINPUT:  {spec_name}\n\n{result}",
            MessageLevel.ERROR,
            definition.source,
            None,
        )
        messages.append(error_msg)

        return ExecutionResult(plugin_name, "check-spec", status, messages)
