"""@sealvera.audit decorator — auto-logs function results."""

import functools
import traceback
from typing import Callable, Optional


def audit(
    action: str = None,
    agent: str = None,
    decision_fn: Callable = None,
    client=None,
):
    """
    Decorator that automatically logs the result of a function to SealVera.

    Args:
        action:      Log action name. Defaults to the function name.
        agent:       Override agent name for this entry.
        decision_fn: Function(return_value) -> decision string.
                     Defaults to COMPLETED on success, FAILED on exception.
        client:      SealVera client instance (uses default if omitted).

    Usage:
        @sealvera.audit(action="process_payment")
        def process_payment(amount, customer_id):
            return {"status": "ok", "tx_id": "123"}

        # Custom decision logic:
        @sealvera.audit(
            action="classify_content",
            decision_fn=lambda r: "APPROVED" if r["safe"] else "REJECTED"
        )
        def classify(text):
            return {"safe": True, "score": 0.1}

        # Async functions supported:
        @sealvera.audit(action="fetch_data")
        async def fetch(url):
            return await httpx.get(url)
    """
    import asyncio

    def decorator(fn):
        _action = action or fn.__name__

        @functools.wraps(fn)
        def sync_wrapper(*args, **kwargs):
            _client = client
            if _client is None:
                from . import _default_client
                _client = _default_client

            input_data = _build_input(fn, args, kwargs)
            try:
                result = fn(*args, **kwargs)
                decision = decision_fn(result) if decision_fn else "COMPLETED"
                _client.log(
                    action=_action,
                    decision=decision,
                    agent=agent,
                    input=input_data,
                    output=result if isinstance(result, dict) else {"value": str(result)[:500]},
                    reasoning=[{"factor": "outcome", "value": "success", "signal": "safe",
                                "explanation": f"{_action} completed without error"}],
                )
                return result
            except Exception as e:
                _client.log(
                    action=_action,
                    decision="FAILED",
                    agent=agent,
                    input=input_data,
                    output={"error": str(e), "type": type(e).__name__},
                    reasoning=[{"factor": "exception", "value": type(e).__name__,
                                "signal": "block", "explanation": str(e)[:300]}],
                )
                raise

        @functools.wraps(fn)
        async def async_wrapper(*args, **kwargs):
            _client = client
            if _client is None:
                from . import _default_client
                _client = _default_client

            input_data = _build_input(fn, args, kwargs)
            try:
                result = await fn(*args, **kwargs)
                decision = decision_fn(result) if decision_fn else "COMPLETED"
                _client.log(
                    action=_action,
                    decision=decision,
                    agent=agent,
                    input=input_data,
                    output=result if isinstance(result, dict) else {"value": str(result)[:500]},
                    reasoning=[{"factor": "outcome", "value": "success", "signal": "safe",
                                "explanation": f"{_action} completed without error"}],
                )
                return result
            except Exception as e:
                _client.log(
                    action=_action,
                    decision="FAILED",
                    agent=agent,
                    input=input_data,
                    output={"error": str(e), "type": type(e).__name__},
                    reasoning=[{"factor": "exception", "value": type(e).__name__,
                                "signal": "block", "explanation": str(e)[:300]}],
                )
                raise

        if asyncio.iscoroutinefunction(fn):
            return async_wrapper
        return sync_wrapper

    return decorator


def _build_input(fn, args, kwargs) -> dict:
    """Build a clean input dict from function args."""
    try:
        import inspect
        sig    = inspect.signature(fn)
        params = list(sig.parameters.keys())
        bound  = {}
        for i, arg in enumerate(args):
            if i < len(params):
                val = arg
                # Don't log self/cls
                if params[i] in ("self", "cls"):
                    continue
                bound[params[i]] = str(val)[:200] if not isinstance(val, (str, int, float, bool, type(None))) else val
        for k, v in kwargs.items():
            bound[k] = str(v)[:200] if not isinstance(v, (str, int, float, bool, type(None))) else v
        return bound
    except Exception:
        return {}
