"""FastAPI decorator for x402-style INR paywalls via Amrood."""

from __future__ import annotations

import base64
import functools
import json
import os
from datetime import datetime, timezone, timedelta

from fastapi import Request
from fastapi.responses import JSONResponse

from amrood_paywall.nonce import NonceStore
from amrood_paywall.verify import verify_payment


_nonce_store = NonceStore()


def amrood_pay(
    amount: str,
    pay_to: str,
    description: str | None = None,
    agent_key: str | None = None,
    base_url: str | None = None,
    expiry_seconds: int = 600,
):
    """Decorator that adds an Amrood x402 paywall to a FastAPI endpoint.

    Usage:
        @app.get("/api/data")
        @amrood_pay(amount="5.00", pay_to="databot")
        async def get_data():
            return {"data": "premium"}

    Args:
        amount: Price in INR (e.g. "5.00").
        pay_to: Amrood agent handle or ID that receives payment.
        description: Human-readable description of what's being purchased.
        agent_key: Payee's agent API key for verification. Defaults to
                   AMROOD_AGENT_KEY env var.
        base_url: Amrood API base URL. Defaults to AMROOD_BASE_URL env var
                  or https://amrood.io.
        expiry_seconds: How long a payment instruction is valid (default 600s).
    """
    def decorator(func):
        @functools.wraps(func)
        async def wrapper(*args, **kwargs):
            request = _extract_request(args, kwargs)
            if request is None:
                return await func(*args, **kwargs)

            key = agent_key or os.environ.get("AMROOD_AGENT_KEY", "")
            url = base_url or os.environ.get("AMROOD_BASE_URL", "https://amrood.io")

            payment_header = request.headers.get("x-amrood-payment")

            if not payment_header:
                nonce = _nonce_store.generate()
                pay_instruction = {
                    "version": 1,
                    "payTo": pay_to,
                    "amount": amount,
                    "asset": "INR",
                    "resource": str(request.url.path),
                    "description": description or f"Payment for {request.url.path}",
                    "nonce": nonce,
                    "expiresAt": (
                        datetime.now(timezone.utc) + timedelta(seconds=expiry_seconds)
                    ).isoformat(),
                }
                encoded = base64.b64encode(
                    json.dumps(pay_instruction).encode()
                ).decode()

                return JSONResponse(
                    status_code=402,
                    content={
                        "error": "payment_required",
                        "message": f"This endpoint costs ₹{amount}. "
                                   f"Pay agent '{pay_to}' and retry with X-AMROOD-PAYMENT header.",
                        "payTo": pay_to,
                        "amount": amount,
                        "asset": "INR",
                    },
                    headers={"X-AMROOD-PAY": encoded},
                )

            try:
                payload = json.loads(base64.b64decode(payment_header))
            except Exception:
                return JSONResponse(
                    status_code=400,
                    content={"error": "invalid_payment_header", "message": "Could not decode X-AMROOD-PAYMENT header"},
                )

            txn_id = payload.get("transactionId")
            nonce = payload.get("nonce")

            if not txn_id:
                return JSONResponse(
                    status_code=400,
                    content={"error": "missing_transaction_id"},
                )

            if nonce and not _nonce_store.mark_used(nonce):
                return JSONResponse(
                    status_code=409,
                    content={"error": "nonce_reused", "message": "This payment proof has already been used"},
                )

            result = await verify_payment(
                transaction_id=txn_id,
                agent_key=key,
                expected_payee=pay_to,
                expected_amount=float(amount),
                nonce=nonce,
                base_url=url,
            )

            if not result.get("verified"):
                reason = result.get("reason", "verification_failed")
                return JSONResponse(
                    status_code=402,
                    content={"error": "payment_verification_failed", "reason": reason},
                )

            return await func(*args, **kwargs)

        return wrapper
    return decorator


def _extract_request(args, kwargs) -> Request | None:
    """Extract the FastAPI Request object from function arguments."""
    for arg in args:
        if isinstance(arg, Request):
            return arg
    for val in kwargs.values():
        if isinstance(val, Request):
            return val
    return None
