package com.jeesharp.business.modules.pay.payfundbalance.application;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.jeesharp.business.modules.pay.paychannelconfig.support.PayChannelTenantSupport;
import com.jeesharp.business.modules.pay.payfundbalance.convert.PayFundBalanceConvert;
import com.jeesharp.business.modules.pay.payfundbalance.enums.PayFundAccountTypeEnum;
import com.jeesharp.business.modules.pay.payfundbalance.support.PayWechatFundClient;
import com.jeesharp.business.modules.pay.payfundbalance.vo.PayFundBalanceItemVO;
import com.jeesharp.business.modules.pay.payfundbalance.vo.PayFundBalanceOverviewVO;
import com.jeesharp.business.modules.pay.paysubmerchantapplyment.application.support.PaySubMerchantApplymentOperateSupport;
import com.jeesharp.business.modules.pay.paysubmerchantapplyment.entity.PaySubMerchantApplyment;
import com.jeesharp.business.modules.pay.paysubmerchantapplyment.enums.PaySubMerchantApplyStatusEnum;
import com.jeesharp.business.modules.pay.paysubmerchantapplyment.service.PaySubMerchantApplymentService;
import com.jeesharp.business.modules.pay.paywechatconfig.entity.PayWechatConfig;
import com.jeesharp.framework.utils.WebFrameworkUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * 账户资金余额应用服务：代理微信 V3 查询平台/特约商户余额，不落本地库。
 *
 * @author jeesharp
 * @since 2026-06-12
 */
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class PayFundBalanceApplicationService {

    private static final String SCOPE_PLATFORM = "PLATFORM";
    private static final String SCOPE_MERCHANT = "MERCHANT";
    private static final String EMPTY_NO_APPLYMENT = "NO_APPLYMENT";
    private static final String EMPTY_NO_SUB_MCH_ID = "NO_SUB_MCH_ID";
    private static final String EMPTY_NOT_FINISHED = "NOT_FINISHED";
    private static final String EMPTY_CANCELLED = "MERCHANT_CANCELLED";

    private final PayWechatFundClient payWechatFundClient;
    private final PaySubMerchantApplymentService paySubMerchantApplymentService;

    /**
     * 平台服务商本商户号余额（BASIC / OPERATION / FEES）。
     */
    public PayFundBalanceOverviewVO getPlatformBalance() {
        PayWechatConfig config = payWechatFundClient.requireConfig(PayChannelTenantSupport.PLATFORM_TENANT_ID);
        PayFundBalanceOverviewVO overview = new PayFundBalanceOverviewVO();
        overview.setScopeType(SCOPE_PLATFORM);
        overview.setMchId(config.getMchId());
        overview.setAccounts(queryPlatformAccounts());
        return overview;
    }

    /**
     * 当前登录租户对应特约商户余额（每租户唯一进件，零筛选）。
     */
    public PayFundBalanceOverviewVO getMerchantBalance() {
        String loginTenantId = WebFrameworkUtils.getLoginUserTenantId();
        PaySubMerchantApplyment applyment = paySubMerchantApplymentService.findByApplymentTenantId(loginTenantId);

        PayFundBalanceOverviewVO overview = new PayFundBalanceOverviewVO();
        overview.setScopeType(SCOPE_MERCHANT);

        if (applyment == null) {
            overview.setEmptyCode(EMPTY_NO_APPLYMENT);
            overview.setEmptyMessage("当前租户尚未提交特约商户进件，无法查询余额");
            overview.setAccounts(List.of());
            return overview;
        }

        overview.setMerchantShortName(applyment.getMerchantShortname());
        if (PaySubMerchantApplyStatusEnum.SUB_MCH_CANCELLED.getValue().equals(applyment.getApplyStatus())) {
            overview.setEmptyCode(EMPTY_CANCELLED);
            overview.setEmptyMessage("该特约商户已注销，无法查询余额");
            overview.setAccounts(List.of());
            return overview;
        }
        if (StrUtil.isBlank(applyment.getSubMchId())) {
            overview.setEmptyCode(EMPTY_NO_SUB_MCH_ID);
            overview.setEmptyMessage("进件尚未分配特约商户号（sub_mchid），请等待微信审核通过后再查询");
            overview.setAccounts(List.of());
            return overview;
        }
        if (!PaySubMerchantApplymentOperateSupport.isEffectiveSubMerchant(applyment)) {
            overview.setEmptyCode(EMPTY_NOT_FINISHED);
            overview.setEmptyMessage("进件尚未完成（须 FINISH），暂不可查询余额");
            overview.setAccounts(List.of());
            return overview;
        }

        String configTenantKey = resolveWechatConfigTenantKey(applyment.getApplymentTenantId());
        PayWechatConfig config = payWechatFundClient.requireConfig(configTenantKey);
        overview.setMchId(config.getMchId());
        overview.setSubMchId(applyment.getSubMchId());
        overview.setAccounts(querySubMerchantAccounts(applyment.getSubMchId(), configTenantKey));
        return overview;
    }

    private List<PayFundBalanceItemVO> queryPlatformAccounts() {
        String configTenantId = PayChannelTenantSupport.PLATFORM_TENANT_ID;
        List<PayFundBalanceItemVO> items = new ArrayList<>();
        for (PayFundAccountTypeEnum type : PayFundAccountTypeEnum.values()) {
            items.add(queryPlatformAccount(type.getValue(), configTenantId));
        }
        return items;
    }

    private PayFundBalanceItemVO queryPlatformAccount(String accountType, String configTenantId) {
        try {
            JSONObject wx = payWechatFundClient.queryPlatformBalance(accountType, configTenantId);
            return PayFundBalanceConvert.INSTANCE.toItemVO(accountType, wx);
        } catch (Exception ex) {
            return PayFundBalanceConvert.INSTANCE.toFailedItem(accountType, ex.getMessage());
        }
    }

    private List<PayFundBalanceItemVO> querySubMerchantAccounts(String subMchId, String configTenantKey) {
        List<PayFundBalanceItemVO> items = new ArrayList<>();
        for (PayFundAccountTypeEnum type : PayFundAccountTypeEnum.values()) {
            items.add(querySubMerchantAccount(subMchId, type.getValue(), configTenantKey));
        }
        return items;
    }

    private PayFundBalanceItemVO querySubMerchantAccount(String subMchId, String accountType, String configTenantKey) {
        try {
            JSONObject wx = payWechatFundClient.querySubMerchantBalance(subMchId, accountType, configTenantKey);
            return PayFundBalanceConvert.INSTANCE.toItemVO(accountType, wx);
        } catch (Exception ex) {
            return PayFundBalanceConvert.INSTANCE.toFailedItem(accountType, ex.getMessage());
        }
    }

    private static String resolveWechatConfigTenantKey(String applymentTenantId) {
        if (PayChannelTenantSupport.isPlatformLevel(applymentTenantId)) {
            return PayChannelTenantSupport.PLATFORM_TENANT_ID;
        }
        return PayChannelTenantSupport.normalize(applymentTenantId);
    }
}
