package payment

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"log/slog"
	"strings"
	"sync"
	"time"

	"kra/pkg/paymentkit"

	"github.com/google/uuid"
)

const (
	PaymentAlipay     = paymentutil.ProviderAlipay
	PaymentAlipayV3   = paymentutil.ProviderAlipayV3
	PaymentWechatV2   = paymentutil.ProviderWechatV2
	PaymentWechatV3   = paymentutil.ProviderWechatV3
	PaymentApple      = paymentutil.ProviderApple
	PaymentChinaums   = paymentutil.ProviderChinaums
	PaymentSFT        = paymentutil.ProviderSFT
	PaymentSuperPay   = paymentutil.ProviderSuperPay
	PaymentWechatGame = paymentutil.ProviderWechatGame
	PaymentDouyinGame = paymentutil.ProviderDouyinGame
	// GoPay-backed providers. These are kept separate from the existing
	// configuration-driven game/aggregator protocols above.
	PaymentDouyin   = paymentutil.ProviderDouyin
	PaymentQQ       = paymentutil.ProviderQQ
	PaymentAllinPay = paymentutil.ProviderAllinPay
	PaymentLakala   = paymentutil.ProviderLakala
	PaymentPayPal   = paymentutil.ProviderPayPal
	PaymentSaobei   = paymentutil.ProviderSaobei
	PaymentInternal = paymentutil.ProviderInternal

	PaymentModeExternal = paymentutil.ModeExternal
	PaymentModeInternal = paymentutil.ModeInternal
)

var SupportedPaymentProviders = paymentutil.SupportedProviders()

var (
	ErrPaymentProviderNotFound  = errors.New("支付渠道未配置")
	ErrPaymentOperationRejected = errors.New("支付操作被平台拒绝")
)

func PaymentRejected(err error) error {
	if err == nil {
		return ErrPaymentOperationRejected
	}
	return fmt.Errorf("%w: %v", ErrPaymentOperationRejected, err)
}

type PaymentRequest struct {
	Provider       string         `json:"provider"`
	TradeNo        string         `json:"tradeNo"`
	Subject        string         `json:"subject"`
	Amount         int64          `json:"amount"`
	Currency       string         `json:"currency"`
	NotifyURL      string         `json:"notifyUrl"`
	ReturnURL      string         `json:"returnUrl"`
	ClientIP       string         `json:"clientIp"`
	Extra          map[string]any `json:"extra"`
	BusinessType   string         `json:"businessType"`
	BusinessID     string         `json:"businessId"`
	PaymentMode    string         `json:"paymentMode"`
	OriginalAmount int64          `json:"originalAmount"`
}

// PaymentRefundRequest carries the durable provider identities needed to
// retry a refund without treating runtime configuration as per-order state.
type PaymentRefundRequest struct {
	Provider        string
	TradeNo         string
	ProviderTradeNo string
	QueryID         string
	RefundNo        string
	Amount          int64
	TotalAmount     int64
	Currency        string
}

// PaymentIntent is the canonical business-facing payment snapshot.
type PaymentIntent struct {
	Provider       string
	TradeNo        string
	BusinessType   string
	BusinessID     string
	Subject        string
	Amount         int64
	Currency       string
	Extra          json.RawMessage
	PaymentMode    string
	OriginalAmount int64
}

// InternalPaymentAuthorization is returned by a business module after it has
// atomically and idempotently deducted points, balance, or another platform
// owned asset. TradeNo must be the idempotency key for the deduction.
type InternalPaymentAuthorization struct {
	AuthorizationID      string
	Amount               int64
	Currency             string
	PayerPaidAmount      int64
	CashPaidAmount       int64
	PointPaidAmount      int64
	DiscountAmount       int64
	SettlementAmount     int64
	PayerCurrency        string
	AmountBreakdownKnown bool
	Payload              json.RawMessage
}

type InternalPaymentRefund struct {
	RefundID string
	Amount   int64
	Currency string
	Payload  json.RawMessage
}

type PaymentInternalPayer interface {
	PayInternal(context.Context, *PaymentIntent) (*InternalPaymentAuthorization, error)
}

type PaymentInternalRefundProcessor interface {
	RefundInternal(context.Context, *PaymentOrder, int64) (*InternalPaymentRefund, error)
}

type PaymentConfirmation struct {
	ID                     string
	Provider               string
	TradeNo                string
	ProviderTradeNo        string
	BusinessType           string
	BusinessID             string
	Subject                string
	Amount                 int64
	OriginalAmount         int64
	PayerPaidAmount        int64
	CashPaidAmount         int64
	PointPaidAmount        int64
	DiscountAmount         int64
	ProviderDiscountAmount int64
	MerchantDiscountAmount int64
	SettlementAmount       int64
	Currency               string
	PayerCurrency          string
	AmountBreakdownKnown   bool
	Payload                json.RawMessage
	CreatedAt              time.Time
}

type PaymentResult struct {
	Provider               string             `json:"provider"`
	Status                 string             `json:"status"`
	TradeNo                string             `json:"tradeNo"`
	ProviderTradeNo        string             `json:"providerTradeNo"`
	Amount                 int64              `json:"amount"`
	PayerPaidAmount        int64              `json:"payerPaidAmount,omitempty"`
	CashPaidAmount         int64              `json:"cashPaidAmount,omitempty"`
	PointPaidAmount        int64              `json:"pointPaidAmount,omitempty"`
	DiscountAmount         int64              `json:"discountAmount,omitempty"`
	ProviderDiscountAmount int64              `json:"providerDiscountAmount,omitempty"`
	MerchantDiscountAmount int64              `json:"merchantDiscountAmount,omitempty"`
	SettlementAmount       int64              `json:"settlementAmount,omitempty"`
	Currency               string             `json:"currency"`
	PayerCurrency          string             `json:"payerCurrency,omitempty"`
	AmountBreakdownKnown   bool               `json:"amountBreakdownKnown"`
	Duplicate              bool               `json:"duplicate"`
	Payload                json.RawMessage    `json:"payload"`
	OrderStatus            string             `json:"orderStatus,omitempty"`
	FulfillmentStatus      string             `json:"fulfillmentStatus,omitempty"`
	RefundStatus           string             `json:"refundStatus,omitempty"`
	EventID                string             `json:"-"`
	QueryID                string             `json:"-"`
	SuccessAck             PaymentCallbackAck `json:"-"`
	FailureAck             PaymentCallbackAck `json:"-"`
}

// PaymentTestStage is one step of a provider connectivity test. A skipped
// query/refund is reported explicitly because a prepay flow cannot be marked
// paid without a sandbox payer interaction.
type PaymentTestStage struct {
	Name     string `json:"name"`
	Status   string `json:"status"`
	Message  string `json:"message,omitempty"`
	TradeNo  string `json:"tradeNo,omitempty"`
	Duration int64  `json:"durationMs,omitempty"`
}

type PaymentTestResult struct {
	Provider string             `json:"provider"`
	TradeNo  string             `json:"tradeNo"`
	Passed   bool               `json:"passed"`
	FullFlow bool               `json:"fullFlow"`
	Mode     string             `json:"mode,omitempty"`
	Stages   []PaymentTestStage `json:"stages"`
	Result   *PaymentResult     `json:"result,omitempty"`
}

type PaymentCallbackAck = paymentutil.CallbackAck
type PaymentCallbackError = paymentutil.CallbackError

func CallbackFailure(err error, fallback PaymentCallbackAck) PaymentCallbackAck {
	return paymentutil.CallbackFailure(err, fallback)
}

func DefaultPaymentCallbackAck(provider string, success bool) PaymentCallbackAck {
	return paymentutil.DefaultCallbackAck(provider, success)
}

type PaymentCallback struct {
	Provider string
	Headers  map[string]string
	Body     []byte
	Query    map[string]string
}

type PaymentRepo interface {
	Create(context.Context, *PaymentRequest) (*PaymentResult, error)
	Query(context.Context, string, string) (*PaymentResult, error)
	Refund(context.Context, *PaymentRefundRequest) (*PaymentResult, error)
	HandleCallback(context.Context, *PaymentCallback) (*PaymentResult, error)
}

type PaymentProviderTester interface {
	TestProvider(context.Context, string) (*PaymentTestResult, error)
}

type PaymentHooks interface {
	BeforeCreate(context.Context, *PaymentRequest) error
}

type NoopPaymentHooks struct{}

func (NoopPaymentHooks) BeforeCreate(context.Context, *PaymentRequest) error { return nil }

type PaymentFulfillmentHandler interface {
	Type() string
	Fulfill(context.Context, *PaymentConfirmation) error
}

type PaymentFulfillmentRegistry struct {
	mu       sync.RWMutex
	handlers map[string]PaymentFulfillmentHandler
}

func NewPaymentFulfillmentRegistry() *PaymentFulfillmentRegistry {
	return &PaymentFulfillmentRegistry{handlers: map[string]PaymentFulfillmentHandler{}}
}

func (r *PaymentFulfillmentRegistry) Register(handler PaymentFulfillmentHandler) error {
	if handler == nil || strings.TrimSpace(handler.Type()) == "" {
		return errors.New("支付发货 handler 无效")
	}
	r.mu.Lock()
	defer r.mu.Unlock()
	if _, exists := r.handlers[handler.Type()]; exists {
		return errors.New("支付发货 handler 已注册: " + handler.Type())
	}
	r.handlers[handler.Type()] = handler
	return nil
}

func (r *PaymentFulfillmentRegistry) Handler(kind string) PaymentFulfillmentHandler {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.handlers[kind]
}

type PaymentUsecase struct {
	repo         PaymentRepo
	orders       PaymentOrderRepo
	hooks        PaymentHooks
	sources      *PaymentOrderSourceRegistry
	fulfillments *PaymentFulfillmentRegistry
	logger       PaymentLogger
}

func NewPaymentUsecase(repo PaymentRepo, orders PaymentOrderRepo, appLogger *slog.Logger) *PaymentUsecase {
	return &PaymentUsecase{
		repo:         repo,
		orders:       orders,
		hooks:        NoopPaymentHooks{},
		sources:      NewPaymentOrderSourceRegistry(),
		fulfillments: NewPaymentFulfillmentRegistry(),
		logger:       NewPaymentLogger(appLogger),
	}
}

func (uc *PaymentUsecase) SetHooks(hooks PaymentHooks) {
	if hooks != nil {
		uc.hooks = hooks
	}
}

func (uc *PaymentUsecase) SetOrderSourceRegistry(registry *PaymentOrderSourceRegistry) {
	if registry != nil {
		uc.sources = registry
	}
}

func (uc *PaymentUsecase) SetFulfillmentRegistry(registry *PaymentFulfillmentRegistry) {
	if registry != nil {
		uc.fulfillments = registry
	}
}

func (uc *PaymentUsecase) RegisterBusinessModule(module PaymentBusinessModule) error {
	if module == nil {
		return errors.New("支付业务模块为空")
	}
	if err := uc.sources.Register(module); err != nil {
		return err
	}
	if err := uc.fulfillments.Register(module); err != nil {
		uc.sources.Unregister(module.Type())
		return err
	}
	return nil
}

func (uc *PaymentUsecase) Order(ctx context.Context, provider, tradeNo string) (*PaymentOrder, error) {
	if uc.orders == nil {
		return nil, errors.New("支付订单仓储未接入")
	}
	if !validPaymentText(provider, 64) || !validPaymentText(tradeNo, 128) {
		return nil, errors.New("支付订单查询参数不完整")
	}
	return uc.orders.FindPaymentOrder(ctx, provider, tradeNo)
}

func (uc *PaymentUsecase) Orders(ctx context.Context, page, pageSize int, filter PaymentOrderFilter) ([]*PaymentOrder, int64, error) {
	if uc.orders == nil {
		return nil, 0, errors.New("支付订单仓储未接入")
	}
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 10
	}
	return uc.orders.ListPaymentOrders(ctx, page, pageSize, filter)
}

func (uc *PaymentUsecase) Create(ctx context.Context, req *PaymentRequest) (*PaymentResult, error) {
	if req == nil || !validPaymentText(req.Provider, 64) || !validPaymentText(req.TradeNo, 128) || !validPaymentText(req.BusinessType, 64) || !validPaymentText(req.BusinessID, 128) {
		return nil, errors.New("支付参数不完整")
	}
	if !supportedPaymentProvider(req.Provider) {
		return nil, errors.New("不支持的支付渠道")
	}
	if uc.orders == nil {
		return nil, errors.New("支付订单仓储未接入")
	}
	prepared, err := uc.preparePaymentRequest(ctx, req)
	if err != nil {
		return nil, err
	}
	req = prepared
	if !validPaymentText(req.Currency, 16) || !validPaymentText(req.Subject, 256) || req.Amount <= 0 {
		return nil, errors.New("支付订单金额、币种或标题无效")
	}
	req.PaymentMode = defaultPaymentMode(req.Provider, req.PaymentMode)
	if req.PaymentMode != PaymentModeExternal && req.PaymentMode != PaymentModeInternal {
		return nil, ErrPaymentOrderConflict
	}
	if req.Provider == PaymentInternal && req.PaymentMode != PaymentModeInternal {
		return nil, ErrPaymentOrderConflict
	}
	if req.Provider != PaymentInternal && req.PaymentMode == PaymentModeInternal {
		return nil, ErrPaymentOrderConflict
	}
	if req.OriginalAmount <= 0 {
		req.OriginalAmount = req.Amount
	}
	if req.OriginalAmount < req.Amount {
		return nil, errors.New("原始金额不能小于支付订单金额")
	}
	canonicalProvider, canonicalTradeNo := req.Provider, req.TradeNo
	canonicalBusinessType, canonicalBusinessID := req.BusinessType, req.BusinessID
	canonicalSubject, canonicalCurrency, canonicalAmount := req.Subject, req.Currency, req.Amount
	canonicalOriginalAmount, canonicalPaymentMode := req.OriginalAmount, req.PaymentMode
	canonicalExtra, err := json.Marshal(req.Extra)
	if err != nil {
		return nil, fmt.Errorf("支付扩展参数无效: %w", err)
	}
	if err := uc.hooks.BeforeCreate(ctx, req); err != nil {
		return nil, err
	}
	currentExtra, err := json.Marshal(req.Extra)
	if err != nil {
		return nil, fmt.Errorf("支付扩展参数无效: %w", err)
	}
	if req.Provider != canonicalProvider || req.TradeNo != canonicalTradeNo || req.BusinessType != canonicalBusinessType || req.BusinessID != canonicalBusinessID || req.Subject != canonicalSubject || req.Currency != canonicalCurrency || req.Amount != canonicalAmount || req.OriginalAmount != canonicalOriginalAmount || req.PaymentMode != canonicalPaymentMode || string(currentExtra) != string(canonicalExtra) {
		return nil, ErrPaymentOrderConflict
	}
	return uc.createWithOrder(ctx, req)
}

func (uc *PaymentUsecase) preparePaymentRequest(ctx context.Context, req *PaymentRequest) (*PaymentRequest, error) {
	source := uc.sources.Source(req.BusinessType)
	if source == nil {
		return nil, fmt.Errorf("支付业务订单来源未注册: %s", req.BusinessType)
	}
	intent, err := source.PreparePayment(ctx, req.Provider, req.TradeNo, req.BusinessID)
	if err != nil {
		return nil, err
	}
	if intent == nil || intent.Provider != req.Provider || intent.TradeNo != req.TradeNo || intent.BusinessType != req.BusinessType || intent.BusinessID != req.BusinessID {
		return nil, ErrPaymentOrderConflict
	}
	prepared := *req
	prepared.Subject = intent.Subject
	prepared.Amount = intent.Amount
	prepared.Currency = strings.ToUpper(intent.Currency)
	prepared.PaymentMode = defaultPaymentMode(intent.Provider, intent.PaymentMode)
	prepared.OriginalAmount = intent.OriginalAmount
	if prepared.OriginalAmount <= 0 {
		prepared.OriginalAmount = prepared.Amount
	}
	prepared.Extra = mergeCanonicalPaymentExtra(req.Extra, intent.Extra)
	return &prepared, nil
}

func mergeCanonicalPaymentExtra(client map[string]any, canonical json.RawMessage) map[string]any {
	merged := make(map[string]any, len(client)+4)
	for key, value := range client {
		merged[key] = value
	}
	var values map[string]any
	if json.Unmarshal(canonical, &values) == nil {
		for key, value := range values {
			merged[key] = value
		}
	}
	return merged
}

func supportedPaymentProvider(provider string) bool {
	if provider == PaymentInternal {
		return true
	}
	for _, supported := range SupportedPaymentProviders {
		if provider == supported {
			return true
		}
	}
	return false
}

func (uc *PaymentUsecase) Query(ctx context.Context, provider, tradeNo string) (*PaymentResult, error) {
	if !validPaymentText(provider, 64) || !validPaymentText(tradeNo, 128) {
		return nil, errors.New("查询支付参数不完整")
	}
	if uc.orders == nil {
		return nil, errors.New("支付订单仓储未接入")
	}
	order, err := uc.orders.FindPaymentOrder(ctx, provider, tradeNo)
	if err != nil {
		return nil, err
	}
	if provider == PaymentInternal || order.PaymentMode == PaymentModeInternal {
		return paymentResultFromOrder(order), nil
	}
	queryID := tradeNo
	if order.QueryID != "" {
		queryID = order.QueryID
	} else if provider == PaymentApple {
		if order.ProviderTradeNo == "" {
			return nil, ErrPaymentOrderState
		}
		queryID = order.ProviderTradeNo
	}
	result, err := uc.repo.Query(ctx, provider, queryID)
	if err != nil {
		uc.logger.Error(ctx, "payment.query.failed", "provider", provider, "trade_no", tradeNo, "query_id", queryID, "error", err)
		return nil, err
	}
	if err = validatePaymentQueryResult(provider, queryID, result); err != nil {
		uc.logger.Error(ctx, "payment.query.invalid", "provider", provider, "trade_no", tradeNo, "query_id", queryID, "error", err)
		return nil, err
	}
	if result.TradeNo != tradeNo {
		return nil, errors.New("支付平台查单商户订单号不匹配")
	}
	return uc.reconcilePaymentResult(ctx, result, nil)
}

func (uc *PaymentUsecase) Refund(ctx context.Context, provider, tradeNo string, amount int64) (*PaymentResult, error) {
	if !validPaymentText(provider, 64) || !validPaymentText(tradeNo, 128) || amount <= 0 {
		return nil, errors.New("退款参数不完整")
	}
	if uc.orders == nil {
		return nil, errors.New("支付订单仓储未接入")
	}
	return uc.refundWithOrder(ctx, provider, tradeNo, amount)
}

// TestProvider exercises the configured provider without requiring a business
// module or a real customer order. Provider adapters use their configured
// sandbox/test endpoint when one is selected in integration settings.
func (uc *PaymentUsecase) TestProvider(ctx context.Context, provider string) (*PaymentTestResult, error) {
	provider = strings.TrimSpace(provider)
	if !supportedPaymentProvider(provider) {
		return nil, errors.New("不支持的支付渠道")
	}
	tester, ok := uc.repo.(PaymentProviderTester)
	if !ok {
		return nil, errors.New("支付渠道仓储未接入")
	}
	return tester.TestProvider(ctx, provider)
}

// Fulfill retries delivery for an already-paid order. It is intentionally
// idempotent: the repository lease prevents concurrent attempts and a
// succeeded order is returned as a duplicate without invoking the handler.
func (uc *PaymentUsecase) Fulfill(ctx context.Context, provider, tradeNo string) (*PaymentResult, error) {
	if !validPaymentText(provider, 64) || !validPaymentText(tradeNo, 128) {
		return nil, errors.New("发货参数不完整")
	}
	if uc.orders == nil {
		return nil, errors.New("支付订单仓储未接入")
	}
	order, err := uc.orders.FindPaymentOrder(ctx, provider, tradeNo)
	if err != nil {
		return nil, err
	}
	result := paymentResultFromOrder(order)
	if result == nil {
		return nil, ErrPaymentOrderNotFound
	}
	if order.PaymentStatus != PaymentStatusPaid {
		return nil, ErrPaymentOrderState
	}
	return uc.fulfillOrder(ctx, order, result)
}

// Callback verifies the notification in the adapter, then always performs a
// provider-side query before it can dispatch fulfillment. Callback payloads
// are never trusted for amount, currency, or final payment state.
func (uc *PaymentUsecase) Callback(ctx context.Context, callback *PaymentCallback) (*PaymentResult, error) {
	if callback == nil || strings.TrimSpace(callback.Provider) == "" || len(callback.Body) == 0 {
		err := errors.New("支付回调参数不完整")
		uc.logger.Error(ctx, "payment.callback.invalid", "error", err)
		return nil, err
	}
	if uc.orders == nil {
		return nil, errors.New("支付订单仓储未接入")
	}
	return uc.callbackWithOrder(ctx, callback)
}

func (uc *PaymentUsecase) createWithOrder(ctx context.Context, req *PaymentRequest) (*PaymentResult, error) {
	extra, err := json.Marshal(req.Extra)
	if err != nil {
		return nil, fmt.Errorf("支付扩展参数无效: %w", err)
	}
	if len(extra) == 0 || string(extra) == "null" {
		extra = []byte("{}")
	}
	order := &PaymentOrder{
		TradeNo:            req.TradeNo,
		Provider:           req.Provider,
		BusinessType:       req.BusinessType,
		BusinessID:         req.BusinessID,
		Subject:            req.Subject,
		PaymentMode:        defaultPaymentMode(req.Provider, req.PaymentMode),
		OriginalAmount:     req.OriginalAmount,
		Amount:             req.Amount,
		Currency:           strings.ToUpper(req.Currency),
		PaymentStatus:      PaymentStatusInitialized,
		FulfillmentStatus:  FulfillmentStatusPending,
		RefundStatus:       RefundStatusNone,
		ConfirmationID:     paymentConfirmationID(req.Provider, req.TradeNo),
		RequestFingerprint: paymentOrderFingerprint(req, extra),
		Extra:              extra,
	}
	order, created, err := uc.orders.CreatePaymentOrder(ctx, order)
	if err != nil {
		return nil, err
	}
	if order.RequestFingerprint != paymentOrderFingerprint(req, extra) {
		return nil, ErrPaymentOrderConflict
	}
	if !created && len(order.CreatePayload) > 0 && string(order.CreatePayload) != "{}" {
		return paymentResultFromOrder(order), nil
	}
	if req.Provider == PaymentInternal || order.PaymentMode == PaymentModeInternal {
		source := uc.sources.Source(req.BusinessType)
		payer, ok := source.(PaymentInternalPayer)
		if !ok {
			return nil, fmt.Errorf("支付业务未实现内部支付: %s", req.BusinessType)
		}
		authorization, err := payer.PayInternal(ctx, &PaymentIntent{
			Provider: req.Provider, TradeNo: req.TradeNo, BusinessType: req.BusinessType,
			BusinessID: req.BusinessID, Subject: req.Subject, Amount: req.Amount,
			Currency: req.Currency, Extra: extra, PaymentMode: PaymentModeInternal,
			OriginalAmount: req.OriginalAmount,
		})
		if err != nil {
			return nil, err
		}
		if authorization == nil || authorization.AuthorizationID == "" || authorization.Amount != req.Amount || !strings.EqualFold(authorization.Currency, req.Currency) {
			return nil, errors.New("内部支付授权结果无效")
		}
		result := &PaymentResult{
			Provider: PaymentInternal, Status: "success", TradeNo: req.TradeNo,
			ProviderTradeNo: authorization.AuthorizationID, QueryID: authorization.AuthorizationID,
			Amount: req.Amount, PayerPaidAmount: authorization.PayerPaidAmount,
			CashPaidAmount: authorization.CashPaidAmount, PointPaidAmount: authorization.PointPaidAmount,
			DiscountAmount: authorization.DiscountAmount, SettlementAmount: authorization.SettlementAmount,
			Currency: strings.ToUpper(req.Currency), PayerCurrency: strings.ToUpper(authorization.PayerCurrency),
			AmountBreakdownKnown: authorization.AmountBreakdownKnown, Payload: authorization.Payload,
		}
		if result.PayerCurrency == "" {
			result.PayerCurrency = result.Currency
		}
		if !authorization.AmountBreakdownKnown {
			return nil, errors.New("内部支付必须返回完整金额拆分")
		}
		if err = validatePaymentBreakdown(result); err != nil {
			return nil, fmt.Errorf("内部支付金额拆分无效: %w", err)
		}
		if _, err = uc.orders.RecordPaymentCreate(ctx, req.Provider, req.TradeNo, paymentProviderUpdate(result)); err != nil {
			return nil, err
		}
		return uc.reconcilePaymentResult(ctx, result, nil)
	}

	uc.logger.Info(ctx, "payment.order.create", "provider", req.Provider, "trade_no", req.TradeNo, "business_type", req.BusinessType, "business_id", req.BusinessID)
	result, err := uc.repo.Create(ctx, req)
	if err != nil {
		uc.logger.Error(ctx, "payment.order.provider_create_failed", "provider", req.Provider, "trade_no", req.TradeNo, "error", err)
		return nil, err
	}
	if err = validatePaymentCreateResult(req, result); err != nil {
		uc.logger.Error(ctx, "payment.order.provider_create_invalid", "provider", req.Provider, "trade_no", req.TradeNo, "error", err)
		return nil, err
	}
	order, err = uc.orders.RecordPaymentCreate(ctx, req.Provider, req.TradeNo, paymentProviderUpdate(result))
	if err != nil {
		uc.logger.Error(ctx, "payment.order.provider_create_record_failed", "provider", req.Provider, "trade_no", req.TradeNo, "error", err)
		return nil, err
	}
	if strings.EqualFold(result.Status, "success") {
		result.Status = "pending"
	}
	return attachOrderResult(result, order), nil
}

func (uc *PaymentUsecase) callbackWithOrder(ctx context.Context, callback *PaymentCallback) (*PaymentResult, error) {
	callbackResult, err := uc.repo.HandleCallback(ctx, callback)
	if err != nil {
		uc.logger.Error(ctx, "payment.callback.verify_failed", "provider", callback.Provider, "error", err)
		return nil, err
	}
	if callbackResult == nil || callbackResult.Provider != callback.Provider || !validPaymentText(callbackResult.TradeNo, 128) || (callbackResult.QueryID != "" && !validPaymentText(callbackResult.QueryID, 128)) {
		err = errors.New("支付回调渠道或商户订单号校验失败")
		return nil, callbackResultError(callbackResult, err)
	}
	queryID := callbackResult.QueryID
	if queryID == "" {
		queryID = callbackResult.TradeNo
	}
	queryResult, err := uc.repo.Query(ctx, callbackResult.Provider, queryID)
	if err != nil {
		uc.logger.Error(ctx, "payment.callback.query_failed", "provider", callbackResult.Provider, "trade_no", callbackResult.TradeNo, "event_id", callbackResult.EventID, "error", err)
		return nil, callbackResultError(callbackResult, err)
	}
	if err = validatePaymentQueryResult(callbackResult.Provider, queryID, queryResult); err != nil {
		uc.logger.Error(ctx, "payment.callback.query_invalid", "provider", callbackResult.Provider, "trade_no", callbackResult.TradeNo, "event_id", callbackResult.EventID, "error", err)
		return nil, callbackResultError(callbackResult, err)
	}
	if queryResult.TradeNo != callbackResult.TradeNo {
		err = errors.New("支付回调商户订单号与主动查单结果不匹配")
		return nil, callbackResultError(callbackResult, err)
	}
	queryResult = clonePaymentResult(queryResult)
	queryResult.EventID = callbackResult.EventID
	queryResult.SuccessAck = callbackResult.SuccessAck
	queryResult.FailureAck = callbackResult.FailureAck
	return uc.reconcilePaymentResult(ctx, queryResult, callbackResult)
}

func (uc *PaymentUsecase) reconcilePaymentResult(ctx context.Context, result, callbackSource *PaymentResult) (*PaymentResult, error) {
	if result == nil {
		return nil, errors.New("支付查单结果为空")
	}
	fail := func(err error) (*PaymentResult, error) {
		if callbackSource != nil {
			return nil, callbackResultError(callbackSource, err)
		}
		return nil, err
	}
	order, err := uc.orders.FindPaymentOrder(ctx, result.Provider, result.TradeNo)
	if err != nil {
		uc.logger.Error(ctx, "payment.order.not_found", "provider", result.Provider, "trade_no", result.TradeNo, "error", err)
		return fail(err)
	}
	if strings.EqualFold(result.Status, "success") {
		if err = validatePaymentConfirmation(order.Intent(), result.Provider, result.TradeNo, result); err != nil {
			uc.logger.Error(ctx, "payment.order.validation_failed", "provider", result.Provider, "trade_no", result.TradeNo, "error", err)
			return fail(err)
		}
	}
	order, err = uc.orders.ApplyPaymentResult(ctx, result.Provider, result.TradeNo, paymentProviderUpdate(result))
	if err != nil {
		uc.logger.Error(ctx, "payment.order.result_record_failed", "provider", result.Provider, "trade_no", result.TradeNo, "error", err)
		return fail(err)
	}
	result = attachOrderResult(result, order)
	if !strings.EqualFold(result.Status, "success") {
		return result, nil
	}

	fulfilled, err := uc.fulfillOrder(ctx, order, result)
	if err != nil {
		return fail(err)
	}
	return fulfilled, nil
}

func (uc *PaymentUsecase) fulfillOrder(ctx context.Context, order *PaymentOrder, result *PaymentResult) (*PaymentResult, error) {
	if order == nil || result == nil {
		return nil, errors.New("支付发货订单为空")
	}
	order, token, duplicate, err := uc.orders.BeginPaymentFulfillment(ctx, result.Provider, result.TradeNo, 10*time.Minute)
	if err != nil {
		uc.logger.Error(ctx, "payment.order.fulfillment_begin_failed", "provider", result.Provider, "trade_no", result.TradeNo, "error", err)
		return nil, err
	}
	if duplicate {
		result.Duplicate = true
		result.Status = "fulfilled"
		return attachOrderResult(result, order), nil
	}
	handler := uc.fulfillments.Handler(order.BusinessType)
	if handler == nil {
		err = fmt.Errorf("支付发货 handler 未注册: %s", order.BusinessType)
		_, _ = uc.orders.CompletePaymentFulfillment(ctx, result.Provider, result.TradeNo, token, false, err.Error())
		return nil, err
	}
	confirmation := &PaymentConfirmation{ID: order.ConfirmationID, Provider: order.Provider, TradeNo: order.TradeNo,
		ProviderTradeNo: result.ProviderTradeNo, BusinessType: order.BusinessType, BusinessID: order.BusinessID,
		Subject: order.Subject, Amount: order.Amount, OriginalAmount: order.OriginalAmount,
		PayerPaidAmount: order.PayerPaidAmount, CashPaidAmount: order.CashPaidAmount, PointPaidAmount: order.PointPaidAmount,
		DiscountAmount: order.DiscountAmount, ProviderDiscountAmount: order.ProviderDiscountAmount,
		MerchantDiscountAmount: order.MerchantDiscountAmount, SettlementAmount: order.SettlementAmount,
		Currency: order.Currency, PayerCurrency: order.PayerCurrency, AmountBreakdownKnown: order.AmountBreakdownKnown,
		Payload: result.Payload, CreatedAt: time.Now().UTC()}
	if err = handler.Fulfill(ctx, confirmation); err != nil {
		_, _ = uc.orders.CompletePaymentFulfillment(ctx, result.Provider, result.TradeNo, token, false, err.Error())
		return nil, err
	}
	order, err = uc.orders.CompletePaymentFulfillment(ctx, result.Provider, result.TradeNo, token, true, "")
	if err != nil {
		return nil, err
	}
	result.Status = "fulfilled"
	return attachOrderResult(result, order), nil
}

func (uc *PaymentUsecase) refundWithOrder(ctx context.Context, provider, tradeNo string, amount int64) (*PaymentResult, error) {
	current, err := uc.orders.FindPaymentOrder(ctx, provider, tradeNo)
	if err != nil {
		return nil, err
	}
	handler := uc.fulfillments.Handler(current.BusinessType)
	authorizer, ok := handler.(PaymentRefundAuthorizer)
	if !ok {
		return nil, fmt.Errorf("支付业务未实现退款授权: %s", current.BusinessType)
	}
	if err = authorizer.AuthorizeRefund(ctx, current, amount); err != nil {
		return nil, err
	}
	order, token, err := uc.orders.BeginPaymentRefund(ctx, provider, tradeNo, amount, 10*time.Minute)
	if err != nil {
		return nil, err
	}
	if provider == PaymentInternal || current.PaymentMode == PaymentModeInternal {
		processor, ok := handler.(PaymentInternalRefundProcessor)
		if !ok {
			_, _ = uc.orders.CompletePaymentRefundRequest(ctx, provider, tradeNo, token, false, "支付业务未实现内部退款")
			return nil, fmt.Errorf("支付业务未实现内部退款: %s", current.BusinessType)
		}
		refund, refundErr := processor.RefundInternal(ctx, order, amount)
		accepted := refundErr == nil && refund != nil && refund.Amount == amount && strings.EqualFold(refund.Currency, current.Currency)
		message := ""
		if refundErr != nil {
			message = refundErr.Error()
		} else if !accepted {
			message = "内部退款结果无效"
		}
		if refundErr != nil && !errors.Is(refundErr, ErrPaymentOperationRejected) {
			return nil, refundErr
		}
		if refundErr == nil && refund == nil {
			return nil, errors.New("内部退款结果为空")
		}
		if _, err = uc.orders.CompletePaymentRefundRequest(ctx, provider, tradeNo, token, accepted, message); err != nil {
			return nil, err
		}
		if !accepted {
			return nil, errors.New(message)
		}
		order, err = uc.orders.ConfirmPaymentRefund(ctx, provider, tradeNo, order.RefundNo, amount, true, "")
		if err != nil {
			return nil, err
		}
		return attachOrderResult(&PaymentResult{Provider: provider, TradeNo: tradeNo, ProviderTradeNo: refund.RefundID, Amount: amount, Currency: current.Currency, Payload: refund.Payload, Status: "refunded"}, order), nil
	}
	result, providerErr := uc.repo.Refund(ctx, &PaymentRefundRequest{
		Provider:        order.Provider,
		TradeNo:         order.TradeNo,
		ProviderTradeNo: order.ProviderTradeNo,
		QueryID:         order.QueryID,
		RefundNo:        order.RefundNo,
		Amount:          amount,
		TotalAmount:     order.Amount,
		Currency:        order.Currency,
	})
	if providerErr == nil {
		providerErr = validatePaymentRefundResult(provider, tradeNo, result)
	}
	if providerErr != nil && !errors.Is(providerErr, ErrPaymentOperationRejected) {
		// A timeout or malformed response cannot prove that the provider did not
		// accept the refund. Keep the durable refund operation and its idempotency
		// number; the lease expiry path will retry the same operation.
		return nil, providerErr
	}
	accepted := providerErr == nil
	message := ""
	if providerErr != nil {
		message = providerErr.Error()
	} else if !accepted {
		message = "支付平台未接受退款请求"
	}
	order, err = uc.orders.CompletePaymentRefundRequest(ctx, provider, tradeNo, token, accepted, message)
	if err != nil {
		return nil, err
	}
	if !accepted {
		if providerErr != nil {
			return nil, providerErr
		}
		return nil, errors.New(message)
	}
	result.Status = "refund_pending"
	return attachOrderResult(result, order), nil
}

// ConfirmRefund is called by a provider-specific refund notification or a
// reconciliation worker after the platform reports the final refund state.
func (uc *PaymentUsecase) ConfirmRefund(ctx context.Context, provider, tradeNo, refundNo string, amount int64, success bool, message string) (*PaymentResult, error) {
	if uc.orders == nil {
		return nil, errors.New("支付订单仓储未接入")
	}
	if !validPaymentText(provider, 64) || !validPaymentText(tradeNo, 128) || !validPaymentText(refundNo, 128) || amount <= 0 {
		return nil, errors.New("退款确认参数无效")
	}
	order, err := uc.orders.ConfirmPaymentRefund(ctx, provider, tradeNo, refundNo, amount, success, message)
	if err != nil {
		return nil, err
	}
	result := &PaymentResult{Provider: provider, TradeNo: tradeNo, Status: "refund_failed"}
	if success {
		result.Status = "refunded"
	}
	return attachOrderResult(result, order), nil
}

func paymentProviderUpdate(result *PaymentResult) *PaymentProviderUpdate {
	if result == nil {
		return &PaymentProviderUpdate{}
	}
	var payloadHash string
	if len(result.Payload) > 0 {
		sum := sha256.Sum256(result.Payload)
		payloadHash = hex.EncodeToString(sum[:])
	}
	return &PaymentProviderUpdate{
		Status: result.Status, ProviderStatus: result.Status, ProviderTradeNo: result.ProviderTradeNo,
		QueryID: result.QueryID, Amount: result.Amount, PayerPaidAmount: result.PayerPaidAmount,
		CashPaidAmount: result.CashPaidAmount, PointPaidAmount: result.PointPaidAmount, DiscountAmount: result.DiscountAmount,
		ProviderDiscountAmount: result.ProviderDiscountAmount, MerchantDiscountAmount: result.MerchantDiscountAmount,
		SettlementAmount: result.SettlementAmount, Currency: result.Currency, PayerCurrency: result.PayerCurrency,
		AmountBreakdownKnown: result.AmountBreakdownKnown,
		EventID:              result.EventID, PayloadHash: payloadHash, CreatePayload: result.Payload,
	}
}

func paymentOrderFingerprint(req *PaymentRequest, extra json.RawMessage) string {
	value, _ := json.Marshal(map[string]any{
		"provider": req.Provider, "trade_no": req.TradeNo, "business_type": req.BusinessType,
		"business_id": req.BusinessID, "subject": req.Subject, "amount": req.Amount,
		"original_amount": req.OriginalAmount, "payment_mode": defaultPaymentMode(req.Provider, req.PaymentMode),
		"currency": strings.ToUpper(req.Currency), "extra": json.RawMessage(extra),
	})
	sum := sha256.Sum256(value)
	return hex.EncodeToString(sum[:])
}

func paymentResultFromOrder(order *PaymentOrder) *PaymentResult {
	if order == nil {
		return nil
	}
	status := "pending"
	switch order.PaymentStatus {
	case PaymentStatusPaid:
		status = "success"
	case PaymentStatusPartiallyRefunded:
		status = "partially_refunded"
	case PaymentStatusRefunded:
		status = "refunded"
	case PaymentStatusFailed, PaymentStatusClosed:
		status = "failed"
	}
	if order.FulfillmentStatus == FulfillmentStatusSucceeded && status == "success" {
		status = "fulfilled"
	}
	amount := order.PaidAmount
	if amount == 0 {
		amount = order.Amount
	}
	return &PaymentResult{
		Provider: order.Provider, Status: status, TradeNo: order.TradeNo,
		ProviderTradeNo: order.ProviderTradeNo, Amount: amount, PayerPaidAmount: order.PayerPaidAmount,
		CashPaidAmount: order.CashPaidAmount, PointPaidAmount: order.PointPaidAmount, DiscountAmount: order.DiscountAmount,
		ProviderDiscountAmount: order.ProviderDiscountAmount, MerchantDiscountAmount: order.MerchantDiscountAmount,
		SettlementAmount: order.SettlementAmount, Currency: order.Currency, PayerCurrency: order.PayerCurrency,
		AmountBreakdownKnown: order.AmountBreakdownKnown,
		Payload:              append(json.RawMessage(nil), order.CreatePayload...), OrderStatus: order.PaymentStatus,
		FulfillmentStatus: order.FulfillmentStatus, RefundStatus: order.RefundStatus,
	}
}

func attachOrderResult(result *PaymentResult, order *PaymentOrder) *PaymentResult {
	if result == nil {
		result = paymentResultFromOrder(order)
		return result
	}
	if order == nil {
		return result
	}
	result.OrderStatus = order.PaymentStatus
	result.FulfillmentStatus = order.FulfillmentStatus
	result.RefundStatus = order.RefundStatus
	return result
}

func validatePaymentQueryResult(provider, queryID string, result *PaymentResult) error {
	if result == nil {
		return errors.New("支付平台查单结果为空")
	}
	if result.Provider != provider || !validPaymentText(result.TradeNo, 128) {
		return errors.New("支付平台查单渠道或商户订单号无效")
	}
	if result.QueryID != "" {
		if result.QueryID != queryID {
			return errors.New("支付平台查单键不匹配")
		}
	} else if result.TradeNo != queryID {
		return errors.New("支付平台查单商户订单号不匹配")
	}
	switch strings.ToLower(strings.TrimSpace(result.Status)) {
	case "success":
		if !validPaymentText(result.ProviderTradeNo, 128) {
			return errors.New("支付平台查单成功但缺少平台交易号")
		}
		if result.Amount <= 0 {
			return errors.New("支付平台查单成功但金额无效")
		}
		if !validPaymentText(result.Currency, 16) {
			return errors.New("支付平台查单成功但币种为空")
		}
	case "pending", "failed":
	default:
		return fmt.Errorf("支付平台查单返回未知状态: %s", result.Status)
	}
	return nil
}

func validatePaymentCreateResult(req *PaymentRequest, result *PaymentResult) error {
	if req == nil || result == nil {
		return errors.New("支付平台下单结果为空")
	}
	if result.Provider != req.Provider || result.TradeNo != req.TradeNo {
		return errors.New("支付平台下单结果渠道或商户订单号不匹配")
	}
	if result.ProviderTradeNo != "" && !validPaymentText(result.ProviderTradeNo, 128) {
		return errors.New("支付平台交易号无效")
	}
	if result.QueryID != "" && !validPaymentText(result.QueryID, 128) {
		return errors.New("支付平台查单键无效")
	}
	switch strings.ToLower(strings.TrimSpace(result.Status)) {
	case "created", "client_pending", "pending", "processing", "success":
		return nil
	default:
		return fmt.Errorf("支付平台下单返回未知状态: %s", result.Status)
	}
}

func validatePaymentRefundResult(provider, tradeNo string, result *PaymentResult) error {
	if result == nil {
		return errors.New("支付平台退款结果为空")
	}
	if result.Provider != provider || result.TradeNo != tradeNo {
		return errors.New("支付平台退款结果渠道或商户订单号不匹配")
	}
	if result.ProviderTradeNo != "" && !validPaymentText(result.ProviderTradeNo, 128) {
		return errors.New("支付平台退款交易号无效")
	}
	switch strings.ToLower(strings.TrimSpace(result.Status)) {
	case "created", "pending", "processing", "success", "refunded":
		return nil
	case "failed":
		return PaymentRejected(errors.New("支付平台拒绝退款请求"))
	default:
		return fmt.Errorf("支付平台退款返回未知状态: %s", result.Status)
	}
}

func validPaymentText(value string, maxBytes int) bool {
	trimmed := strings.TrimSpace(value)
	if trimmed == "" || trimmed != value || len(value) > maxBytes {
		return false
	}
	for _, r := range value {
		if r < 0x20 || r == 0x7f {
			return false
		}
	}
	return true
}

func callbackResultError(result *PaymentResult, err error) error {
	if err == nil {
		return nil
	}
	if result == nil || result.FailureAck.StatusCode == 0 {
		return err
	}
	return &PaymentCallbackError{Cause: err, Ack: result.FailureAck}
}

func validatePaymentConfirmation(intent *PaymentIntent, provider, tradeNo string, result *PaymentResult) error {
	if intent == nil || result == nil {
		return errors.New("支付确认数据为空")
	}
	if !strings.EqualFold(intent.Provider, provider) || intent.TradeNo != tradeNo || intent.TradeNo == "" {
		return errors.New("支付商户订单号校验失败")
	}
	if strings.ToLower(result.Status) != "success" || result.Provider != provider || result.TradeNo != tradeNo {
		return errors.New("支付平台订单状态校验失败")
	}
	if result.ProviderTradeNo == "" || result.Amount <= 0 || intent.Amount <= 0 || result.Amount != intent.Amount {
		return errors.New("支付金额校验失败")
	}
	if result.PayerPaidAmount < 0 || result.CashPaidAmount < 0 || result.PointPaidAmount < 0 || result.DiscountAmount < 0 || result.ProviderDiscountAmount < 0 || result.MerchantDiscountAmount < 0 || result.SettlementAmount < 0 {
		return errors.New("支付优惠或实付金额校验失败")
	}
	if result.AmountBreakdownKnown {
		if err := validatePaymentBreakdown(result); err != nil {
			return err
		}
	}
	if strings.TrimSpace(intent.Currency) == "" || strings.TrimSpace(result.Currency) == "" || !strings.EqualFold(intent.Currency, result.Currency) {
		return errors.New("支付币种校验失败")
	}
	if strings.TrimSpace(intent.BusinessType) == "" || strings.TrimSpace(intent.BusinessID) == "" {
		return errors.New("支付业务标识不完整")
	}
	if provider == PaymentApple {
		if err := validateAppleProduct(intent.Extra, result.Payload); err != nil {
			return err
		}
	}
	return nil
}

func validateAppleProduct(intentExtra, providerPayload json.RawMessage) error {
	var expected struct {
		ProductID string `json:"product_id"`
	}
	if err := json.Unmarshal(intentExtra, &expected); err != nil {
		return errors.New("Apple 支付订单商品配置无效")
	}
	expected.ProductID = strings.TrimSpace(expected.ProductID)
	if expected.ProductID == "" {
		return errors.New("Apple 支付订单缺少 product_id")
	}
	var actual struct {
		ProductID string `json:"productId"`
	}
	if err := json.Unmarshal(providerPayload, &actual); err != nil {
		return errors.New("Apple 交易载荷无效")
	}
	actual.ProductID = strings.TrimSpace(actual.ProductID)
	if actual.ProductID == "" || actual.ProductID != expected.ProductID {
		return errors.New("Apple 交易 productId 与业务订单不匹配")
	}
	return nil
}

func validatePaymentBreakdown(result *PaymentResult) error {
	if result == nil {
		return errors.New("支付金额拆分为空")
	}
	payerCurrency := result.PayerCurrency
	if payerCurrency == "" {
		payerCurrency = result.Currency
	}
	if strings.EqualFold(payerCurrency, result.Currency) {
		if result.PayerPaidAmount > result.Amount || result.DiscountAmount > result.Amount-result.PayerPaidAmount || result.PayerPaidAmount+result.DiscountAmount != result.Amount {
			return errors.New("支付总额、实付和优惠金额不守恒")
		}
		if result.CashPaidAmount > result.PayerPaidAmount || result.PointPaidAmount > result.PayerPaidAmount-result.CashPaidAmount || result.CashPaidAmount+result.PointPaidAmount != result.PayerPaidAmount {
			return errors.New("支付现金和积分金额不守恒")
		}
	}
	if result.ProviderDiscountAmount > result.DiscountAmount || result.MerchantDiscountAmount > result.DiscountAmount-result.ProviderDiscountAmount {
		return errors.New("支付优惠出资金额超过总优惠")
	}
	if result.SettlementAmount > result.Amount {
		return errors.New("支付结算金额超过订单总额")
	}
	return nil
}

func paymentConfirmationID(provider, tradeNo string) string {
	return uuid.NewSHA1(uuid.Nil, []byte(provider+"\x00"+tradeNo)).String()
}

func clonePaymentResult(result *PaymentResult) *PaymentResult {
	if result == nil {
		return nil
	}
	cloned := *result
	cloned.Payload = append(json.RawMessage(nil), result.Payload...)
	cloned.SuccessAck.Body = append([]byte(nil), result.SuccessAck.Body...)
	cloned.FailureAck.Body = append([]byte(nil), result.FailureAck.Body...)
	return &cloned
}
