from dataclasses import dataclass, field
from typing import Any, Literal


ProtocolName = Literal[
    "source_extract",
    "email_read",
    "email_write",
    "calendar_read",
    "calendar_write",
    "search_read",
    "code_change",
    "general_agent",
]
ExecutionMode = Literal["simple", "direct", "agent"]
_LIVE_TASK_STATE_DOMAINS = {"email", "calendar", "search"}


_CODE_CHANGE_RE = __import__("re").compile(
    r"\b(?:fix|fixen|bug|debug|implement|build|create|add|edit|change|update|bijwerk\w*|refactor|rewrite|patch|test|tests|failing test|code|repo|repository|workspace|bestand|file|files|module|functie|function|class|script|component|backend|frontend|python|pytest)\b",
    __import__("re").IGNORECASE,
)


def _looks_like_code_change_request(goal: str) -> bool:
    value = str(goal or "").strip()
    if not value:
        return False
    if not _CODE_CHANGE_RE.search(value):
        return False
    return bool(
        __import__("re").search(
            r"\b(?:fix|fixen|debug|implement|build|create|add|edit|change|update|bijwerk\w*|refactor|rewrite|patch|write|maak|wijzig|pas aan|verbeter|test)\b",
            value,
            __import__("re").IGNORECASE,
        )
    )


def _task_state_domain(task_state: dict | None) -> str:
    task = dict(task_state or {})
    task_type = str(task.get("task_type") or "").strip().lower()
    if task_type in {"email_lookup", "email_action"}:
        return "email"
    if task_type in {"calendar_lookup", "calendar_action"}:
        return "calendar"
    if task_type == "search_lookup":
        return "search"
    return "generic"


def scope_task_state_to_domain(task_state: dict | None, domain: str) -> dict | None:
    normalized_domain = str(domain or "").strip().lower()
    if normalized_domain not in _LIVE_TASK_STATE_DOMAINS:
        return None
    if not isinstance(task_state, dict):
        return None
    if _task_state_domain(task_state) != normalized_domain:
        return None
    return task_state


def _domain_from_direct_intent(direct_intent: dict | None) -> str:
    intent_name = str((direct_intent or {}).get("intent") or "").strip().lower()
    if intent_name in {"inbox_read", "email_search"}:
        return "email"
    if intent_name == "calendar_read":
        return "calendar"
    if intent_name == "search_lookup":
        return "search"
    return "generic"


@dataclass(slots=True)
class ProtocolRoute:
    protocol: ProtocolName
    mode: ExecutionMode
    domain: str
    reason: str = ""
    requires_live_data: bool = False
    followup_relation: str = ""
    task_type: str = ""
    side_effect: bool = False
    metadata: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        return {
            "protocol": self.protocol,
            "mode": self.mode,
            "domain": self.domain,
            "reason": self.reason,
            "requires_live_data": self.requires_live_data,
            "followup_relation": self.followup_relation,
            "task_type": self.task_type,
            "side_effect": self.side_effect,
            "metadata": dict(self.metadata),
        }


def resolve_protocol_route(
    goal: str,
    *,
    task_state: dict | None = None,
    email_action_request: bool = False,
    calendar_action_request: bool = False,
    forced_extract: bool = False,
) -> ProtocolRoute:
    task = dict(task_state or {})
    domain = _task_state_domain(task)
    followup_relation = str(task.get("followup_relation") or "")
    task_type = str(task.get("task_type") or "")
    requires_live_data = bool(task.get("requires_live_data", False))

    if forced_extract:
        return ProtocolRoute(
            protocol="source_extract",
            mode="simple",
            domain="content",
            reason="forced_source_extraction",
            requires_live_data=True,
            metadata={"goal": goal},
        )

    if task_type == "email_action":
        return ProtocolRoute(
            protocol="email_write",
            mode="direct",
            domain="email",
            reason="task_state_email_action",
            requires_live_data=True,
            followup_relation=followup_relation,
            task_type=task_type,
            side_effect=True,
        )

    if task_type == "calendar_action":
        return ProtocolRoute(
            protocol="calendar_write",
            mode="direct",
            domain="calendar",
            reason="task_state_calendar_action",
            requires_live_data=True,
            followup_relation=followup_relation,
            task_type=task_type,
            side_effect=True,
        )

    if email_action_request:
        return ProtocolRoute(
            protocol="email_write",
            mode="direct",
            domain="email",
            reason="email_action_request",
            requires_live_data=True,
            followup_relation=followup_relation,
            task_type=task_type,
            side_effect=True,
        )

    if _looks_like_code_change_request(goal):
        return ProtocolRoute(
            protocol="code_change",
            mode="agent",
            domain="code",
            reason="code_change_request",
            requires_live_data=False,
            metadata={"goal": goal},
        )

    if calendar_action_request:
        return ProtocolRoute(
            protocol="calendar_write",
            mode="direct",
            domain="calendar",
            reason="calendar_action_request",
            requires_live_data=True,
            followup_relation=followup_relation,
            task_type=task_type,
            side_effect=True,
        )

    if requires_live_data and domain == "email":
        return ProtocolRoute(
            protocol="email_read",
            mode="direct",
            domain="email",
            reason="task_state_email_lookup",
            requires_live_data=True,
            followup_relation=followup_relation,
            task_type=task_type,
        )
    if requires_live_data and domain == "calendar":
        return ProtocolRoute(
            protocol="calendar_read",
            mode="direct",
            domain="calendar",
            reason="task_state_calendar_lookup",
            requires_live_data=True,
            followup_relation=followup_relation,
            task_type=task_type,
        )
    if requires_live_data and domain == "search":
        return ProtocolRoute(
            protocol="search_read",
            mode="direct",
            domain="search",
            reason="task_state_search_lookup",
            requires_live_data=True,
            followup_relation=followup_relation,
            task_type=task_type,
        )

    return ProtocolRoute(
        protocol="general_agent",
        mode="agent",
        domain=domain,
        reason="fallback_agent_orchestrator",
        requires_live_data=requires_live_data,
        followup_relation=followup_relation,
        task_type=task_type,
        metadata={"goal": goal},
    )


def refine_protocol_route(
    route: ProtocolRoute,
    *,
    task_state: dict | None = None,
    direct_intent: dict | None = None,
) -> ProtocolRoute:
    if route.protocol != "general_agent" and route.domain != "generic":
        return route

    domain = _task_state_domain(task_state)
    if domain == "generic":
        domain = _domain_from_direct_intent(direct_intent)

    if domain == "email":
        return ProtocolRoute(
            protocol="email_read",
            mode="direct",
            domain="email",
            reason="refined_from_direct_intent",
            requires_live_data=True,
        )
    if domain == "calendar":
        return ProtocolRoute(
            protocol="calendar_read",
            mode="direct",
            domain="calendar",
            reason="refined_from_direct_intent",
            requires_live_data=True,
        )
    if domain == "search":
        return ProtocolRoute(
            protocol="search_read",
            mode="direct",
            domain="search",
            reason="refined_from_direct_intent",
            requires_live_data=True,
        )
    return route