"""
matrice_vss.agents
==================
Agent layer: query routing, SQL generation & execution, VLM inference,
and final response composition.

All agents are designed as **LangGraph node functions** — each receives a
:class:`~orchestration.state.VSSState` dict, mutates it, and returns it.
They can also be used standalone (e.g. in unit tests) by constructing their
class instances directly.

Agents
------
``routing_agent`` — :class:`RoutingAgent` / :func:`classify_intent`
    Classifies a user query as ``"sql"`` or ``"vlm"`` using:

    1. Rule-based regex patterns (high confidence → skip LLM).
    2. LLM-based classification via Ollama/vLLM (ambiguous queries).

``sql_agent`` — :class:`SQLAgent` / :func:`process_sql` / :func:`ask_sql_agent`
    Multi-step LangGraph pipeline: intent routing → table discovery →
    schema loading → SQL generation → SQL checking → execution →
    retry → answer finalization.  All SQL is read-only (SELECT/WITH only).

``vlm_agent`` — :class:`VLMAgent` / :func:`process_vlm`
    Sends the uploaded image to Cosmos-Reason2-8B via the vLLM
    OpenAI-compatible API and returns a natural-language description.

``response_composer`` — :class:`ResponseComposer` / :func:`compose_response`
    Selects the correct final-response assembly strategy (SQL pass-through,
    VLM prose, escalation wrapper, or fallback) and writes the result to
    ``state["final_response"]``.

LangGraph node signatures
-------------------------
All public node functions share the same signature::

    async def <name>(state: VSSState) -> VSSState

Usage
-----
.. code-block:: python

    # Via orchestrator (recommended)
    from orchestration.graph import VSSOrchestrator
    state = await VSSOrchestrator().run(query="How many alerts yesterday?")

    # Standalone SQL helper
    from agents.sql_agent import ask_sql_agent
    result = ask_sql_agent("What are the top 5 incident types last week?")

    # Direct LangGraph node invocation (testing)
    from agents.routing_agent import classify_intent
    from orchestration.state import create_state
    state = create_state("How many vehicles passed yesterday?")
    state = await classify_intent(state)
"""

from __future__ import annotations

from typing import TYPE_CHECKING


def __getattr__(name: str):  # noqa: N807
    """Lazy-load public symbols from child modules on first access."""
    import importlib

    _symbol_map: dict[str, str] = {
        # routing_agent
        "RoutingAgent": "routing_agent",
        "classify_intent": "routing_agent",
        # sql_agent
        "AgentConfig": "sql_agent",
        "AgentState": "sql_agent",
        "SQLAgent": "sql_agent",
        "SQLAgentToolkit": "sql_agent",
        "CustomQueryTool": "sql_agent",
        "CustomSchemaTool": "sql_agent",
        "CustomListTablesTool": "sql_agent",
        "CustomQueryCheckerTool": "sql_agent",
        "IntentDecision": "sql_agent",
        "TableSelection": "sql_agent",
        "sanitize_sql": "sql_agent",
        "reduce_sql_result": "sql_agent",
        "ask_sql_agent": "sql_agent",
        "process_sql": "sql_agent",
        # vlm_agent
        "VLMAgent": "vlm_agent",
        "process_vlm": "vlm_agent",
        # response_composer
        "ResponseComposer": "response_composer",
        "compose_response": "response_composer",
    }

    if name in _symbol_map:
        module = importlib.import_module(
            f".{_symbol_map[name]}", package=__name__
        )
        value = getattr(module, name)
        globals()[name] = value
        return value

    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


if TYPE_CHECKING:  # pragma: no cover
    from .routing_agent import RoutingAgent, classify_intent  # noqa: F401
    from .sql_agent import (  # noqa: F401
        AgentConfig,
        AgentState,
        CustomListTablesTool,
        CustomQueryCheckerTool,
        CustomQueryTool,
        CustomSchemaTool,
        IntentDecision,
        SQLAgent,
        SQLAgentToolkit,
        TableSelection,
        ask_sql_agent,
        process_sql,
        reduce_sql_result,
        sanitize_sql,
    )
    from .vlm_agent import VLMAgent, process_vlm  # noqa: F401
    from .response_composer import ResponseComposer, compose_response  # noqa: F401

__all__: list[str] = [
    # routing_agent
    "RoutingAgent",
    "classify_intent",
    # sql_agent — configuration & state
    "AgentConfig",
    "AgentState",
    # sql_agent — tools & toolkit
    "SQLAgentToolkit",
    "CustomQueryTool",
    "CustomSchemaTool",
    "CustomListTablesTool",
    "CustomQueryCheckerTool",
    # sql_agent — pydantic schemas
    "IntentDecision",
    "TableSelection",
    # sql_agent — main class & helpers
    "SQLAgent",
    "sanitize_sql",
    "reduce_sql_result",
    # sql_agent — public entry-points
    "ask_sql_agent",
    "process_sql",
    # vlm_agent
    "VLMAgent",
    "process_vlm",
    # response_composer
    "ResponseComposer",
    "compose_response",
]
