"""MCP discovery tools for node specifications.

LLMs call these tools first to learn the available node-type catalog and
each node's property schema before composing or modifying a workflow.
"""

from fastapi import HTTPException

from api.mcp_server.auth import authenticate_mcp_request
from api.mcp_server.tracing import traced_tool
from api.services.workflow.node_specs import SPEC_VERSION, all_specs, get_spec


@traced_tool
async def list_node_types() -> dict:
    """List every available node type with a brief summary.

    Use this first to discover what nodes exist, then call `get_node_type`
    for the full schema of any node you intend to use.

    Returns:
        A dict with `spec_version` (pin against this in any generated workflow
        code) and `node_types` (list of {name, display_name, description,
        category}).
    """
    await authenticate_mcp_request()
    return {
        "spec_version": SPEC_VERSION,
        "node_types": [
            {
                "name": spec.name,
                "display_name": spec.display_name,
                "description": spec.description,
                "category": spec.category.value,
            }
            for spec in all_specs()
        ],
    }


@traced_tool
async def get_node_type(name: str) -> dict:
    """Fetch the authoring schema for a node type: each property's name,
    type, default, requiredness, enum options, validation bounds, and
    LLM-readable description, plus worked examples and graph constraints.

    UI-only metadata (display labels, placeholders, conditional visibility
    rules, renderer hints) is intentionally omitted — set only the fields
    you need. Use the property `description`/`llm_hint` and the `examples`
    list to understand semantics; types alone are not enough.
    """
    await authenticate_mcp_request()
    spec = get_spec(name)
    if spec is None:
        raise HTTPException(status_code=404, detail=f"Unknown node type: {name!r}")
    return spec.to_mcp_dict()
