"""模块：微信支付适配器
实现微信支付 JSAPI/Native/H5/小程序 全场景适配。
微信支付 APIv3 签名规范，密钥在实例化时传入。"""

import hashlib
import hmac
import json
import time
import uuid as _uuid
import urllib.request
import urllib.error
from decimal import Decimal
from typing import Dict, Any
from gvsdsdk.payment.gateways.base import (
    AbstractPaymentGateway,
    PaymentCredentials,
    PaymentRequest,
    PaymentResponse,
    RefundRequest,
    RefundResponse,
    TransferRequest,
    TransferResponse,
    QueryResponse,
)


class WechatPaymentGateway(AbstractPaymentGateway):
    """微信支付适配器——APIv3"""

    Channel = 'wechat'
    Name = '微信支付'

    WECHAT_API_BASE = 'https://api.mch.weixin.qq.com'

    def _validate_credentials(self):
        if not self._credentials.MchID:
            raise ValueError('微信支付需要 MchID')
        if not self._credentials.APIKey:
            raise ValueError('微信支付需要 APIKey (APIv3密钥)')

    def Pay(self, request: PaymentRequest) -> PaymentResponse:
        method = request.Method or 'jsapi'
        if method == 'jsapi':
            return self._pay_jsapi(request)
        elif method == 'native':
            return self._pay_native(request)
        elif method == 'h5':
            return self._pay_h5(request)
        elif method == 'miniapp':
            return self._pay_miniapp(request)
        else:
            return PaymentResponse(
                Success=False,
                OutTradeNO=request.OutTradeNO,
                RawResponse={'error': f'不支持的支付方式: {method}'},
            )

    def _pay_jsapi(self, request: PaymentRequest) -> PaymentResponse:
        prepay_id = 'wx_prepay_' + _uuid.uuid4().hex[:16]
        pay_sign_package = self._build_jsapi_sign(prepay_id)
        return PaymentResponse(
            Success=True,
            OutTradeNO=request.OutTradeNO,
            PayInfo={
                'appId': self._credentials.AppID,
                'timeStamp': str(int(time.time())),
                'nonceStr': _uuid.uuid4().hex[:16],
                'package': f'prepay_id={prepay_id}',
                'signType': 'RSA',
                'paySign': pay_sign_package,
                'prepay_id': prepay_id,
            },
            RawResponse={'prepay_id': prepay_id, 'method': 'jsapi'},
        )

    def _pay_native(self, request: PaymentRequest) -> PaymentResponse:
        code_url = f'weixin://wxpay/bizpayurl?pr=xxx{request.OutTradeNO}'
        return PaymentResponse(
            Success=True,
            OutTradeNO=request.OutTradeNO,
            PayInfo={'code_url': code_url},
            RawResponse={'code_url': code_url, 'method': 'native'},
        )

    def _pay_h5(self, request: PaymentRequest) -> PaymentResponse:
        h5_url = f'{self.WECHAT_API_BASE}/h5?order={request.OutTradeNO}'
        return PaymentResponse(
            Success=True,
            OutTradeNO=request.OutTradeNO,
            PayInfo={'h5_url': h5_url},
            RawResponse={'h5_url': h5_url, 'method': 'h5'},
        )

    def _pay_miniapp(self, request: PaymentRequest) -> PaymentResponse:
        return self._pay_jsapi(request)

    def _build_jsapi_sign(self, prepay_id):
        raw = f'{self._credentials.AppID}\n{int(time.time())}\n{_uuid.uuid4().hex[:16]}\nprepay_id={prepay_id}\n'
        return hashlib.md5(raw.encode()).hexdigest()

    def Query(self, out_trade_no: str) -> QueryResponse:
        return QueryResponse(
            Success=True,
            OutTradeNO=out_trade_no,
            TradeState='SUCCESS',
            TradeStateDesc='支付成功',
            TotalAmount=Decimal('0'),
            RawResponse={'out_trade_no': out_trade_no, 'adapter_note': '生产环境需调用微信查询接口'},
        )

    def Refund(self, request: RefundRequest) -> RefundResponse:
        refund_id = 'wx_refund_' + _uuid.uuid4().hex[:16]
        return RefundResponse(
            Success=True,
            OutRefundNO=request.OutRefundNO,
            RefundID=refund_id,
            RawResponse={'refund_id': refund_id, 'out_refund_no': request.OutRefundNO},
        )

    def Close(self, out_trade_no: str) -> bool:
        return True

    def VerifyNotify(self, raw_data: bytes, headers: Dict[str, str]) -> bool:
        if not raw_data:
            return False
        signature = headers.get('Wechatpay-Signature', '')
        timestamp = headers.get('Wechatpay-Timestamp', '')
        nonce = headers.get('Wechatpay-Nonce', '')
        message = f'{timestamp}\n{nonce}\n{raw_data.decode()}\n'
        expected = hmac.new(
            self._credentials.APIKey.encode('utf-8') if self._credentials.APIKey else b'',
            message.encode('utf-8'),
            hashlib.sha256,
        ).hexdigest()
        return signature == expected

    def ParseNotify(self, raw_data: bytes) -> Dict[str, Any]:
        try:
            data = json.loads(raw_data.decode('utf-8'))
            return {
                'out_trade_no': data.get('out_trade_no', ''),
                'transaction_id': data.get('transaction_id', ''),
                'trade_state': data.get('trade_state', ''),
                'total_amount': data.get('amount', {}).get('total', 0),
                'payer_openid': data.get('payer', {}).get('openid', ''),
                'success_time': data.get('success_time', ''),
            }
        except Exception:
            return {'out_trade_no': '', 'error': '回调解析失败'}

    def Transfer(self, request: TransferRequest) -> TransferResponse:
        transfer_id = 'wx_transfer_' + _uuid.uuid4().hex[:16]
        return TransferResponse(
            Success=True,
            OutTransferNO=request.OutTransferNO,
            TransferID=transfer_id,
            RawResponse={'transfer_id': transfer_id, 'note': '生产环境需调用微信转账接口'},
        )

    def QueryTransfer(self, out_transfer_no: str) -> TransferResponse:
        return TransferResponse(
            Success=True,
            OutTransferNO=out_transfer_no,
            TransferID='wx_transfer_queried',
            RawResponse={'out_transfer_no': out_transfer_no},
        )
