package payment

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	bizpayment "kra/internal/biz/payment"
	"math"
	"strconv"
	"strings"

	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/paypal"
)

type paypalAdapter struct{}

func (a *paypalAdapter) client(c map[string]any) (*paypal.Client, error) {
	environment := strings.ToLower(strings.TrimSpace(text(c, "environment")))
	isProd := environment != "sandbox"
	options := []paypal.Option{paypal.WithoutAutoRefreshToken()}
	if baseURL := strings.TrimRight(firstAny(c, "api_base_url", "base_url", "proxy_url"), "/"); baseURL != "" {
		options = append(options, paypal.WithProxyUrl(baseURL, baseURL))
	}
	client, err := paypal.NewClient(text(c, "client_id"), text(c, "client_secret"), isProd, options...)
	if err != nil {
		return nil, fmt.Errorf("PayPal 客户端初始化失败: %w", err)
	}
	client.SetRequestHeader("Prefer", "return=representation")
	return client, nil
}

func (a *paypalAdapter) Create(ctx context.Context, req *bizpayment.PaymentRequest, c map[string]any) (*bizpayment.PaymentResult, error) {
	if req == nil {
		return nil, errors.New("PayPal 下单参数为空")
	}
	client, err := a.client(c)
	if err != nil {
		return nil, err
	}
	currency := strings.ToUpper(strings.TrimSpace(req.Currency))
	value, err := paypalFormatAmount(req.Amount, currency, c)
	if err != nil {
		return nil, err
	}
	purchaseUnit := &paypal.PurchaseUnit{
		ReferenceId: req.TradeNo,
		Description: req.Subject,
		CustomId:    req.TradeNo,
		InvoiceId:   req.TradeNo,
		Amount:      &paypal.Amount{CurrencyCode: currency, Value: value},
	}
	bm := gopay.BodyMap{
		"intent":         "CAPTURE",
		"purchase_units": []*paypal.PurchaseUnit{purchaseUnit},
	}
	if applicationContext := paypalApplicationContext(req, c); len(applicationContext) > 0 {
		bm["application_context"] = applicationContext
	}
	mergeGoPayExtras(bm, req.Extra, "intent", "purchase_units", "application_context")
	client.SetRequestHeader("PayPal-Request-Id", req.TradeNo)
	rsp, err := client.CreateOrder(ctx, bm)
	if err != nil {
		return nil, err
	}
	if rsp == nil || rsp.Code != paypal.Success || rsp.Response == nil {
		return nil, paypalResponseError("下单", paypalResponseCode(rsp), paypalCreateError(rsp))
	}
	order := rsp.Response
	if strings.TrimSpace(order.Id) == "" {
		return nil, errors.New("PayPal 下单成功但缺少 order ID")
	}
	return paypalCreateResult(req, order, c)
}

func (a *paypalAdapter) Query(ctx context.Context, orderID string, c map[string]any) (*bizpayment.PaymentResult, error) {
	orderID = strings.TrimSpace(orderID)
	if orderID == "" {
		return nil, errors.New("PayPal 查单缺少 order ID")
	}
	client, err := a.client(c)
	if err != nil {
		return nil, err
	}
	rsp, err := client.OrderDetail(ctx, orderID, nil)
	if err != nil {
		return nil, err
	}
	if rsp == nil || rsp.Code != paypal.Success || rsp.Response == nil {
		return nil, paypalResponseError("查单", paypalResponseCode(rsp), paypalOrderError(rsp))
	}
	if rsp.Response.Id != "" && rsp.Response.Id != orderID {
		return nil, errors.New("PayPal 查单响应的 order ID 不匹配")
	}
	order := rsp.Response
	if _, err = paypalOrderIdentity(order); err != nil {
		return nil, err
	}
	if paypalAutoCaptureEnabled(c) && strings.EqualFold(strings.TrimSpace(order.Status), "APPROVED") {
		order, err = paypalCaptureOrder(ctx, client, orderID, c)
		if err != nil {
			return nil, err
		}
	}
	return paypalOrderResult(order, orderID, "", c)
}

// paypalCaptureOrder completes an order after the buyer approves it. PayPal's
// CAPTURE intent deliberately separates approval from settlement; treating an
// APPROVED order as paid would allow fulfillment before funds are captured.
func paypalCaptureOrder(ctx context.Context, client *paypal.Client, orderID string, c map[string]any) (*paypal.OrderDetail, error) {
	if client == nil || strings.TrimSpace(orderID) == "" {
		return nil, errors.New("PayPal 捕获订单参数为空")
	}
	bm := gopay.BodyMap{}
	mergeGoPayConfigExtras(bm, c, "capture_extra")
	client.SetRequestHeader("PayPal-Request-Id", strings.TrimSpace(orderID)+"-capture")
	rsp, err := client.OrderCapture(ctx, orderID, bm)
	if err != nil {
		return nil, err
	}
	if rsp == nil || rsp.Code != paypal.Success || rsp.Response == nil {
		return nil, paypalResponseError("捕获订单", paypalResponseCode(rsp), paypalCaptureError(rsp))
	}
	if returnedID := strings.TrimSpace(rsp.Response.Id); returnedID != "" && returnedID != strings.TrimSpace(orderID) {
		return nil, errors.New("PayPal 捕获响应的 order ID 不匹配")
	}
	return rsp.Response, nil
}

func paypalAutoCaptureEnabled(c map[string]any) bool {
	value, ok := c["auto_capture"]
	if !ok || value == nil {
		return true
	}
	switch parsed := value.(type) {
	case bool:
		return parsed
	case string:
		if result, err := strconv.ParseBool(strings.TrimSpace(parsed)); err == nil {
			return result
		}
	case json.Number:
		return parsed != "0"
	case float64:
		return parsed != 0
	case int:
		return parsed != 0
	case int64:
		return parsed != 0
	}
	return true
}

func (a *paypalAdapter) Refund(ctx context.Context, req *bizpayment.PaymentRefundRequest, c map[string]any) (*bizpayment.PaymentResult, error) {
	if req == nil {
		return nil, errors.New("PayPal 退款请求为空")
	}
	tradeNo := strings.TrimSpace(req.TradeNo)
	refundNo := strings.TrimSpace(req.RefundNo)
	if tradeNo == "" || refundNo == "" || req.Amount <= 0 {
		return nil, errors.New("PayPal 退款缺少商户订单号、退款单号或有效金额")
	}
	effective := *req
	effective.TradeNo = tradeNo
	effective.RefundNo = refundNo
	req = &effective
	client, err := a.client(c)
	if err != nil {
		return nil, err
	}
	captureID, err := paypalRefundCaptureID(ctx, client, req)
	if err != nil {
		return nil, err
	}
	currency := strings.ToUpper(strings.TrimSpace(req.Currency))
	value, err := paypalFormatAmount(req.Amount, currency, c)
	if err != nil {
		return nil, err
	}
	bm := gopay.BodyMap{
		"invoice_id": refundNo,
		"amount": &paypal.Amount{
			CurrencyCode: currency,
			Value:        value,
		},
	}
	if note := strings.TrimSpace(text(c, "refund_note")); note != "" {
		bm["note_to_payer"] = note
	}
	mergeGoPayConfigExtras(bm, c, "refund_extra", "amount", "invoice_id", "capture_id", "order_id", "query_id", "provider_trade_no")
	client.SetRequestHeader("PayPal-Request-Id", refundNo)
	rsp, err := client.PaymentCaptureRefund(ctx, captureID, bm)
	if err != nil {
		return nil, err
	}
	if rsp == nil || rsp.Code != paypal.Success || rsp.Response == nil {
		return nil, paypalResponseError("退款", paypalResponseCode(rsp), paypalRefundError(rsp))
	}
	return paypalRefundResult(req, rsp.Response, c)
}

func paypalRefundResult(req *bizpayment.PaymentRefundRequest, refund *paypal.PaymentCaptureRefund, c map[string]any) (*bizpayment.PaymentResult, error) {
	if req == nil || refund == nil {
		return nil, errors.New("PayPal 退款响应为空")
	}
	if invoiceID := strings.TrimSpace(refund.InvoiceId); invoiceID == "" {
		return nil, errors.New("PayPal 退款响应缺少 invoice_id")
	} else if invoiceID != strings.TrimSpace(req.RefundNo) {
		return nil, errors.New("PayPal 退款响应的 invoice_id 不匹配")
	}
	providerRefundID := strings.TrimSpace(refund.Id)
	if providerRefundID == "" {
		return nil, errors.New("PayPal 退款响应缺少 refund ID")
	}
	currency := strings.ToUpper(strings.TrimSpace(req.Currency))
	result := &bizpayment.PaymentResult{
		Provider:        bizpayment.PaymentPayPal,
		Status:          normalizePayPalRefundState(refund.Status),
		TradeNo:         req.TradeNo,
		ProviderTradeNo: providerRefundID,
		Amount:          req.Amount,
		Currency:        currency,
		Payload:         mustJSON(refund),
	}
	if refund.Amount == nil {
		return nil, errors.New("PayPal 退款响应缺少金额")
	}
	parsed, err := paypalParseAmount(refund.Amount, c)
	if err != nil {
		return nil, err
	}
	if parsed != req.Amount {
		return nil, errors.New("PayPal 退款响应金额不匹配")
	}
	responseCurrency := strings.ToUpper(strings.TrimSpace(refund.Amount.CurrencyCode))
	if responseCurrency == "" {
		return nil, errors.New("PayPal 退款响应缺少币种")
	}
	if currency != "" && responseCurrency != currency {
		return nil, errors.New("PayPal 退款响应币种不匹配")
	}
	result.Amount = parsed
	result.Currency = responseCurrency
	return result, nil
}

func paypalCreateResult(req *bizpayment.PaymentRequest, order *paypal.OrderDetail, c map[string]any) (*bizpayment.PaymentResult, error) {
	if req == nil || order == nil {
		return nil, errors.New("PayPal 下单响应为空")
	}
	tradeNo, err := paypalOrderIdentity(order)
	if err != nil {
		return nil, err
	}
	if tradeNo != "" && tradeNo != strings.TrimSpace(req.TradeNo) {
		return nil, errors.New("PayPal 下单响应的商户订单号不匹配")
	}
	amount, currency, found, err := paypalOrderAmount(order, c)
	if err != nil {
		return nil, err
	}
	if found {
		if amount != req.Amount {
			return nil, errors.New("PayPal 下单响应金额不匹配")
		}
		if expected := strings.ToUpper(strings.TrimSpace(req.Currency)); currency == "" || currency != expected {
			return nil, errors.New("PayPal 下单响应币种不匹配")
		}
	}
	result, err := paypalOrderResult(order, order.Id, req.TradeNo, c)
	if err != nil {
		return nil, err
	}
	result.TradeNo = req.TradeNo
	return result, nil
}

func (a *paypalAdapter) Callback(ctx context.Context, callback *bizpayment.PaymentCallback, c map[string]any) (*bizpayment.PaymentResult, error) {
	if callback == nil || len(callback.Body) == 0 {
		return nil, errors.New("PayPal 回调为空")
	}
	webhookID := strings.TrimSpace(text(c, "webhook_id"))
	if webhookID == "" {
		return nil, errors.New("PayPal 回调验签缺少 webhook_id")
	}
	var event paypal.WebhookEvent
	if err := json.Unmarshal(callback.Body, &event); err != nil {
		return nil, fmt.Errorf("PayPal 回调 JSON 无效: %w", err)
	}
	if strings.TrimSpace(event.Id) == "" || len(event.Resource) == 0 {
		return nil, errors.New("PayPal 回调事件不完整")
	}
	var webhookEvent any
	if err := json.Unmarshal(callback.Body, &webhookEvent); err != nil {
		return nil, err
	}
	verifyBody := gopay.BodyMap{
		"auth_algo":         paypalCallbackHeader(callback, "Paypal-Auth-Algo"),
		"cert_url":          paypalCallbackHeader(callback, "Paypal-Cert-Url"),
		"transmission_id":   paypalCallbackHeader(callback, "Paypal-Transmission-Id"),
		"transmission_sig":  paypalCallbackHeader(callback, "Paypal-Transmission-Sig"),
		"transmission_time": paypalCallbackHeader(callback, "Paypal-Transmission-Time"),
		"webhook_id":        webhookID,
		"webhook_event":     webhookEvent,
	}
	client, err := a.client(c)
	if err != nil {
		return nil, err
	}
	verified, err := client.VerifyWebhookSignature(ctx, verifyBody)
	if err != nil {
		return nil, err
	}
	if verified == nil || !strings.EqualFold(verified.VerificationStatus, "SUCCESS") {
		return nil, errors.New("PayPal 回调签名校验失败")
	}
	result, err := paypalWebhookResult(&event)
	if err != nil {
		return nil, err
	}
	result.Payload = append([]byte(nil), callback.Body...)
	result.EventID = event.Id
	return result, nil
}

func paypalApplicationContext(req *bizpayment.PaymentRequest, c map[string]any) map[string]any {
	applicationContext := map[string]any{}
	if configured, ok := req.Extra["application_context"].(map[string]any); ok {
		for key, value := range configured {
			applicationContext[key] = value
		}
	}
	for _, key := range []string{"brand_name", "locale", "landing_page", "shipping_preference", "user_action"} {
		if _, exists := applicationContext[key]; !exists {
			if value := strings.TrimSpace(text(c, key)); value != "" {
				applicationContext[key] = value
			}
		}
	}
	if returnURL := strings.TrimSpace(req.ReturnURL); returnURL != "" {
		applicationContext["return_url"] = returnURL
	}
	cancelURL := firstAny(c, "cancel_url", "return_url")
	if cancelURL == "" {
		cancelURL = strings.TrimSpace(req.ReturnURL)
	}
	if cancelURL != "" {
		applicationContext["cancel_url"] = cancelURL
	}
	return applicationContext
}

func paypalOrderResult(order *paypal.OrderDetail, queryID, fallbackTradeNo string, c map[string]any) (*bizpayment.PaymentResult, error) {
	if order == nil {
		return nil, errors.New("PayPal 订单结果为空")
	}
	tradeNo, err := paypalOrderIdentity(order)
	if err != nil {
		return nil, err
	}
	if tradeNo == "" {
		tradeNo = fallbackTradeNo
	}
	capture := paypalOrderCapture(order)
	result := &bizpayment.PaymentResult{
		Provider: bizpayment.PaymentPayPal,
		Status:   paypalOrderCaptureState(order),
		TradeNo:  tradeNo,
		QueryID:  queryID,
		Payload:  mustJSON(order),
	}
	if capture != nil {
		result.ProviderTradeNo = capture.Id
	}
	amount, currency, found, err := paypalOrderAmount(order, c)
	if err != nil {
		return nil, err
	}
	if found {
		result.Amount = amount
		result.Currency = currency
	}
	return result, nil
}

func paypalOrderTradeNo(order *paypal.OrderDetail) string {
	tradeNo, _ := paypalOrderIdentity(order)
	return tradeNo
}

func paypalOrderIdentity(order *paypal.OrderDetail) (string, error) {
	if order == nil {
		return "", nil
	}
	identity := ""
	for _, unit := range order.PurchaseUnits {
		if unit == nil {
			continue
		}
		for _, value := range []string{unit.InvoiceId, unit.CustomId, unit.ReferenceId} {
			value = strings.TrimSpace(value)
			if value == "" {
				continue
			}
			if identity == "" {
				identity = value
				continue
			}
			if value != identity {
				return "", errors.New("PayPal 订单响应包含冲突的商户订单号")
			}
		}
	}
	return identity, nil
}

func paypalOrderCapture(order *paypal.OrderDetail) *paypal.Capture {
	if order == nil {
		return nil
	}
	for _, unit := range order.PurchaseUnits {
		if unit == nil || unit.Payments == nil {
			continue
		}
		for _, capture := range unit.Payments.Captures {
			if capture == nil || strings.TrimSpace(capture.Id) == "" {
				continue
			}
			if strings.EqualFold(capture.Status, "COMPLETED") {
				return capture
			}
		}
	}
	return nil
}

func paypalOrderCaptureState(order *paypal.OrderDetail) string {
	if order == nil {
		return "pending"
	}
	pending, failed, seen := false, false, false
	for _, unit := range order.PurchaseUnits {
		if unit == nil || unit.Payments == nil {
			continue
		}
		for _, capture := range unit.Payments.Captures {
			if capture == nil || strings.TrimSpace(capture.Id) == "" {
				continue
			}
			seen = true
			switch normalizePayPalCaptureState(capture.Status) {
			case "success":
				return "success"
			case "pending":
				pending = true
			case "failed":
				failed = true
			}
		}
	}
	if pending || !seen {
		if strings.EqualFold(order.Status, "VOIDED") {
			return "failed"
		}
		return "pending"
	}
	if failed {
		return "failed"
	}
	return "pending"
}

func paypalOrderAmount(order *paypal.OrderDetail, c map[string]any) (int64, string, bool, error) {
	var total int64
	var currency string
	found := false
	for _, unit := range order.PurchaseUnits {
		if unit == nil || unit.Amount == nil || strings.TrimSpace(unit.Amount.Value) == "" {
			continue
		}
		unitCurrency := strings.ToUpper(strings.TrimSpace(unit.Amount.CurrencyCode))
		amount, err := paypalParseAmount(unit.Amount, c)
		if err != nil {
			return 0, "", false, err
		}
		if found && currency != unitCurrency {
			return 0, "", false, errors.New("PayPal 订单包含不同币种的 purchase unit")
		}
		if amount > math.MaxInt64-total {
			return 0, "", false, errors.New("PayPal 订单金额超出范围")
		}
		currency = unitCurrency
		total += amount
		found = true
	}
	return total, currency, found, nil
}

func paypalRefundCaptureID(ctx context.Context, client *paypal.Client, req *bizpayment.PaymentRefundRequest) (string, error) {
	if req == nil {
		return "", errors.New("PayPal 退款请求为空")
	}
	if captureID := strings.TrimSpace(req.ProviderTradeNo); captureID != "" {
		return captureID, nil
	}
	orderID := strings.TrimSpace(req.QueryID)
	if orderID == "" {
		return "", errors.New("PayPal 退款缺少已持久化的 capture ID")
	}
	rsp, err := client.OrderDetail(ctx, orderID, nil)
	if err != nil {
		return "", err
	}
	if rsp == nil || rsp.Code != paypal.Success || rsp.Response == nil {
		return "", paypalResponseError("退款前查单", paypalResponseCode(rsp), paypalOrderError(rsp))
	}
	if rsp.Response.Id != "" && rsp.Response.Id != orderID {
		return "", errors.New("PayPal 退款查单响应的 order ID 不匹配")
	}
	returnedTradeNo, identityErr := paypalOrderIdentity(rsp.Response)
	if identityErr != nil {
		return "", identityErr
	}
	if returnedTradeNo == "" || returnedTradeNo != req.TradeNo {
		return "", errors.New("PayPal 退款订单与本地商户订单号不匹配")
	}
	capture := paypalOrderCapture(rsp.Response)
	if capture == nil || strings.TrimSpace(capture.Id) == "" {
		return "", errors.New("PayPal 退款订单缺少 capture ID")
	}
	return capture.Id, nil
}

func paypalWebhookResult(event *paypal.WebhookEvent) (*bizpayment.PaymentResult, error) {
	var resource map[string]any
	if err := json.Unmarshal(event.Resource, &resource); err != nil {
		return nil, fmt.Errorf("PayPal 回调 resource 无效: %w", err)
	}
	eventType := strings.ToUpper(strings.TrimSpace(event.EventType))
	tradeNo := firstNonEmpty(paypalMapString(resource, "invoice_id"), paypalMapString(resource, "custom_id"))
	queryID := paypalNestedMapString(resource, "supplementary_data", "related_ids", "order_id")
	providerTradeNo := ""
	status := normalizePayPalCaptureState(paypalMapString(resource, "status"))
	if strings.HasPrefix(eventType, "CHECKOUT.ORDER.") {
		var order paypal.OrderDetail
		if err := json.Unmarshal(event.Resource, &order); err != nil {
			return nil, err
		}
		identity, identityErr := paypalOrderIdentity(&order)
		if identityErr != nil {
			return nil, identityErr
		}
		tradeNo = identity
		queryID = order.Id
		if capture := paypalOrderCapture(&order); capture != nil {
			providerTradeNo = capture.Id
		}
		status = paypalOrderCaptureState(&order)
	} else {
		providerTradeNo = paypalMapString(resource, "id")
	}
	if tradeNo == "" {
		tradeNo = paypalPurchaseUnitTradeNo(resource)
	}
	if tradeNo == "" || queryID == "" {
		return nil, errors.New("PayPal 回调缺少商户订单号或 order ID")
	}
	return &bizpayment.PaymentResult{
		Provider:        bizpayment.PaymentPayPal,
		Status:          status,
		TradeNo:         tradeNo,
		ProviderTradeNo: providerTradeNo,
		QueryID:         queryID,
	}, nil
}

func paypalPurchaseUnitTradeNo(resource map[string]any) string {
	units, _ := resource["purchase_units"].([]any)
	for _, value := range units {
		unit, _ := value.(map[string]any)
		if tradeNo := firstNonEmpty(paypalMapString(unit, "invoice_id"), paypalMapString(unit, "custom_id"), paypalMapString(unit, "reference_id")); tradeNo != "" {
			return tradeNo
		}
	}
	return ""
}

func paypalCallbackHeader(callback *bizpayment.PaymentCallback, name string) string {
	for key, value := range callback.Headers {
		if strings.EqualFold(key, name) {
			return strings.TrimSpace(value)
		}
	}
	return ""
}

func paypalFormatAmount(amount int64, currency string, c map[string]any) (string, error) {
	scale, err := paypalAmountScale(currency, c)
	if err != nil {
		return "", err
	}
	return formatDecimalAmount(amount, scale)
}

func paypalParseAmount(amount *paypal.Amount, c map[string]any) (int64, error) {
	if amount == nil {
		return 0, errors.New("PayPal 金额为空")
	}
	scale, err := paypalAmountScale(amount.CurrencyCode, c)
	if err != nil {
		return 0, err
	}
	return parseDecimalAmount(amount.Value, scale)
}

func paypalAmountScale(currency string, c map[string]any) (int64, error) {
	currency = strings.ToUpper(strings.TrimSpace(currency))
	for _, key := range []string{"amount_scales", "currency_scales"} {
		if scales, ok := c[key].(map[string]any); ok {
			for configuredCurrency, raw := range scales {
				if !strings.EqualFold(configuredCurrency, currency) {
					continue
				}
				scale, err := strconv.ParseInt(strings.TrimSpace(fmt.Sprint(raw)), 10, 64)
				if err != nil || scale <= 0 {
					return 0, fmt.Errorf("PayPal %s 金额换算比例无效", currency)
				}
				if _, err = formatDecimalAmount(scale, scale); err != nil {
					return 0, fmt.Errorf("PayPal %s 金额换算比例无效: %w", currency, err)
				}
				return scale, nil
			}
		}
	}
	if scale := configuredInt64(c, "amount_scale", 0); scale > 0 {
		if _, err := formatDecimalAmount(scale, scale); err != nil {
			return 0, fmt.Errorf("PayPal 金额换算比例无效: %w", err)
		}
		return scale, nil
	}
	switch currency {
	case "HUF", "JPY", "TWD":
		return 1, nil
	default:
		return 100, nil
	}
}

func normalizePayPalOrderState(state string) string {
	switch strings.ToUpper(strings.TrimSpace(state)) {
	case "COMPLETED":
		return "success"
	case "VOIDED":
		return "failed"
	default:
		return "pending"
	}
}

func normalizePayPalCaptureState(state string) string {
	switch strings.ToUpper(strings.TrimSpace(state)) {
	case "COMPLETED", "PARTIALLY_REFUNDED", "REFUNDED":
		return "success"
	case "DECLINED", "FAILED", "DENIED", "VOIDED":
		return "failed"
	default:
		return "pending"
	}
}

func normalizePayPalRefundState(state string) string {
	switch strings.ToUpper(strings.TrimSpace(state)) {
	case "COMPLETED":
		return "success"
	case "CANCELLED", "FAILED":
		return "failed"
	default:
		return "pending"
	}
}

func paypalMapString(values map[string]any, key string) string {
	value := values[key]
	if value == nil {
		return ""
	}
	return strings.TrimSpace(fmt.Sprint(value))
}

func paypalNestedMapString(values map[string]any, keys ...string) string {
	var current any = values
	for _, key := range keys {
		object, ok := current.(map[string]any)
		if !ok {
			return ""
		}
		current = object[key]
	}
	if current == nil {
		return ""
	}
	return strings.TrimSpace(fmt.Sprint(current))
}

func firstNonEmpty(values ...string) string {
	for _, value := range values {
		if value = strings.TrimSpace(value); value != "" && value != "<nil>" {
			return value
		}
	}
	return ""
}

func paypalResponseError(operation string, code int, detail string) error {
	detail = strings.TrimSpace(detail)
	if detail == "" {
		detail = "未知错误"
	}
	if code == 0 {
		return fmt.Errorf("PayPal %s失败: %s", operation, detail)
	}
	return fmt.Errorf("PayPal %s失败(%d): %s", operation, code, detail)
}

func paypalResponseCode(value any) int {
	switch rsp := value.(type) {
	case *paypal.CreateOrderRsp:
		if rsp != nil {
			return rsp.Code
		}
	case *paypal.OrderDetailRsp:
		if rsp != nil {
			return rsp.Code
		}
	case *paypal.PaymentCaptureRefundRsp:
		if rsp != nil {
			return rsp.Code
		}
	}
	return 0
}

func paypalCreateError(rsp *paypal.CreateOrderRsp) string {
	if rsp == nil {
		return "响应为空"
	}
	return paypalErrorDetail(rsp.Error, rsp.ErrorResponse)
}

func paypalOrderError(rsp *paypal.OrderDetailRsp) string {
	if rsp == nil {
		return "响应为空"
	}
	return paypalErrorDetail(rsp.Error, rsp.ErrorResponse)
}

func paypalCaptureError(rsp *paypal.OrderCaptureRsp) string {
	if rsp == nil {
		return "响应为空"
	}
	return paypalErrorDetail(rsp.Error, rsp.ErrorResponse)
}

func paypalRefundError(rsp *paypal.PaymentCaptureRefundRsp) string {
	if rsp == nil {
		return "响应为空"
	}
	return paypalErrorDetail(rsp.Error, rsp.ErrorResponse)
}

func paypalErrorDetail(raw string, response *paypal.ErrorResponse) string {
	if response != nil {
		if value := firstNonEmpty(response.Message, response.Name); value != "" {
			return value
		}
	}
	return raw
}
