"""Obol interceptor for the OpenAI Agents SDK (openai-agents package).

Provides ObolRunHooks that plug into the Agents SDK's RunHooks interface
to detect threats before tool execution and log events after completion.

Usage:
    from obol.interceptors.openai_agents import ObolRunHooks
    from agents import Runner

    hooks = ObolRunHooks()
    result = await Runner.run(agent, input="...", hooks=hooks)

    # Or with custom enforcement mode override:
    hooks = ObolRunHooks(enforcement_mode="alert")
"""
from obol.interceptors._base import send_event, run_detection, ObolSecurityBlock


def _safe_tool_name(tool):
    """Extract tool name safely."""
    try:
        return getattr(tool, "name", None) or type(tool).__name__
    except Exception:
        return "unknown"


def _safe_agent_name(agent):
    """Extract agent name safely."""
    try:
        return getattr(agent, "name", None) or type(agent).__name__
    except Exception:
        return "unknown"


class ObolRunHooks:
    """RunHooks implementation for Obol security monitoring.

    Runs the on-device detection engine before every tool execution.
    In enforce mode, raises ObolSecurityBlock to prevent dangerous calls.
    In audit/alert mode, logs detections without blocking.

    Compatible with the openai-agents RunHooks protocol:
        on_tool_start(context, agent, tool) -> None
        on_tool_end(context, agent, tool, result) -> None

    Also implements optional lifecycle hooks if available:
        on_agent_start(context, agent) -> None
        on_agent_end(context, agent, output) -> None
    """

    def __init__(self, enforcement_mode=None):
        """Initialize hooks.

        Args:
            enforcement_mode: Override config enforcement_mode.
                None = read from ~/.obol/config.json (default).
                "audit" / "alert" / "enforce" = force this mode.
        """
        self._enforcement_mode = enforcement_mode

    async def on_tool_start(self, context, agent, tool):
        """Called before each tool execution. Runs detection, may block."""
        tool_name = _safe_tool_name(tool)
        agent_name = _safe_agent_name(agent)

        # Extract arguments from context
        args = ""
        try:
            args = getattr(context, "tool_arguments", "") or ""
            if not isinstance(args, str):
                try:
                    import json
                    args = json.dumps(args, default=str)
                except Exception:
                    args = str(args)
        except Exception:
            pass

        # Run detection
        try:
            flags, ml_score, blocked = run_detection(tool_name, args)

            # Override blocked based on local enforcement_mode if set
            if self._enforcement_mode is not None and flags:
                if self._enforcement_mode != "enforce":
                    blocked = False
                elif not blocked:
                    # Re-evaluate with forced enforce
                    try:
                        from obol.hooks.detection import should_alert
                        blocked = should_alert(flags)
                    except ImportError:
                        pass

            if blocked:
                send_event(
                    platform="openai-agents",
                    action=f"Tool.{tool_name}",
                    target=args[:500] if args else None,
                    result="blocked",
                    detected_patterns=flags,
                    metadata={
                        "agent_name": agent_name,
                        "ml_score": ml_score,
                        "enforcement": "enforce",
                    }
                )
                raise ObolSecurityBlock(tool_name, args, flags, ml_score)

            if flags:
                send_event(
                    platform="openai-agents",
                    action=f"Tool.{tool_name}",
                    target=args[:500] if args else None,
                    result="flagged",
                    detected_patterns=flags,
                    metadata={
                        "agent_name": agent_name,
                        "ml_score": ml_score,
                    }
                )
        except ObolSecurityBlock:
            raise
        except Exception:
            pass  # Detection failure must never block execution

    async def on_tool_end(self, context, agent, tool, result):
        """Called after each tool execution. Logs the event."""
        tool_name = _safe_tool_name(tool)
        agent_name = _safe_agent_name(agent)

        try:
            result_str = str(result) if result is not None else ""
            send_event(
                platform="openai-agents",
                action=f"Tool.{tool_name}",
                target=None,
                result="success",
                metadata={
                    "agent_name": agent_name,
                    "output_size": len(result_str),
                }
            )
        except Exception:
            pass

    async def on_agent_start(self, context, agent):
        """Called when an agent run begins."""
        agent_name = _safe_agent_name(agent)
        try:
            send_event(
                platform="openai-agents",
                action=f"Agent.{agent_name}.start",
                result="pending",
                metadata={"agent_name": agent_name}
            )
        except Exception:
            pass

    async def on_agent_end(self, context, agent, output):
        """Called when an agent run completes."""
        agent_name = _safe_agent_name(agent)
        try:
            send_event(
                platform="openai-agents",
                action=f"Agent.{agent_name}.end",
                result="success",
                metadata={
                    "agent_name": agent_name,
                    "output_size": len(str(output)) if output else 0,
                }
            )
        except Exception:
            pass
