"""
LangChain integration for Risicare SDK.

Provides two complementary instrumentation mechanisms:

1. **Auto-injection** (via import hooks): Patches Runnable.invoke/ainvoke/stream
   to automatically inject RisicareCallbackHandler into all chain executions.

2. **Manual callback**: Users can directly pass RisicareCallbackHandler to any
   LangChain chain for explicit instrumentation.

Usage (automatic — zero config):
    import risicare
    risicare.init(api_key="rsk-...")
    from langchain_core.runnables import RunnableSequence
    chain.invoke(input)  # Automatically traced

Usage (explicit callback):
    from risicare.integrations.langchain import RisicareCallbackHandler
    chain.invoke(input, config={"callbacks": [RisicareCallbackHandler()]})
"""

from __future__ import annotations

import logging
import threading
from typing import Any

logger = logging.getLogger(__name__)

_instrumented = False
_lock = threading.RLock()


def instrument_langchain(module: Any) -> None:
    """
    Apply instrumentation to LangChain module.

    Called by the import hook system when `langchain` or `langchain_core`
    is imported. Patches Runnable.invoke/ainvoke/stream to auto-inject
    the Risicare callback handler.

    Args:
        module: The langchain or langchain_core module.
    """
    global _instrumented
    if _instrumented:
        return

    with _lock:
        if _instrumented:
            return
        # Set True BEFORE patching: if wrapt triggers a re-entrant call the
        # outer check above will return immediately, preventing double-patching.
        # RLock ensures the same thread can re-acquire without deadlocking.
        _instrumented = True
        try:
            from risicare.integrations._base import check_version_compatibility

            check_version_compatibility("langchain")
            check_version_compatibility("langchain-core")

            from risicare.integrations.langchain._patches import patch_langchain

            patch_langchain(module)
            logger.debug("Instrumented LangChain")
        except Exception as e:
            _instrumented = False  # Rollback: allow retry on next import
            logger.debug(f"Failed to instrument LangChain: {e}")


# Lazy re-export for convenience
def __getattr__(name: str) -> Any:
    if name == "RisicareCallbackHandler":
        from risicare.integrations.langchain._callback import RisicareCallbackHandler

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