package payment

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	bizpayment "kra/internal/biz/payment"
	"net/url"
	"strings"
	"testing"
)

func TestWechatV2SignOfficialStyle(t *testing.T) {
	values := map[string]string{
		"appid": "wxd930ea5d5a258f4f", "mch_id": "10000100", "device_info": "1000",
		"body": "test", "nonce_str": "ibuaiVcKdpRxkhJA",
	}
	got := wechatV2Sign(values, "192006250b4c09247ec02edce69f6a2d", "MD5")
	if got != strings.ToUpper(got) || len(got) != 32 {
		t.Fatalf("invalid WeChat v2 MD5 signature %q", got)
	}
	values["sign"] = got
	if err := verifyWechatV2(values, "192006250b4c09247ec02edce69f6a2d"); err != nil {
		t.Fatal(err)
	}
}

func TestApplePaymentResultSeparatesMerchantAndProviderTradeNumbers(t *testing.T) {
	result, err := applePaymentResult("1000000000001", map[string]any{
		"transactionId":   "1000000000001",
		"appAccountToken": "123e4567-e89b-12d3-a456-426614174000",
		"currency":        "CNY",
		"price":           "1000",
	}, nil, map[string]any{"price_divisor": "10"})
	if err != nil {
		t.Fatal(err)
	}
	if result.TradeNo != "123e4567-e89b-12d3-a456-426614174000" || result.ProviderTradeNo != "1000000000001" || result.QueryID != "1000000000001" {
		t.Fatalf("unexpected Apple order identifiers: %+v", result)
	}
}

func TestApplePaymentResultTreatsZeroRevocationDateAsNotRevoked(t *testing.T) {
	result, err := applePaymentResult("1000000000001", map[string]any{
		"transactionId":   "1000000000001",
		"appAccountToken": "123e4567-e89b-12d3-a456-426614174000",
		"currency":        "CNY",
		"price":           "1000",
		"revocationDate":  float64(0),
	}, nil, map[string]any{"price_divisor": "10"})
	if err != nil || result.Status != "success" || result.Amount != 100 {
		t.Fatalf("zero revocationDate result = %+v, err = %v", result, err)
	}
	result, err = applePaymentResult("1000000000001", map[string]any{
		"transactionId":   "1000000000001",
		"appAccountToken": "123e4567-e89b-12d3-a456-426614174000",
		"currency":        "CNY",
		"price":           "1000",
		"revocationDate":  float64(1700000000000),
	}, nil, map[string]any{"price_divisor": "10"})
	if err != nil || result.Status != "failed" {
		t.Fatalf("positive revocationDate result = %+v, err = %v", result, err)
	}
}

func TestWechatV3Decrypt(t *testing.T) {
	key := "01234567890123456789012345678901"
	nonce := "0123456789ab"
	aad := "transaction"
	plain := []byte(`{"out_trade_no":"T1","trade_state":"SUCCESS"}`)
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		t.Fatal(err)
	}
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		t.Fatal(err)
	}
	ciphertext := base64.StdEncoding.EncodeToString(gcm.Seal(nil, []byte(nonce), plain, []byte(aad)))
	got, err := decryptWechatV3(ciphertext, nonce, aad, key)
	if err != nil {
		t.Fatal(err)
	}
	if string(got) != string(plain) {
		t.Fatalf("plaintext = %q", got)
	}
}

func TestAlipaySignContentSortedAndExcludesSign(t *testing.T) {
	values := url.Values{"method": {"alipay.trade.query"}, "app_id": {"123"}, "sign": {"ignored"}, "empty": {""}}
	if got := alipaySignContent(values); got != "app_id=123&method=alipay.trade.query" {
		t.Fatalf("sign content = %q", got)
	}
}

func TestAlipayBreakdownWithPointPayment(t *testing.T) {
	result := &bizpayment.PaymentResult{Status: "success", Amount: 1000}
	err := populateAlipayBreakdown(result, map[string]any{
		"total_amount": "10.00", "buyer_pay_amount": "8.00", "point_amount": "2.00", "receipt_amount": "8.00",
	})
	if err != nil {
		t.Fatal(err)
	}
	if !result.AmountBreakdownKnown || result.PayerPaidAmount != 800 || result.CashPaidAmount != 600 || result.PointPaidAmount != 200 || result.DiscountAmount != 200 || result.SettlementAmount != 800 {
		t.Fatalf("unexpected Alipay breakdown: %+v", result)
	}
}

func TestWechatV2BreakdownWithCoupon(t *testing.T) {
	result := &bizpayment.PaymentResult{Status: "success", Amount: 1000}
	err := populateWechatV2Breakdown(result, map[string]string{"cash_fee": "900", "coupon_fee": "100", "settlement_total_fee": "950"})
	if err != nil {
		t.Fatal(err)
	}
	if !result.AmountBreakdownKnown || result.PayerPaidAmount != 900 || result.DiscountAmount != 100 || result.SettlementAmount != 950 {
		t.Fatalf("unexpected WeChat v2 breakdown: %+v", result)
	}
}

func TestWechatV3BreakdownWithPromotion(t *testing.T) {
	result := &bizpayment.PaymentResult{Status: "success", Amount: 1000}
	err := populateWechatV3Breakdown(result, map[string]any{
		"amount":           map[string]any{"payer_total": float64(800), "settlement_amount": float64(780)},
		"promotion_detail": []any{map[string]any{"amount": float64(200)}},
	})
	if err != nil {
		t.Fatal(err)
	}
	if !result.AmountBreakdownKnown || result.PayerPaidAmount != 800 || result.CashPaidAmount != 800 || result.DiscountAmount != 200 || result.SettlementAmount != 780 {
		t.Fatalf("unexpected WeChat v3 breakdown: %+v", result)
	}
}

func TestVendorBreakdownUsesConfiguredUnits(t *testing.T) {
	result := &bizpayment.PaymentResult{Status: "success", Amount: 1000, Currency: "CNY"}
	object := map[string]any{"data": map[string]any{
		"payer": "8.00", "cash": "6.00", "points": "2.00", "discount": "2.00", "settlement": "7.80",
	}}
	config := map[string]any{
		"query_amount_scale": "100", "query_payer_paid_amount_field": "data.payer", "query_cash_paid_amount_field": "data.cash",
		"query_point_paid_amount_field": "data.points", "query_discount_amount_field": "data.discount",
		"query_settlement_amount_field": "data.settlement", "query_payer_currency_field": "data.currency",
	}
	err := populateVendorBreakdown(result, object, config)
	if err != nil {
		t.Fatal(err)
	}
	if !result.AmountBreakdownKnown || result.PayerPaidAmount != 800 || result.CashPaidAmount != 600 || result.PointPaidAmount != 200 || result.DiscountAmount != 200 || result.SettlementAmount != 780 {
		t.Fatalf("unexpected vendor breakdown: %+v", result)
	}
}
