package pay

import (
	"context"
	"crypto"
	crand "crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	mrand "math/rand"
	"os"
	"sync"
	"time"

	"bindbox-game/configs"
	"bindbox-game/internal/service/sysconfig"
)

// 私钥缓存 - 避免每次请求都重新加载
var (
	cachedRSAKey   *rsa.PrivateKey
	rsaKeyOnce     sync.Once
	rsaKeyLoadErr  error
	rsaKeyLoadFrom string // "dynamic" 或 "file"
)

// getCachedRSAKeyForSign 获取缓存的RSA私钥用于签名
// 优先使用动态配置中的 Base64 私钥内容，fallback 到静态文件路径
func getCachedRSAKeyForSign(ctx context.Context) (*rsa.PrivateKey, error) {
	rsaKeyOnce.Do(func() {
		staticCfg := configs.Get()

		// 尝试从动态配置获取
		var dynamicCfg *sysconfig.WechatPayConfig
		if dc := sysconfig.GetDynamicConfig(); dc != nil {
			cfg := dc.GetWechatPay(ctx)
			dynamicCfg = &cfg
		}

		// 优先动态配置的 Base64 内容
		if dynamicCfg != nil && dynamicCfg.PrivateKey != "" {
			cachedRSAKey, rsaKeyLoadErr = LoadPrivateKeyFromBase64(dynamicCfg.PrivateKey)
			if rsaKeyLoadErr == nil {
				rsaKeyLoadFrom = "dynamic"
				return
			}
		}

		// fallback 到静态文件路径
		if staticCfg.WechatPay.PrivateKeyPath != "" {
			cachedRSAKey, rsaKeyLoadErr = loadRSAPrivateKeyFromFile(staticCfg.WechatPay.PrivateKeyPath)
			if rsaKeyLoadErr == nil {
				rsaKeyLoadFrom = "file"
			}
		} else if rsaKeyLoadErr == nil {
			rsaKeyLoadErr = errors.New("wechat pay private key not configured")
		}
	})
	return cachedRSAKey, rsaKeyLoadErr
}

// loadRSAPrivateKeyFromFile 从磁盘加载私钥（内部函数）
func loadRSAPrivateKeyFromFile(keyPath string) (*rsa.PrivateKey, error) {
	b, err := os.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}
	block, _ := pem.Decode(b)
	if block == nil {
		return nil, errors.New("invalid merchant private key pem")
	}
	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		// 兼容PKCS1
		k1, e1 := x509.ParsePKCS1PrivateKey(block.Bytes)
		if e1 != nil {
			return nil, err
		}
		key = k1
	}
	rsaKey, ok := key.(*rsa.PrivateKey)
	if !ok {
		return nil, errors.New("merchant private key is not RSA")
	}
	return rsaKey, nil
}

// BuildJSAPIParams 为小程序支付构造客户端参数
// 入参：ctx(上下文)、appid(微信小程序AppID)、prepayID(统一下单返回的prepay_id)
// 返回：timeStamp、nonceStr、package(格式为"prepay_id=***")、signType(固定"RSA")、paySign(RSA-SHA256签名)
// 错误：当私钥读取或签名失败时返回错误
func BuildJSAPIParams(ctx context.Context, appid string, prepayID string) (timeStamp string, nonceStr string, pkg string, signType string, paySign string, err error) {
	// 使用缓存的私钥，优先动态配置
	rsaKey, err := getCachedRSAKeyForSign(ctx)
	if err != nil {
		return "", "", "", "", "", err
	}

	ts := fmt.Sprintf("%d", time.Now().Unix())
	// 随机串32位
	const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	rb := make([]byte, 32)
	for i := range rb {
		rb[i] = letters[mrand.Intn(len(letters))]
	}
	nonce := string(rb)
	pkg = "prepay_id=" + prepayID
	signType = "RSA"

	message := fmt.Sprintf("%s\n%s\n%s\n%s\n", appid, ts, nonce, pkg)
	h := sha256.Sum256([]byte(message))
	sig, err := rsa.SignPKCS1v15(crand.Reader, rsaKey, crypto.SHA256, h[:])
	if err != nil {
		return "", "", "", "", "", err
	}
	paySign = base64.StdEncoding.EncodeToString(sig)
	return ts, nonce, pkg, signType, paySign, nil
}

// ValidateConfig 校验微信支付必要配置
// 入参：ctx(上下文)
// 返回：true表示配置齐全；false表示缺失，并附带错误信息
func ValidateConfig(ctx context.Context) (bool, error) {
	// 检查动态配置
	var dynamicCfg *sysconfig.WechatPayConfig
	var wxCfg *sysconfig.WechatConfig

	if dc := sysconfig.GetDynamicConfig(); dc != nil {
		pCfg := dc.GetWechatPay(ctx)
		dynamicCfg = &pCfg
		wCfg := dc.GetWechat(ctx)
		wxCfg = &wCfg
	}

	if wxCfg == nil || wxCfg.AppID == "" {
		return false, errors.New("wechat app_id missing")
	}

	if dynamicCfg == nil {
		return false, errors.New("wechat pay config incomplete")
	}

	mchID := dynamicCfg.MchID
	serialNo := dynamicCfg.SerialNo
	apiV3Key := dynamicCfg.ApiV3Key
	hasPrivateKey := dynamicCfg.PrivateKey != ""

	if mchID == "" || serialNo == "" || !hasPrivateKey || apiV3Key == "" {
		return false, errors.New("wechat pay config incomplete")
	}
	return true, nil
}
