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

import cn.hutool.core.util.StrUtil;
import com.jeesharp.business.modules.pay.config.weixin.PayWechatCredentialSupport;
import com.jeesharp.business.modules.pay.paywechatconfig.convert.PayWechatConfigConvert;
import com.jeesharp.business.modules.pay.paywechatconfig.dto.PayWechatConfigSaveDTO;
import com.jeesharp.business.modules.pay.paywechatconfig.entity.PayWechatConfig;
import com.jeesharp.business.modules.pay.paychannelconfig.entity.PayChannelConfig;
import com.jeesharp.business.modules.pay.paychannelconfig.enums.PayChannelCodeEnum;
import com.jeesharp.business.modules.pay.paychannelconfig.service.PayChannelConfigService;
import com.jeesharp.business.modules.pay.paychannelconfig.support.PayChannelConfigMergeSupport;
import com.jeesharp.business.modules.pay.paychannelconfig.support.PayChannelTenantSupport;
import com.jeesharp.business.modules.pay.paychannelconfig.support.PayChannelWechatSyncSupport;
import com.jeesharp.business.modules.pay.paywechatconfig.enums.PayWechatConfigStatusEnum;
import com.jeesharp.business.modules.pay.paywechatconfig.service.PayWechatConfigRuntimeService;
import com.jeesharp.business.modules.pay.paywechatconfig.service.PayWechatConfigService;
import com.jeesharp.business.modules.pay.paywechatconfig.vo.PayWechatConfigInfoVO;
import com.jeesharp.business.modules.pay.paywechatconfig.vo.PayWechatConfigListVO;
import com.jeesharp.business.modules.pay.paywechatconfig.vo.PayWechatConfigQueryVO;
import com.jeesharp.framework.exception.BizErrorException;
import com.jeesharp.framework.pojo.Page;
import com.jeesharp.framework.pojo.query.PageRespVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

/**
 * 微信支付配置应用服务：管理端 CRUD 与运行时公开配置。
 *
 * @author jeesharp
 * @since 2026-05-25
 */
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class PayWechatConfigApplicationService {

    private final PayWechatConfigService payWechatConfigService;
    private final PayWechatConfigRuntimeService payWechatConfigRuntimeService;
    private final PayChannelWechatSyncSupport payChannelWechatSyncSupport;
    private final PayChannelConfigService payChannelConfigService;

    public PayWechatConfigInfoVO get(String id) {
        return maskSecrets(PayWechatConfigConvert.INSTANCE.toInfoVO(payWechatConfigService.get(id)));
    }

    public PayWechatConfigInfoVO getActive(String tenantId) {
        PayWechatConfig active = payWechatConfigService.findActive(tenantId);
        if (active == null) {
            return null;
        }
        return maskSecrets(PayWechatConfigConvert.INSTANCE.toInfoVO(active));
    }

    /**
     * 管理端「当前配置」解析：优先主表主键；其次按 {@code pay_channel_config.config_code} + 租户（空则按平台 {@code 1}）查主表再加载子表；
     * 否则回落 {@link #getActive(String)}。
     */
    public PayWechatConfigInfoVO resolveActive(String tenantId, String channelConfigId, String payChannelConfigCode) {
        if (StrUtil.isNotBlank(channelConfigId)) {
            return getByChannelConfigId(channelConfigId.trim());
        }
        if (StrUtil.isNotBlank(payChannelConfigCode)) {
            String tid = PayChannelTenantSupport.normalize(tenantId);
            if (tid == null) {
                tid = PayChannelTenantSupport.PLATFORM_TENANT_ID;
            }
            PayChannelConfig ch = payChannelConfigService.findByChannelAndConfigCode(
                    PayChannelCodeEnum.WECHAT.getCode(), payChannelConfigCode.trim(), tid);
            if (ch != null) {
                return getByChannelConfigId(ch.getId());
            }
        }
        return getActive(tenantId);
    }

    /**
     * 按 {@code pay_channel_config.id} 加载微信子配置：子表有则合并主表回调字段后返回；无则返回带主表信息的空壳供首次保存。
     */
    public PayWechatConfigInfoVO getByChannelConfigId(String channelConfigId) {
        PayChannelConfig ch = requireWechatChannel(channelConfigId);
        PayWechatConfig wechat = payWechatConfigService.findByChannelConfigId(ch.getId());
        if (wechat == null) {
            PayWechatConfig shell = new PayWechatConfig();
            shell.setChannelConfigId(ch.getId());
            shell.setTenantId(PayChannelTenantSupport.normalize(ch.getTenantId()));
            shell.setTenantCode(ch.getTenantCode());
            shell.setConfigCode(StrUtil.blankToDefault(ch.getConfigCode(), "DEFAULT"));
            shell.setConfigName(ch.getConfigName());
            shell.setStatus(PayWechatConfigStatusEnum.ENABLED.getValue());
            shell.setWxEnabled(0);
            shell.setMockFallback(0);
            shell.setSkipSignatureVerify(0);
            shell.setPayCenterNotifyPath("/api/pay/payNotify/wxNotify");
            PayWechatConfig merged = PayChannelConfigMergeSupport.mergeWechatNotify(shell, ch);
            return maskSecrets(PayWechatConfigConvert.INSTANCE.toInfoVO(merged));
        }
        PayWechatConfig merged = PayChannelConfigMergeSupport.mergeWechatNotify(wechat, ch);
        return maskSecrets(PayWechatConfigConvert.INSTANCE.toInfoVO(merged));
    }

    public PageRespVO<PayWechatConfigListVO> findPage(Page<PayWechatConfig> page, PayWechatConfigQueryVO query) {
        Page<PayWechatConfig> result = payWechatConfigService.findPage(page, query);
        return PayWechatConfigConvert.INSTANCE.toPageRespVO(result);
    }

    @Transactional(readOnly = false)
    public void save(PayWechatConfigSaveDTO dto) {
        PayWechatConfig entity = PayWechatConfigConvert.INSTANCE.toEntity(dto);
        entity.setTenantId(PayChannelTenantSupport.normalize(dto.getTenantId()));
        if (StrUtil.isBlank(entity.getConfigCode())) {
            entity.setConfigCode("DEFAULT");
        }
        if (StrUtil.isBlank(entity.getPayCenterNotifyPath())) {
            entity.setPayCenterNotifyPath("/api/pay/payNotify/wxNotify");
        }
        PayWechatConfig existing = resolveExistingRow(entity);
        if (existing != null) {
            entity.setId(existing.getId());
            if (StrUtil.isBlank(entity.getChannelConfigId()) && StrUtil.isNotBlank(existing.getChannelConfigId())) {
                entity.setChannelConfigId(existing.getChannelConfigId());
            }
            mergeSensitiveFields(entity, existing, dto);
        } else {
            if (entity.getStatus() == null) {
                entity.setStatus(PayWechatConfigStatusEnum.ENABLED.getValue());
            }
            if (entity.getWxEnabled() == null) {
                entity.setWxEnabled(0);
            }
            if (entity.getSkipSignatureVerify() == null) {
                entity.setSkipSignatureVerify(0);
            }
        }
        entity.setMockFallback(0);
        if (PayWechatCredentialSupport.isWxEnabled(entity)) {
            try {
                PayWechatCredentialSupport.requireValidApiV3KeyForRealWx(entity.getApiV3Key());
            } catch (IllegalStateException e) {
                throw new BizErrorException(e.getMessage());
            }
        }
        if (PayWechatConfigStatusEnum.ENABLED.getValue().equals(entity.getStatus())) {
            payWechatConfigService.disableOtherActiveExcept(entity.getTenantId(), entity.getId());
        }
        payChannelWechatSyncSupport.syncFromWechat(entity);
        payWechatConfigService.save(entity);
        payWechatConfigRuntimeService.evictWxPayClientCache();
    }

    @Transactional(readOnly = false)
    public void delete(String ids) {
        List<String> idList = Arrays.asList(ids.split(","));
        for (String id : idList) {
            PayWechatConfig existing = payWechatConfigService.get(id);
            PayChannelTenantSupport.assertDeletableTenantCode(existing != null ? existing.getTenantCode() : null);
        }
        payWechatConfigService.batchDelete(idList);
        payWechatConfigRuntimeService.evictWxPayClientCache();
    }

    /**
     * 解析待更新行：优先 {@code channel_config_id}（与渠道列表入口一致），再按子表主键 id，最后按 configCode+租户（兼容旧数据）。
     */
    private PayWechatConfig resolveExistingRow(PayWechatConfig entity) {
        if (StrUtil.isNotBlank(entity.getChannelConfigId())) {
            PayChannelConfig ch = payChannelConfigService.get(entity.getChannelConfigId().trim());
            if (ch == null || !PayChannelCodeEnum.WECHAT.getCode().equalsIgnoreCase(ch.getChannelCode())) {
                throw new BizErrorException("无效或非微信的渠道配置 ID");
            }
            if (StrUtil.isBlank(entity.getTenantId())) {
                entity.setTenantId(PayChannelTenantSupport.normalize(ch.getTenantId()));
            }
            if (StrUtil.isBlank(entity.getConfigCode())) {
                entity.setConfigCode(StrUtil.blankToDefault(ch.getConfigCode(), "DEFAULT"));
            }
            PayWechatConfig byCh = payWechatConfigService.findByChannelConfigId(entity.getChannelConfigId().trim());
            if (byCh != null) {
                return byCh;
            }
            return null;
        }
        if (StrUtil.isNotBlank(entity.getId())) {
            PayWechatConfig byId = payWechatConfigService.get(entity.getId());
            if (byId != null) {
                return byId;
            }
        }
        return payWechatConfigService.findByConfigCode(entity.getConfigCode(), entity.getTenantId());
    }

    private PayChannelConfig requireWechatChannel(String channelConfigId) {
        if (StrUtil.isBlank(channelConfigId)) {
            throw new BizErrorException("渠道配置 ID 不能为空");
        }
        PayChannelConfig ch = payChannelConfigService.get(channelConfigId.trim());
        if (ch == null) {
            throw new BizErrorException("渠道配置不存在");
        }
        if (!PayChannelCodeEnum.WECHAT.getCode().equalsIgnoreCase(StrUtil.trimToEmpty(ch.getChannelCode()))) {
            throw new BizErrorException("该渠道配置不是微信渠道");
        }
        return ch;
    }

    private static void mergeSensitiveFields(PayWechatConfig target, PayWechatConfig existing, PayWechatConfigSaveDTO dto) {
        if (existing == null) {
            return;
        }
        if (isPlaceholderOrBlank(dto.getMerchantPrivateKeyPem())) {
            target.setMerchantPrivateKeyPem(existing.getMerchantPrivateKeyPem());
        }
        if (isPlaceholderOrBlank(dto.getPublicKeyPem())) {
            target.setPublicKeyPem(existing.getPublicKeyPem());
        }
        if (isPlaceholderOrBlank(dto.getApiV3Key())) {
            target.setApiV3Key(existing.getApiV3Key());
        }
        if (isPlaceholderOrBlank(dto.getMchKey())) {
            target.setMchKey(existing.getMchKey());
        }
    }

    private static boolean isPlaceholderOrBlank(String value) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        return PayWechatCredentialSupport.SECRET_FIELD_MASK.equals(value.trim());
    }

    private static PayWechatConfigInfoVO maskSecrets(PayWechatConfigInfoVO vo) {
        if (vo == null) {
            return null;
        }
        if (StrUtil.isNotBlank(vo.getMerchantPrivateKeyPem())) {
            vo.setMerchantPrivateKeyPem(PayWechatCredentialSupport.SECRET_FIELD_MASK);
        }
        if (StrUtil.isNotBlank(vo.getPublicKeyPem()) && !vo.getPublicKeyPem().startsWith("/")) {
            vo.setPublicKeyPem(PayWechatCredentialSupport.SECRET_FIELD_MASK);
        }
        if (StrUtil.isNotBlank(vo.getApiV3Key())) {
            vo.setApiV3Key(PayWechatCredentialSupport.SECRET_FIELD_MASK);
        }
        if (StrUtil.isNotBlank(vo.getMchKey())) {
            vo.setMchKey(PayWechatCredentialSupport.SECRET_FIELD_MASK);
        }
        return vo;
    }
}
