import re
from typing import Any

from a2a.server.agent_execution import RequestContext
from a2a.types import (
    SendMessageResponse,
    SendMessageSuccessResponse,
    Message,
)

from a2a_acl.protocol_extension import A2A_ACL_PROTOCOL_URI, MIME_TAG
from a2a_acl.protocol_extension.acl_message import ACLIncomingMessage


def check_illocution_regexpr(i: str) -> bool:
    """An illocution starts with a lowercase letter, and contains only lowercase letters and dash '-' character."""
    return bool(re.fullmatch(r"[a-z][a-z-]*", i))


def add_illocution(m: Message, i: str, codec: str) -> Message:
    """Add an illocution to a message with the ACL extension.
    The message is modified."""
    assert check_illocution_regexpr(i)
    if m.extensions is None:
        m.extensions = []
    if m.metadata is None:
        m.metadata = {}
    md: dict[str, Any] = {
        "illocution": i,
        "codec": codec,
        "mediaType": MIME_TAG,
    }
    m.extensions.append(A2A_ACL_PROTOCOL_URI)
    m.metadata[A2A_ACL_PROTOCOL_URI] = md
    return m


def extract_text(response: SendMessageResponse):
    """Extract text from synchronous replies"""
    if isinstance(response, SendMessageResponse):
        if isinstance(response.root, SendMessageSuccessResponse):
            if isinstance(response.root.result, Message):
                return response.root.result.parts[0].root.text
            else:
                print(
                    "Warning: Result of type: "
                    + str(type(response.root.result))
                    + " instead of Message."
                )
        else:
            print(
                "Warning: Root of type: "
                + str(type(response.root))
                + " instead of SendMessageSuccessResponse."
            )
    else:
        print(
            "Warning: Response of type: "
            + str(type(response))
            + " instead of SendMessageResponse."
        )

    return response.model_dump(mode="json", exclude_none=True)


def extract_illocution(context: RequestContext):
    return context.message.metadata[A2A_ACL_PROTOCOL_URI]["illocution"]


def extract_codec(context: RequestContext):
    return context.message.metadata[A2A_ACL_PROTOCOL_URI]["codec"]


def acl_of_a2a(context: RequestContext) -> ACLIncomingMessage:
    if (context.configuration is None) or (
        context.configuration.push_notification_config is None
    ):
        sender = None
    else:
        sender = context.configuration.push_notification_config.url
    if (
        context.message.metadata is None
        or A2A_ACL_PROTOCOL_URI not in context.message.metadata
    ):
        error_message = "Incoming message not in BDI format (missing metadata)."
        print(error_message)
        raise Exception(error_message)
    else:
        i = extract_illocution(context)
        c = extract_codec(context)
        content = context.get_user_input()

        return ACLIncomingMessage(
            i, content, sender, c, task_id=context.message.task_id, origin=context
        )
