"""V1 type definitions for x402 payment protocol on Stacks blockchain."""

from __future__ import annotations

from typing import Any, Literal, Optional

from pydantic import BaseModel, ConfigDict, Field


NetworkType = Literal["mainnet", "testnet"]
TokenType = Literal["STX", "sBTC", "USDCx"]
PaymentStatus = Literal["pending", "success", "failed", "not_found"]


class TokenContract(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    address: str
    name: str


class X402PaymentRequired(BaseModel):
    """HTTP 402 Payment Required response body."""

    model_config = ConfigDict(populate_by_name=True)

    max_amount_required: str = Field(alias="maxAmountRequired")
    resource: str
    pay_to: str = Field(alias="payTo")
    network: NetworkType
    nonce: str
    expires_at: str = Field(alias="expiresAt")
    memo: Optional[str] = None
    token_type: Optional[TokenType] = Field(default=None, alias="tokenType")
    token_contract: Optional[TokenContract] = Field(default=None, alias="tokenContract")


class PaymentDetails(BaseModel):
    """Payment details for making a transfer."""

    model_config = ConfigDict(populate_by_name=True)

    recipient: str
    amount: int
    sender_key: str = Field(alias="senderKey")
    network: NetworkType
    memo: Optional[str] = None
    nonce: Optional[int] = None
    fee: Optional[int] = None
    token_type: Optional[TokenType] = Field(default=None, alias="tokenType")
    token_contract: Optional[TokenContract] = Field(default=None, alias="tokenContract")
    sender_address: Optional[str] = Field(default=None, alias="senderAddress")


class PaymentResult(BaseModel):
    """Result of broadcasting a payment transaction."""

    model_config = ConfigDict(populate_by_name=True)

    tx_id: str = Field(alias="txId")
    tx_raw: str = Field(alias="txRaw")
    success: bool
    error: Optional[str] = None


class SignedPaymentResult(BaseModel):
    """Result of signing a payment transaction (without broadcasting)."""

    model_config = ConfigDict(populate_by_name=True)

    signed_transaction: str = Field(alias="signedTransaction")
    success: bool
    sender_address: Optional[str] = Field(default=None, alias="senderAddress")
    error: Optional[str] = None


class VerifiedPayment(BaseModel):
    """Verified payment transaction details."""

    model_config = ConfigDict(populate_by_name=True)

    tx_id: str = Field(alias="txId")
    status: PaymentStatus
    sender: str
    recipient: str
    amount: int
    memo: Optional[str] = None
    block_height: Optional[int] = Field(default=None, alias="blockHeight")
    timestamp: Optional[int] = None
    is_valid: bool = Field(alias="isValid")
    validation_error: Optional[str] = Field(default=None, alias="validationError")


class VerificationOptions(BaseModel):
    """Options for payment verification."""

    model_config = ConfigDict(populate_by_name=True)

    expected_recipient: str = Field(alias="expectedRecipient")
    min_amount: int = Field(alias="minAmount")
    expected_sender: Optional[str] = Field(default=None, alias="expectedSender")
    expected_memo: Optional[str] = Field(default=None, alias="expectedMemo")
    max_age: Optional[int] = Field(default=None, alias="maxAge")
    resource: Optional[str] = None
    method: Optional[str] = None
    token_type: Optional[TokenType] = Field(default=None, alias="tokenType")
    token_contract: Optional[TokenContract] = Field(default=None, alias="tokenContract")


class X402MiddlewareConfig(BaseModel):
    """Configuration for x402 middleware."""

    model_config = ConfigDict(populate_by_name=True)

    amount: str | int
    address: str
    network: NetworkType
    facilitator_url: Optional[str] = Field(default=None, alias="facilitatorUrl")
    resource: Optional[str] = None
    expiration_seconds: Optional[int] = Field(default=None, alias="expirationSeconds")
    token_type: Optional[TokenType] = Field(default=None, alias="tokenType")
    token_contract: Optional[TokenContract] = Field(default=None, alias="tokenContract")


class StacksTransaction(BaseModel):
    """Transaction data from Stacks API."""

    tx_id: str
    nonce: int
    fee_rate: str
    sender_address: str
    sponsored: bool
    post_condition_mode: str
    post_conditions: list[Any] = Field(default_factory=list)
    anchor_mode: str
    tx_status: Literal["success", "pending", "failed", "abort_by_response", "abort_by_post_condition"]
    tx_type: Literal["token_transfer", "smart_contract", "contract_call", "poison_microblock"]
    receipt_time: int
    receipt_time_iso: str
    block_hash: Optional[str] = None
    block_height: Optional[int] = None
    canonical: Optional[bool] = None
    tx_index: Optional[int] = None
    token_transfer: Optional[dict[str, Any]] = None
    events: Optional[list[Any]] = None


class X402ClientConfig(BaseModel):
    """Client configuration."""

    model_config = ConfigDict(populate_by_name=True)

    network: NetworkType
    private_key: str = Field(alias="privateKey")
    facilitator_url: Optional[str] = Field(default=None, alias="facilitatorUrl")
    api_endpoint: Optional[str] = Field(default=None, alias="apiEndpoint")
    timeout: Optional[int] = None


class FacilitatorVerifyRequest(BaseModel):
    """Facilitator API request for payment verification."""

    tx_id: str
    expected_recipient: str
    min_amount: int
    expected_sender: Optional[str] = None
    expected_memo: Optional[str] = None
    network: NetworkType
    resource: Optional[str] = None
    method: Optional[str] = None
    token_type: Optional[Literal["STX", "SBTC", "USDCX"]] = None


class FacilitatorVerifyResponse(BaseModel):
    """Facilitator API response for payment verification."""

    valid: bool
    tx_id: Optional[str] = None
    sender_address: Optional[str] = None
    recipient_address: Optional[str] = None
    amount: Optional[int] = None
    fee: Optional[int] = None
    nonce: Optional[int] = None
    status: Optional[str] = None
    block_height: Optional[int] = None
    memo: Optional[str] = None
    network: Optional[str] = None
    resource: Optional[str] = None
    method: Optional[str] = None
    validation_errors: Optional[list[str]] = None
    error: Optional[str] = None


class FacilitatorSettleRequest(BaseModel):
    """Facilitator API request for payment settlement."""

    signed_transaction: str
    token_type: Optional[Literal["STX", "SBTC", "USDCX"]] = None
    expected_recipient: str
    min_amount: int
    expected_sender: Optional[str] = None
    network: NetworkType
    resource: Optional[str] = None
    method: Optional[str] = None


class FacilitatorSettleResponse(BaseModel):
    """Facilitator API response for payment settlement."""

    success: bool
    tx_id: Optional[str] = None
    token_type: Optional[str] = None
    sender_address: Optional[str] = None
    recipient_address: Optional[str] = None
    amount: Optional[int] = None
    fee: Optional[int] = None
    status: Optional[str] = None
    block_height: Optional[int] = None
    network: Optional[str] = None
    validation_errors: Optional[list[str]] = None
    error: Optional[str] = None


class StacksAccount(BaseModel):
    """Stacks account for signing transactions."""

    model_config = ConfigDict(populate_by_name=True)

    address: str
    private_key: str = Field(alias="privateKey")
    network: NetworkType


class PaymentResponse(BaseModel):
    """Decoded X-PAYMENT-RESPONSE header."""

    model_config = ConfigDict(populate_by_name=True)

    tx_id: str = Field(alias="txId")
    status: str
    block_height: Optional[int] = Field(default=None, alias="blockHeight")
