package com.jeesharp.business.modules.pay.config.weixin;

import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.jeesharp.business.modules.pay.paywechatconfig.entity.PayWechatConfig;
import com.jeesharp.business.modules.pay.paywechatconfig.service.PayWechatConfigService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 按后台 {@code pay_wechat_config} 装配并缓存 {@link WxPayService}。
 *
 * @author jeesharp
 * @since 2026-05-25
 */
@Component
@RequiredArgsConstructor
public class PayWechatWxPayClientHolder {

    private final PayWechatConfigService payWechatConfigService;

    private final ConcurrentHashMap<String, CachedClient> cacheByVersion = new ConcurrentHashMap<>();

    public PayWechatConfig requireActiveConfig() {
        return requireActiveConfig(null);
    }

    public PayWechatConfig requireActiveConfig(String tenantId) {
        PayWechatConfig config = payWechatConfigService.findActive(tenantId);
        if (config == null) {
            throw new IllegalStateException("未配置微信支付：请在管理后台【支付 · 微信配置】保存并启用一条记录");
        }
        return config;
    }

    public PayWechatConfig findActiveConfig() {
        return findActiveConfig(null);
    }

    public PayWechatConfig findActiveConfig(String tenantId) {
        return payWechatConfigService.findActive(tenantId);
    }

    public WxPayService requireWxPayService() {
        return requireWxPayService(null);
    }

    public WxPayService requireWxPayService(String tenantId) {
        PayWechatConfig config = requireActiveConfig(tenantId);
        if (!PayWechatCredentialSupport.isWxEnabled(config)) {
            throw new IllegalStateException("未启用真实微信 V3 下单：请在后台开启「调用真实微信」");
        }
        return getOrBuild(config, tenantId);
    }

    public WxPayService getWxPayServiceIfEnabled(String tenantId) {
        PayWechatConfig config = findActiveConfig(tenantId);
        if (config == null || !PayWechatCredentialSupport.isWxEnabled(config)) {
            return null;
        }
        return getOrBuild(config, tenantId);
    }

    public void evictCache() {
        cacheByVersion.clear();
    }

    private WxPayService getOrBuild(PayWechatConfig config, String tenantId) {
        String tid = tenantId == null ? "" : tenantId;
        String version = tid + ":" + config.getId() + ":" + (config.getUpdateDate() == null ? "" : config.getUpdateDate());
        return cacheByVersion.computeIfAbsent(version, k -> new CachedClient(version, buildWxPayService(config)))
                .wxPayService();
    }

    private WxPayService buildWxPayService(PayWechatConfig c) {
        String appId = trimToNull(c.getAppId());
        String mchId = trimToNull(c.getMchId());
        if (!StringUtils.hasText(appId) || !StringUtils.hasText(mchId)) {
            throw new IllegalStateException("微信支付配置缺少 appId 或 mchId");
        }
        WxPayConfig wx = new WxPayConfig();
        wx.setAppId(appId);
        wx.setMchId(mchId);
        wx.setMchKey(trimToNull(c.getMchKey()));
        String p12Path = trimToNull(c.getCertPath());
        if (p12Path == null) {
            throw new IllegalStateException("微信支付配置缺少 p12 证书路径 certPath");
        }
        wx.setKeyPath(p12Path);
        try {
            wx.setKeyContent(Files.readAllBytes(Path.of(p12Path)));
        } catch (IOException e) {
            throw new IllegalStateException("无法读取 p12 证书: " + p12Path, e);
        }
        wx.setCertSerialNo(trimToNull(PayWechatCredentialSupport.resolveMerchantSerialNo(c)));
        String apiV3Key = trimToNull(c.getApiV3Key());
        PayWechatCredentialSupport.requireValidApiV3KeyForRealWx(apiV3Key);
        wx.setApiV3Key(apiV3Key);
        String pem = PayWechatCredentialSupport.resolveMerchantPrivateKeyPem(c);
        if (pem != null && !pem.isBlank()) {
            wx.setPrivateKeyContent(pem.getBytes(StandardCharsets.UTF_8));
        }
        String wxpayPubPem = PayWechatCredentialSupport.resolveWechatPayPublicKeyPem(c);
        String wxpayPubId = trimToNull(c.getPublicKeyId());
        if (StringUtils.hasText(wxpayPubPem)) {
            if (wxpayPubId == null) {
                throw new IllegalStateException("已配置微信支付公钥 PEM，但未配置 publicKeyId");
            }
            wx.setPublicKeyId(wxpayPubId);
            wx.setPublicKeyContent(wxpayPubPem.getBytes(StandardCharsets.UTF_8));
        } else if (wxpayPubId != null) {
            throw new IllegalStateException("已配置 publicKeyId，但未配置公钥 PEM 或路径");
        }
        WxPayServiceImpl service = new WxPayServiceImpl();
        service.setConfig(wx);
        return service;
    }

    private static String trimToNull(String s) {
        if (s == null) {
            return null;
        }
        String t = s.trim();
        return t.isEmpty() ? null : t;
    }

    private record CachedClient(String version, WxPayService wxPayService) {
    }
}

