"""
Mandatum Framework Integrations

One-line decorators to guard agent actions with Mandatum authorization.

Usage:
    from mandatum import Mandatum
    from mandatum.integrations import mandatum_guard, MandatumMiddleware

    m = Mandatum(api_key="mdt_live_...")

    # Decorator — wraps any function with spending check
    @mandatum_guard(m, agent_id="agt_abc123", action="payments:execute")
    def buy_groceries(items, budget):
        return razorpay.order.create({"amount": budget * 100, "currency": "INR"})

    result = buy_groceries(["milk", "bread"], 500)
    # If budget > agent limit → raises MandatumBlocked
    # If within limit → executes normally + records spending

    # Context manager — for inline spending checks
    with MandatumGuard(m, "agt_abc123") as guard:
        guard.check_spend(amount=350, vendor="DigitalOcean")
        # If allowed, continues. If blocked, raises MandatumBlocked.
        do_payment(350)
"""

import functools
from .payments import MandatumRazorpay, MandatumStripe


class MandatumBlocked(Exception):
    """Raised when Mandatum blocks an agent action."""

    def __init__(self, reason, event_id=None, spending=None):
        super().__init__(reason)
        self.reason = reason
        self.event_id = event_id
        self.spending = spending


def mandatum_guard(mandatum_client, agent_id: str, action: str = "spending",
                   amount_arg: str = None, amount_kwarg: str = "amount"):
    """
    Decorator that guards a function with Mandatum spending check.

    The decorator extracts the amount from the function's arguments
    and checks it against the agent's spending limits before executing.

    Args:
        mandatum_client: Initialized Mandatum instance
        agent_id: The agent performing the action
        action: Action type for audit trail
        amount_arg: Position of amount in positional args (e.g., 0 for first arg)
        amount_kwarg: Name of amount keyword argument (default: 'amount')

    Example:
        @mandatum_guard(m, "agt_abc123", action="payments:execute")
        def pay_vendor(vendor_name, amount=0, currency="INR"):
            return process_payment(vendor_name, amount)

        pay_vendor("DigitalOcean", amount=350)
        # → Checks limits first, then executes
    """
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # Extract amount from arguments
            amount = None
            if amount_kwarg and amount_kwarg in kwargs:
                amount = kwargs[amount_kwarg]
            elif amount_arg is not None and len(args) > int(amount_arg):
                amount = args[int(amount_arg)]

            if amount is not None and amount > 0:
                # Check with Mandatum
                result = mandatum_client.agents.spend(agent_id, {
                    "amount": amount,
                    "vendor": func.__name__,
                    "category": action,
                    "description": f"{action}: {func.__name__}({amount})",
                })

                if not result.get("allowed"):
                    raise MandatumBlocked(
                        result.get("reason", "Spending limit exceeded"),
                        event_id=result.get("eventId"),
                        spending=result.get("spending"),
                    )

            return func(*args, **kwargs)
        return wrapper
    return decorator


class MandatumGuard:
    """
    Context manager for inline Mandatum spending checks.

    Usage:
        with MandatumGuard(mandatum_client, "agt_abc123") as guard:
            guard.check_spend(amount=350, vendor="AWS")
            aws.create_instance(...)  # Only runs if spend was allowed
    """

    def __init__(self, mandatum_client, agent_id: str):
        self.mandatum = mandatum_client
        self.agent_id = agent_id

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        return False  # Don't suppress exceptions

    def check_spend(self, amount: float, currency: str = "INR",
                    vendor: str = None, category: str = None):
        """Check and record a spending event. Raises MandatumBlocked if denied."""
        result = self.mandatum.agents.spend(self.agent_id, {
            "amount": amount,
            "currency": currency,
            "vendor": vendor,
            "category": category,
        })

        if not result.get("allowed"):
            raise MandatumBlocked(
                result.get("reason", "Spending limit exceeded"),
                event_id=result.get("eventId"),
                spending=result.get("spending"),
            )

        return result
