package payment

import (
	"context"
	"fmt"
	bizpayment "kra/internal/biz/payment"
	"strings"
)

// Adapter is the provider boundary used by the payment repository. Provider
// SDK types stay in this package and are normalized to biz/payment results.
type Adapter interface {
	Create(context.Context, *bizpayment.PaymentRequest, map[string]any) (*bizpayment.PaymentResult, error)
	Query(context.Context, string, map[string]any) (*bizpayment.PaymentResult, error)
	Refund(context.Context, *bizpayment.PaymentRefundRequest, map[string]any) (*bizpayment.PaymentResult, error)
	Callback(context.Context, *bizpayment.PaymentCallback, map[string]any) (*bizpayment.PaymentResult, error)
}

type adapterFactory func() Adapter

// adapterFactories is the single payment integration registration point.
// Keep constructors zero-state: provider configuration belongs to each call,
// so an adapter can never accidentally retain secrets or order data.
var adapterFactories = map[string]adapterFactory{
	bizpayment.PaymentAlipay:     func() Adapter { return &alipayAdapter{} },
	bizpayment.PaymentAlipayV3:   func() Adapter { return &alipayV3Adapter{} },
	bizpayment.PaymentWechatV2:   func() Adapter { return &wechatV2Adapter{} },
	bizpayment.PaymentWechatV3:   func() Adapter { return &wechatV3Adapter{} },
	bizpayment.PaymentApple:      func() Adapter { return &appleAdapter{} },
	bizpayment.PaymentDouyin:     func() Adapter { return &douyinAdapter{} },
	bizpayment.PaymentQQ:         func() Adapter { return &qqAdapter{} },
	bizpayment.PaymentAllinPay:   func() Adapter { return &allinpayAdapter{} },
	bizpayment.PaymentLakala:     func() Adapter { return &lakalaAdapter{} },
	bizpayment.PaymentPayPal:     func() Adapter { return &paypalAdapter{} },
	bizpayment.PaymentSaobei:     func() Adapter { return &saobeiAdapter{} },
	bizpayment.PaymentChinaums:   func() Adapter { return newVendorAdapter(bizpayment.PaymentChinaums, vendorChinaums) },
	bizpayment.PaymentSFT:        func() Adapter { return newVendorAdapter(bizpayment.PaymentSFT, vendorSFT) },
	bizpayment.PaymentSuperPay:   func() Adapter { return newVendorAdapter(bizpayment.PaymentSuperPay, vendorSupperPay) },
	bizpayment.PaymentWechatGame: func() Adapter { return newVendorAdapter(bizpayment.PaymentWechatGame, vendorWechatGame) },
	bizpayment.PaymentDouyinGame: func() Adapter { return newVendorAdapter(bizpayment.PaymentDouyinGame, vendorDouyinGame) },
}

// New constructs the SDK-backed adapter for a configured provider. Provider
// identifiers are normalized at this I/O boundary so direct callers get the
// same behavior as the configuration and business layers.
func New(provider string) (Adapter, error) {
	provider = strings.ToLower(strings.TrimSpace(provider))
	factory, ok := adapterFactories[provider]
	if !ok {
		return nil, fmt.Errorf("支付渠道 %s 没有适配器", provider)
	}
	return factory(), nil
}
