package com.jeesharp.business.modules.pay.profitsharing.support;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jeesharp.business.modules.pay.config.weixin.PayWechatCredentialSupport;
import com.jeesharp.business.modules.pay.config.weixin.PayWechatWxPayClientHolder;
import com.jeesharp.business.modules.pay.core.IJPayHttpResponse;
import com.jeesharp.business.modules.pay.core.enums.RequestMethod;
import com.jeesharp.business.modules.pay.paychannelconfig.support.PayChannelTenantSupport;
import com.jeesharp.business.modules.pay.paywechatconfig.entity.PayWechatConfig;
import com.jeesharp.business.modules.pay.profitsharing.dto.PayProfitSharingReceiverAddRequestDTO;
import com.jeesharp.business.modules.pay.profitsharing.dto.PayProfitSharingReceiverDeleteRequestDTO;
import com.jeesharp.business.modules.pay.profitsharing.dto.PayProfitSharingReceiverResultDTO;
import com.jeesharp.business.modules.pay.wxpay.WxPayApi;
import com.jeesharp.business.modules.pay.wxpay.enums.WxApiType;
import com.jeesharp.business.modules.pay.wxpay.enums.WxDomain;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;

/**
 * 微信电商收付通分账接收方 V3 客户端（添加/删除/查询及 ensure 幂等注册）。
 *
 * @author jeesharp
 * @since 2026-06-12
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PayWechatProfitSharingReceiverClient {

    private static final String RECEIVER_TYPE_MERCHANT = "MERCHANT_ID";
    private static final String RELATION_TYPE_SUPPLIER = "SUPPLIER";
    private static final String CUSTOM_RELATION_MERCHANT = "特约商户货款";

    private final PayWechatWxPayClientHolder payWechatWxPayClientHolder;

    /**
     * 确保二级商户自身已注册为分账接收方（分账货款至 sub_mchid 的前置条件）。
     */
    public PayProfitSharingReceiverResultDTO ensureSubMerchantSelfReceiver(String platformTenantId, String subMchId) {
        PayProfitSharingReceiverResultDTO result = new PayProfitSharingReceiverResultDTO();
        if (StrUtil.isBlank(subMchId)) {
            result.setSuccess(false);
            result.setErrorMsg("sub_mchid 不能为空");
            return result;
        }
        try {
            if (hasMerchantReceiver(platformTenantId, subMchId, subMchId)) {
                result.setSuccess(true);
                result.setAlreadyExists(true);
                return result;
            }
            PayProfitSharingReceiverAddRequestDTO addRequest = new PayProfitSharingReceiverAddRequestDTO();
            addRequest.setPlatformTenantId(platformTenantId);
            addRequest.setSubMchId(subMchId);
            addRequest.setReceiverType(RECEIVER_TYPE_MERCHANT);
            addRequest.setReceiverAccount(subMchId);
            addRequest.setRelationType(RELATION_TYPE_SUPPLIER);
            addRequest.setCustomRelation(CUSTOM_RELATION_MERCHANT);
            return addReceiver(addRequest);
        } catch (Exception ex) {
            result.setSuccess(false);
            result.setErrorMsg(ex.getMessage());
            return result;
        }
    }

    public PayProfitSharingReceiverResultDTO addReceiver(PayProfitSharingReceiverAddRequestDTO request) {
        PayProfitSharingReceiverResultDTO result = new PayProfitSharingReceiverResultDTO();
        try {
            PayWechatConfig config = resolveConfig(request.getPlatformTenantId());
            JSONObject body = buildAddBody(config, request);
            IJPayHttpResponse response = v3Post(config, WxApiType.PROFIT_SHARING_RECEIVERS_ADD.getType(), body.toString());
            JSONObject wxResp = parseResponse(response, "添加分账接收方失败");
            result.setSuccess(true);
            result.setRawResponse(JSONUtil.createObj().set("request", body).set("response", wxResp).toString());
            return result;
        } catch (Exception ex) {
            if (isReceiverAlreadyExists(ex)) {
                result.setSuccess(true);
                result.setAlreadyExists(true);
                result.setErrorMsg(ex.getMessage());
                return result;
            }
            result.setSuccess(false);
            result.setErrorMsg(ex.getMessage());
            return result;
        }
    }

    public PayProfitSharingReceiverResultDTO deleteReceiver(PayProfitSharingReceiverDeleteRequestDTO request) {
        PayProfitSharingReceiverResultDTO result = new PayProfitSharingReceiverResultDTO();
        try {
            PayWechatConfig config = resolveConfig(request.getPlatformTenantId());
            JSONObject body = new JSONObject();
            body.set("sub_mchid", request.getSubMchId());
            body.set("appid", config.getAppId());
            body.set("type", request.getReceiverType());
            body.set("account", request.getReceiverAccount());
            IJPayHttpResponse response = v3Post(config, WxApiType.PROFIT_SHARING_RECEIVERS_DELETE.getType(), body.toString());
            JSONObject wxResp = parseResponse(response, "删除分账接收方失败");
            result.setSuccess(true);
            result.setRawResponse(JSONUtil.createObj().set("request", body).set("response", wxResp).toString());
            return result;
        } catch (Exception ex) {
            result.setSuccess(false);
            result.setErrorMsg(ex.getMessage());
            return result;
        }
    }

    public PayProfitSharingReceiverResultDTO queryReceivers(String platformTenantId, String subMchId) {
        PayProfitSharingReceiverResultDTO result = new PayProfitSharingReceiverResultDTO();
        try {
            PayWechatConfig config = resolveConfig(platformTenantId);
            String suffix = UriComponentsBuilder.fromPath(WxApiType.PROFIT_SHARING_RECEIVERS.getType())
                    .queryParam("sub_mchid", subMchId)
                    .build()
                    .toUriString();
            IJPayHttpResponse response = v3Get(config, suffix);
            JSONObject wxResp = parseResponse(response, "查询分账接收方失败");
            result.setSuccess(true);
            result.setRawResponse(wxResp.toString());
            return result;
        } catch (Exception ex) {
            result.setSuccess(false);
            result.setErrorMsg(ex.getMessage());
            return result;
        }
    }

    private boolean hasMerchantReceiver(String platformTenantId, String subMchId, String receiverAccount) {
        PayProfitSharingReceiverResultDTO queryResult = queryReceivers(platformTenantId, subMchId);
        if (!Boolean.TRUE.equals(queryResult.getSuccess()) || StrUtil.isBlank(queryResult.getRawResponse())) {
            log.debug("查询分账接收方失败 subMch={}: {}", subMchId, queryResult.getErrorMsg());
            return false;
        }
        JSONObject wxResp = JSONUtil.parseObj(queryResult.getRawResponse());
        JSONArray data = wxResp.getJSONArray("data");
        if (data == null || data.isEmpty()) {
            return false;
        }
        for (int i = 0; i < data.size(); i++) {
            JSONObject row = data.getJSONObject(i);
            if (row == null) {
                continue;
            }
            if (RECEIVER_TYPE_MERCHANT.equalsIgnoreCase(row.getStr("type"))
                    && receiverAccount.equals(row.getStr("account"))) {
                return true;
            }
        }
        return false;
    }

    private static JSONObject buildAddBody(PayWechatConfig config, PayProfitSharingReceiverAddRequestDTO request) {
        JSONObject body = new JSONObject();
        body.set("sub_mchid", request.getSubMchId());
        body.set("appid", config.getAppId());
        body.set("type", StrUtil.blankToDefault(request.getReceiverType(), RECEIVER_TYPE_MERCHANT));
        body.set("account", request.getReceiverAccount());
        if (StrUtil.isNotBlank(request.getReceiverName())) {
            body.set("name", request.getReceiverName());
        }
        body.set("relation_type", StrUtil.blankToDefault(request.getRelationType(), RELATION_TYPE_SUPPLIER));
        if (StrUtil.isNotBlank(request.getCustomRelation())) {
            body.set("custom_relation", request.getCustomRelation());
        }
        return body;
    }

    private static boolean isReceiverAlreadyExists(Exception ex) {
        if (ex == null || ex.getMessage() == null) {
            return false;
        }
        String msg = ex.getMessage().toUpperCase();
        return msg.contains("RECEIVER_ACCOUNT_EXIST")
                || msg.contains("ALREADY_EXIST")
                || msg.contains("已存在")
                || msg.contains("RECEIVER_EXIST");
    }

    private PayWechatConfig resolveConfig(String platformTenantId) {
        String tenantId = StrUtil.blankToDefault(platformTenantId, PayChannelTenantSupport.PLATFORM_TENANT_ID);
        PayWechatConfig config = payWechatWxPayClientHolder.requireActiveConfig(tenantId);
        if (!PayWechatCredentialSupport.isWxEnabled(config)) {
            throw new IllegalStateException("未启用真实微信 V3：请在后台开启「调用真实微信」");
        }
        return config;
    }

    private IJPayHttpResponse v3Post(PayWechatConfig config, String urlSuffix, String body) throws Exception {
        return WxPayApi.v3(RequestMethod.POST, WxDomain.CHINA.getType(), urlSuffix,
                config.getMchId(),
                PayWechatCredentialSupport.resolveMerchantSerialNo(config),
                config.getPublicKeyId(),
                config.getCertPrivateKeyPath().trim(),
                body);
    }

    private IJPayHttpResponse v3Get(PayWechatConfig config, String urlSuffix) throws Exception {
        return WxPayApi.v3(RequestMethod.GET, WxDomain.CHINA.getType(), urlSuffix,
                config.getMchId(),
                PayWechatCredentialSupport.resolveMerchantSerialNo(config),
                config.getPublicKeyId(),
                config.getCertPrivateKeyPath().trim(),
                "");
    }

    private static JSONObject parseResponse(IJPayHttpResponse response, String action) {
        if (response == null) {
            throw new IllegalStateException(action + "：无响应");
        }
        int status = response.getStatus();
        String body = response.getBody();
        if (status >= 200 && status < 300) {
            return StringUtils.hasText(body) ? JSONUtil.parseObj(body) : new JSONObject();
        }
        String msg = body;
        if (StringUtils.hasText(body) && JSONUtil.isTypeJSON(body)) {
            JSONObject err = JSONUtil.parseObj(body);
            msg = err.getStr("message", body);
            if (err.containsKey("code")) {
                msg = err.getStr("code") + ": " + msg;
            }
        }
        throw new IllegalStateException(action + "（HTTP " + status + "）：" + msg);
    }
}
