"""
LangGraph integration for Risicare SDK.

Patches CompiledGraph.invoke/ainvoke/stream to wrap graph execution
in an AGENT span with graph-specific attributes. Internal node execution
and LLM calls are captured by the LangChain callback handler (if active)
or by provider patches.

Span Hierarchy:
    langgraph.graph/{graph_name}    [AGENT, role=ORCHESTRATOR]
      langgraph.node/{node_name}     [INTERNAL] (via LangChain callback)
        langchain.llm/{model}         [LLM_CALL] (via LC callback or provider)
        langchain.tool/{tool}         [TOOL_CALL] (via LC callback)

Usage (automatic — zero config):
    import risicare
    risicare.init(api_key="rsk-...")
    graph = builder.compile()
    graph.invoke(state)  # Automatically traced
"""

from __future__ import annotations

import logging
import threading
from typing import Any

logger = logging.getLogger(__name__)

_instrumented = False
_lock = threading.Lock()


def instrument_langgraph(module: Any) -> None:
    """
    Apply instrumentation to LangGraph module.

    Called by the import hook system when `langgraph` is imported.
    Patches CompiledGraph.invoke/ainvoke/stream.
    """
    global _instrumented
    if _instrumented:
        return

    with _lock:
        if _instrumented:
            return
        try:
            from risicare.integrations._base import check_version_compatibility

            check_version_compatibility("langgraph")

            from risicare.integrations.langgraph._patches import patch_langgraph

            patch_langgraph(module)
            _instrumented = True
            logger.debug("Instrumented LangGraph")
        except Exception as e:
            logger.debug(f"Failed to instrument LangGraph: {e}")
