"""The SDK advertises FastAPI support (pyproject `fastapi` extra). FastAPI is
built on Starlette, so A402Middleware should gate FastAPI routes too. This pins
that, and documents the `pay` decorator's current behavior.
"""
from __future__ import annotations

import base64
import json
from unittest.mock import patch

import pytest

fastapi = pytest.importorskip("fastapi")
from fastapi import FastAPI  # noqa: E402
from fastapi.testclient import TestClient  # noqa: E402

from a402 import A402Config, A402Middleware, pay  # noqa: E402

CHALLENGE = {"x402Version": 1, "accepts": [{"scheme": "exact", "network": "Base Sepolia", "nonce": "0xabc"}]}
SETTLED = {"payment": {"status": "settled"}}
XP = base64.b64encode(json.dumps({
    "apiKeyId": "ak_test", "network": "Base Sepolia",
    "authorization": {"from": "0xf", "to": "0xm", "value": "50000", "validAfter": "0", "validBefore": "9999999999", "nonce": "0xabc"},
    "signature": "0xsig",
}).encode()).decode()


def _app() -> TestClient:
    app = FastAPI()

    @app.get("/v1/data")
    @pay("$0.05")  # decorator sets metadata; middleware routes list does the gating
    async def data():
        return {"data": "secret"}

    app.add_middleware(
        A402Middleware,
        config=A402Config(facilitator_url="https://f.test", api_key="sk_seller"),
        routes=[{"method": "GET", "path": "/v1/data", "price": "$0.05"}],
    )
    return TestClient(app, raise_server_exceptions=False)


def test_fastapi_gated_route_returns_402():
    with patch("a402.middleware.issue_challenge", return_value=CHALLENGE):
        r = _app().get("/v1/data")
    assert r.status_code == 402
    assert r.json()["x402Version"] == 1


def test_fastapi_valid_payment_reaches_handler():
    with patch("a402.middleware.settle", return_value=(200, SETTLED)):
        r = _app().get("/v1/data", headers={"X-PAYMENT": XP})
    assert r.status_code == 200
    assert r.json() == {"data": "secret"}
    assert "X-PAYMENT-RESPONSE" in r.headers


def test_pay_decorator_attaches_metadata():
    @pay("$0.25", "Premium data")
    async def handler():
        return None

    assert handler._a402_price == pytest.approx(0.25)
    assert handler._a402_description == "Premium data"
