import functools
import inspect
from typing import Optional, Callable
from .client import Anchor8Client

_GLOBAL_CLIENT: Optional[Anchor8Client] = None

def get_global_client() -> Anchor8Client:
    global _GLOBAL_CLIENT
    if _GLOBAL_CLIENT is None:
        _GLOBAL_CLIENT = Anchor8Client() # Relies on env vars
    return _GLOBAL_CLIENT

def instrument(
    tool_name: str,
    agent_id: str = "default-agent",
    client: Optional[Anchor8Client] = None,
    abort_on_block: bool = True
):
    """
    Decorator to instrument a function with Anchor8 Guard.

    Args:
        tool_name: The name of the tool/activity being performed.
        agent_id: Identifier for the agent.
        client: Optional Anchor8Client instance. Note: It's better to use env vars.
        abort_on_block: If True, raises PermissionError on block. If False, returns None.
    """
    def decorator(func: Callable):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            nonlocal client
            if client is None:
                try:
                    client = get_global_client()
                except ValueError:
                    # If we can't create a client (e.g. no api key), what do we do?
                    # For now, let's log and pass through, or fail?
                    # README says "Fail-closed error handling in security workers".
                    # But here in SDK, maybe we raise.
                    raise RuntimeError("Anchor8 SDK not configured. Set ANCHOR8_API_KEY.")

            # Capture arguments
            sig = inspect.signature(func)
            bound_args = sig.bind(*args, **kwargs)
            bound_args.apply_defaults()
            func_args = dict(bound_args.arguments)

            # Check
            allowed, reason, modified_args = client.check(
                agent_id=agent_id,
                tool_name=tool_name,
                arguments=func_args
            )

            if not allowed:
                if abort_on_block:
                    raise PermissionError(f"Anchor8 Guard Blocked: {reason}")
                return None

            # Apply modifications if any
            if modified_args:
                # Update bound_args with modified_args
                for k, v in modified_args.items():
                    if k in func_args:
                        bound_args.arguments[k] = v

                return func(*bound_args.args, **bound_args.kwargs)

            # Run Log (async/fire-and-forget style call in client)
            # Maybe we log AFTER execution to capture success/failure?
            # The current API implies request logging vs audit.
            # Guard check logs the attempt.
            # We can log the result if we want.

            result = func(*args, **kwargs)

            # Optional: Log success
            try:
                client.log(
                    agent_id=agent_id,
                    tool_name=tool_name,
                    metadata={"status": "success", "function": func.__name__}
                )
            except:
                pass

            return result

        return wrapper
    return decorator
