"""模块：抽象支付网关
SAAS 支付网关抽象层——不绑定具体业务，只定义支付操作的通用契约。

架构设计：
  子服务（如阿龙电竞）
    │
    ├── 注入租户密钥 → PaymentGatewayConfig
    │
    └── 调用 PaymentManager.pay(...)
            │
            ├── 根据 platform 类型获取对应的 GatewayAdapter
            ├── 网关实例由密钥创建（非来自数据库）
            └── 执行 Pay / Query / Refund / Close

设计原则：
  1. 网关是无状态的，凭据由调用方在构造时传入
  2. 不关心"谁"在付款（那是子服务的事）
  3. 只关心"通过哪个渠道"付了"多少钱"
  4. SAAS 主服务器只记录交易流水，不记录业务上下文"""

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Optional, Dict, Any, Literal
from decimal import Decimal


PaymentChannel = Literal['wechat', 'alipay', 'bank', 'unionpay', 'custom']

PaymentMethod = Literal['jsapi', 'app', 'h5', 'native', 'miniapp', 'scan', 'transfer']


@dataclass
class PaymentCredentials:
    """支付凭证——网关实例创建时传入，不持久化到数据库"""

    AppID: str = ''
    MchID: str = ''
    APIKey: str = ''
    PrivateKey: str = ''
    PublicKey: str = ''
    CertPath: str = ''
    CertKeyPath: str = ''
    NotifyURL: str = ''
    ReturnURL: str = ''
    Extra: Dict[str, str] = field(default_factory=dict)

    def AsDict(self):
        return {
            'app_id': self.AppID,
            'mch_id': self.MchID,
            'api_key': '***',
            'notify_url': self.NotifyURL,
            'return_url': self.ReturnURL,
            'extra_keys': list(self.Extra.keys()),
        }


@dataclass
class PaymentRequest:
    """支付请求——标准化入参"""

    OutTradeNO: str
    TotalAmount: Decimal
    Currency: str = 'CNY'
    Subject: str = ''
    Body: str = ''
    Method: PaymentMethod = 'jsapi'
    OpenID: str = ''
    ClientIP: str = ''
    ExpireMinutes: int = 30
    Extra: Dict[str, Any] = field(default_factory=dict)


@dataclass
class PaymentResponse:
    """支付响应——标准化出参"""

    Success: bool
    OutTradeNO: str
    TransactionID: str = ''
    PayInfo: Dict[str, Any] = field(default_factory=dict)
    RawResponse: Dict[str, Any] = field(default_factory=dict)

    @property
    def PrepayID(self):
        return self.PayInfo.get('prepay_id', self.PayInfo.get('prepayid', ''))


@dataclass
class RefundRequest:
    """退款请求"""

    OutTradeNO: str
    OutRefundNO: str
    TotalAmount: Decimal
    RefundAmount: Decimal
    Reason: str = ''
    Extra: Dict[str, Any] = field(default_factory=dict)


@dataclass
class RefundResponse:
    """退款响应"""

    Success: bool
    OutRefundNO: str
    RefundID: str = ''
    RawResponse: Dict[str, Any] = field(default_factory=dict)


@dataclass
class TransferRequest:
    """转账请求（企业付款到零钱/银行卡）"""

    OutTransferNO: str
    Amount: Decimal
    PayeeAccount: str = ''
    PayeeName: str = ''
    Description: str = ''
    TransferType: Literal['wallet', 'bank'] = 'wallet'
    Extra: Dict[str, Any] = field(default_factory=dict)


@dataclass
class TransferResponse:
    """转账响应"""

    Success: bool
    OutTransferNO: str
    TransferID: str = ''
    RawResponse: Dict[str, Any] = field(default_factory=dict)


@dataclass
class QueryResponse:
    """订单查询响应"""

    Success: bool
    OutTradeNO: str
    TransactionID: str = ''
    TradeState: str = ''
    TradeStateDesc: str = ''
    TotalAmount: Decimal = Decimal('0')
    RawResponse: Dict[str, Any] = field(default_factory=dict)

    @property
    def IsPaid(self):
        return self.TradeState in ('SUCCESS', 'TRADE_SUCCESS', 'TRADE_FINISHED')

    @property
    def IsRefunded(self):
        return self.TradeState in ('REFUND', 'TRADE_REFUND')


class AbstractPaymentGateway(ABC):
    """抽象支付网关基类

    所有支付渠道的适配器必须实现此接口。
    每个实例绑定一组支付凭证，不同租户/不同平台使用不同实例。

    用法:
        creds = PaymentCredentials(AppID='wx...', MchID='123', APIKey='...')
        gw = WechatPaymentGateway(creds)
        resp = gw.Pay(PaymentRequest(OutTradeNO='X', TotalAmount=Decimal('1.00')))
    """

    Channel: PaymentChannel = 'custom'
    Name: str = 'Abstract'

    def __init__(self, credentials: PaymentCredentials):
        self._credentials = credentials
        self._validate_credentials()

    def _validate_credentials(self):
        pass

    @property
    def Credentials(self):
        return self._credentials

    # ─── 核心支付接口 ──────────────────────────────────────

    @abstractmethod
    def Pay(self, request: PaymentRequest) -> PaymentResponse:
        """发起支付——返回前端调起支付所需参数"""
        ...

    @abstractmethod
    def Query(self, out_trade_no: str) -> QueryResponse:
        """查询订单状态"""
        ...

    @abstractmethod
    def Refund(self, request: RefundRequest) -> RefundResponse:
        """发起退款"""
        ...

    @abstractmethod
    def Close(self, out_trade_no: str) -> bool:
        """关闭未支付的订单"""
        ...

    # ─── 回调处理 ─────────────────────────────────────────

    @abstractmethod
    def VerifyNotify(self, raw_data: bytes, headers: Dict[str, str]) -> bool:
        """验证支付回调签名的合法性"""
        ...

    @abstractmethod
    def ParseNotify(self, raw_data: bytes) -> Dict[str, Any]:
        """解析支付回调数据为标准化字典"""
        ...

    # ─── 可选接口 ─────────────────────────────────────────

    def Transfer(self, request: TransferRequest) -> TransferResponse:
        """企业付款到零钱/银行卡（部分渠道不支持）"""
        raise NotImplementedError(f'{self.Name} 不支持转账功能')

    def QueryTransfer(self, out_transfer_no: str) -> TransferResponse:
        """查询转账状态"""
        raise NotImplementedError(f'{self.Name} 不支持转账查询')
