"""x402 rail adapters (payment settlement backends).

Vaultfire uses x402 as a *payment-gating and ledgering* layer. The gateway
emits HTTP-402 style requirements and records billable events.

This module defines a minimal adapter interface for plugging in payment
rails without coupling Vaultfire to any one provider.

Mission-aligned goals:
- Privacy first: no identity metadata required to settle payments.
- Extensible: ETH on EVM, Assemble AI (ASM), NS3 rails can be added.
- Auditable: adapters emit structured receipts.

Contract addresses:
  Base USDC:      0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913  (chain 8453)
  Avalanche USDC: 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E  (chain 43114)

NOTE: Adapters here are intentionally lightweight. Production deployments
should harden signature verification, replay protection, and key storage.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Mapping, Protocol


# ---------------------------------------------------------------------------
# Receipt dataclass
# ---------------------------------------------------------------------------

@dataclass(frozen=True, slots=True)
class X402PaymentReceipt:
    """Normalised payment receipt emitted by a rail adapter."""

    rail: str
    currency: str
    amount: float
    tx_ref: str | None = None
    payer: str | None = None
    meta: Mapping[str, Any] | None = None


# ---------------------------------------------------------------------------
# Rail protocol (structural typing)
# ---------------------------------------------------------------------------

class X402Rail(Protocol):
    """Interface that every rail adapter must satisfy."""

    rail_id: str

    def supports_currency(self, currency: str) -> bool:
        """Return True if this rail handles the given currency symbol."""
        ...

    def parse_webhook(self, payload: Mapping[str, Any]) -> X402PaymentReceipt:
        """Parse an inbound webhook payload into a normalised receipt."""
        ...


# ---------------------------------------------------------------------------
# Built-in rail implementations
# ---------------------------------------------------------------------------

class EvmRail:
    """EVM rail — handles ETH and USDC payments on Base / Avalanche / Arbitrum / Polygon."""

    rail_id = "evm"

    def supports_currency(self, currency: str) -> bool:
        return currency.upper() in {"ETH", "USDC"}

    def parse_webhook(self, payload: Mapping[str, Any]) -> X402PaymentReceipt:
        currency = str(payload.get("currency") or "ETH").upper()
        amount = float(payload.get("amount") or 0.0)
        return X402PaymentReceipt(
            rail=self.rail_id,
            currency=currency,
            amount=amount,
            tx_ref=payload.get("tx_hash") or payload.get("transaction_hash"),
            payer=payload.get("from") or payload.get("payer") or payload.get("wallet"),
            meta={"chain": payload.get("chain") or payload.get("network")},
        )


class AssembleRail:
    """Assemble AI rail — normalises inbound receipts denominated in ASM."""

    rail_id = "assemble"

    def supports_currency(self, currency: str) -> bool:
        return currency.upper() == "ASM"

    def parse_webhook(self, payload: Mapping[str, Any]) -> X402PaymentReceipt:
        amount = float(payload.get("amount") or 0.0)
        return X402PaymentReceipt(
            rail=self.rail_id,
            currency="ASM",
            amount=amount,
            tx_ref=payload.get("asm_tx") or payload.get("tx_ref") or payload.get("receipt_id"),
            payer=payload.get("wallet") or payload.get("payer"),
            meta={"ns3": payload.get("ns3"), "receipt_id": payload.get("receipt_id")},
        )


class Ns3Rail:
    """NS3 rail — treats NS3 as a transport + session rail, multi-currency."""

    rail_id = "ns3"

    def supports_currency(self, currency: str) -> bool:
        return currency.upper() in {"ASM", "ETH", "USDC"}

    def parse_webhook(self, payload: Mapping[str, Any]) -> X402PaymentReceipt:
        currency = str(payload.get("currency") or "ASM").upper()
        amount = float(payload.get("amount") or 0.0)
        return X402PaymentReceipt(
            rail=self.rail_id,
            currency=currency,
            amount=amount,
            tx_ref=payload.get("tx_ref") or payload.get("session_id"),
            payer=payload.get("wallet") or payload.get("payer"),
            meta={"session": payload.get("session"), "route": payload.get("route")},
        )


# ---------------------------------------------------------------------------
# Default rails registry
# ---------------------------------------------------------------------------

DEFAULT_RAILS: Mapping[str, X402Rail] = {
    "evm": EvmRail(),
    "assemble": AssembleRail(),
    "ns3": Ns3Rail(),
}

__all__ = [
    "X402PaymentReceipt",
    "X402Rail",
    "EvmRail",
    "AssembleRail",
    "Ns3Rail",
    "DEFAULT_RAILS",
]
