"""Obol interceptor for AutoGen (Microsoft).

Patches ConversableAgent to capture function calls and tool executions.

Usage:
    from obol.interceptors import autogen
    autogen.install()

    # Then use AutoGen normally - all function calls are logged
"""
import functools
from obol.interceptors._base import send_event, _content_hash

_installed = False
_original_execute_function = None
_original_generate_reply = None


def _traced_execute_function(original):
    """Create a traced version of execute_function."""
    @functools.wraps(original)
    def wrapper(self, func_call, *args, **kwargs):
        func_name = "unknown"
        func_args = {}

        # Extract function info based on AutoGen's different versions
        if isinstance(func_call, dict):
            func_name = func_call.get("name", "unknown")
            func_args = func_call.get("arguments", {})
        elif hasattr(func_call, "name"):
            func_name = func_call.name
            func_args = getattr(func_call, "arguments", {})

        # Log function start
        send_event(
            platform="autogen",
            action=f"Function.{func_name}",
            target=_content_hash(func_args),
            result="pending",
            metadata={
                "function_name": func_name,
                "agent_name": getattr(self, "name", "unknown"),
                "args_hash": _content_hash(func_args),
            }
        )

        try:
            result = original(self, func_call, *args, **kwargs)

            # Log function success
            send_event(
                platform="autogen",
                action=f"Function.{func_name}",
                target=_content_hash(func_args),
                result="success",
                metadata={
                    "function_name": func_name,
                    "agent_name": getattr(self, "name", "unknown"),
                    "output_size": len(str(result)) if result else 0,
                }
            )

            return result

        except Exception as e:
            # Log function error
            send_event(
                platform="autogen",
                action=f"Function.{func_name}",
                target=_content_hash(func_args),
                result="error",
                metadata={
                    "function_name": func_name,
                    "agent_name": getattr(self, "name", "unknown"),
                    "error_type": type(e).__name__,
                    "error_message": str(e)[:500],
                }
            )
            raise

    return wrapper


def _traced_generate_reply(original):
    """Create a traced version of generate_reply to capture tool calls in responses."""
    @functools.wraps(original)
    def wrapper(self, messages=None, sender=None, **kwargs):
        agent_name = getattr(self, "name", "unknown")

        # Log agent turn start
        send_event(
            platform="autogen",
            action="Agent.generate_reply",
            target=agent_name,
            result="pending",
            metadata={
                "agent_name": agent_name,
                "message_count": len(messages) if messages else 0,
                "sender": getattr(sender, "name", str(sender)) if sender else None,
            }
        )

        try:
            result = original(self, messages=messages, sender=sender, **kwargs)

            # Check if result contains function calls
            tool_calls = []
            if isinstance(result, dict):
                if "function_call" in result:
                    tool_calls.append(result["function_call"].get("name", "unknown"))
                if "tool_calls" in result:
                    for tc in result.get("tool_calls", []):
                        if isinstance(tc, dict):
                            tool_calls.append(tc.get("function", {}).get("name", "unknown"))

            # Log agent turn success
            send_event(
                platform="autogen",
                action="Agent.generate_reply",
                target=agent_name,
                result="success",
                metadata={
                    "agent_name": agent_name,
                    "tool_calls": tool_calls,
                    "tool_call_count": len(tool_calls),
                    "response_type": type(result).__name__,
                }
            )

            return result

        except Exception as e:
            # Log agent turn error
            send_event(
                platform="autogen",
                action="Agent.generate_reply",
                target=agent_name,
                result="error",
                metadata={
                    "agent_name": agent_name,
                    "error_type": type(e).__name__,
                    "error_message": str(e)[:500],
                }
            )
            raise

    return wrapper


def install():
    """Install the AutoGen interceptor.

    Patches ConversableAgent methods to capture all function calls.
    Safe to call multiple times.
    """
    global _installed, _original_execute_function, _original_generate_reply

    if _installed:
        return

    # Try both autogen and pyautogen package names
    ConversableAgent = None
    try:
        from autogen import ConversableAgent
    except ImportError:
        try:
            from pyautogen import ConversableAgent
        except ImportError:
            return  # AutoGen not installed

    # Patch execute_function (handles function/tool calls)
    for method_name in ("execute_function", "_execute_function", "execute_function_call"):
        if hasattr(ConversableAgent, method_name):
            _original_execute_function = getattr(ConversableAgent, method_name)
            setattr(ConversableAgent, method_name, _traced_execute_function(_original_execute_function))
            break

    # Patch generate_reply (captures which tools the LLM chose)
    if hasattr(ConversableAgent, "generate_reply"):
        _original_generate_reply = ConversableAgent.generate_reply
        ConversableAgent.generate_reply = _traced_generate_reply(_original_generate_reply)

    _installed = True


def uninstall():
    """Remove the AutoGen interceptor."""
    global _installed, _original_execute_function, _original_generate_reply

    if not _installed:
        return

    try:
        from autogen import ConversableAgent
    except ImportError:
        try:
            from pyautogen import ConversableAgent
        except ImportError:
            return

    # Restore originals
    for method_name in ("execute_function", "_execute_function", "execute_function_call"):
        if hasattr(ConversableAgent, method_name) and _original_execute_function:
            setattr(ConversableAgent, method_name, _original_execute_function)
            break

    if _original_generate_reply:
        ConversableAgent.generate_reply = _original_generate_reply

    _installed = False


def is_installed():
    """Check if the interceptor is currently installed."""
    return _installed
