from __future__ import annotations

from dataclasses import dataclass, field
from decimal import Decimal
from typing import Any, Protocol


class PaymentProviderError(Exception):
    def __init__(self, message: str, *, status_code: int = 502, raw: Any = None):
        super().__init__(message)
        self.message = message
        self.status_code = status_code
        self.raw = raw


@dataclass(frozen=True)
class PaymentCreateRequest:
    out_trade_no: str
    amount_yuan: str
    subject: str
    client_ip: str
    notify_url: str
    return_url: str
    user_id: int


@dataclass(frozen=True)
class PaymentCreateResult:
    provider: str
    method: str
    platform_trade_no: str | None = None
    pay_url: str | None = None
    qr_code: str | None = None
    url_scheme: str | None = None
    raw: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class PaymentNotifyResult:
    paid: bool
    out_trade_no: str
    trade_no: str
    amount_yuan: Decimal
    status: str
    raw: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class PaymentQueryResult:
    paid: bool
    out_trade_no: str
    trade_no: str
    amount_yuan: Decimal
    status: str
    raw: dict[str, Any] = field(default_factory=dict)


class PaymentProvider(Protocol):
    name: str
    display_name: str
    method: str

    async def create_payment(self, request: PaymentCreateRequest) -> PaymentCreateResult:
        """Create a payment session and return redirect/QR data."""

    async def parse_notify(self, params: dict[str, Any]) -> PaymentNotifyResult:
        """Validate a provider callback and return a normalized result."""

    async def query_order(self, out_trade_no: str) -> PaymentQueryResult:
        """Query payment status by merchant order number."""

