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

import cn.hutool.core.util.StrUtil;
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.PayChannelPufaSyncSupport;
import com.jeesharp.business.modules.pay.paychannelconfig.support.PayChannelTenantSupport;
import com.jeesharp.framework.exception.BizErrorException;
import com.jeesharp.business.modules.pay.paypufaconfig.convert.PayPufaConfigConvert;
import com.jeesharp.business.modules.pay.paypufaconfig.dto.PayPufaConfigSaveDTO;
import com.jeesharp.business.modules.pay.paypufaconfig.entity.PayPufaConfig;
import com.jeesharp.business.modules.pay.paypufaconfig.enums.PayPufaConfigStatusEnum;
import com.jeesharp.business.modules.pay.paypufaconfig.service.PayPufaConfigRuntimeService;
import com.jeesharp.business.modules.pay.paypufaconfig.service.PayPufaConfigService;
import com.jeesharp.business.modules.pay.paypufaconfig.vo.PayPufaConfigInfoVO;
import com.jeesharp.business.modules.pay.paypufaconfig.vo.PayPufaConfigListVO;
import com.jeesharp.business.modules.pay.paypufaconfig.vo.PayPufaConfigQueryVO;
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;

/**
 * 浦发配置应用服务。
 *
 * @author jeesharp
 * @since 2026-05-25
 */
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class PayPufaConfigApplicationService {

    private static final String SECRET_PLACEHOLDER = "******";

    private static final String DEFAULT_APP_PAY_TRADE = "https://openapi.spdb.com.cn/openapi/payment/appPayTrade";
    private static final String DEFAULT_APP_PAY_STATUS = "https://openapi.spdb.com.cn/openapi/payment/appPayStatus";
    private static final String DEFAULT_APP_PAY_RETURN = "https://openapi.spdb.com.cn/openapi/payment/appPayReturn";
    private static final String DEFAULT_APP_PAY_CANCEL = "https://openapi.spdb.com.cn/openapi/payment/appPayCancel";

    private final PayPufaConfigService payPufaConfigService;
    private final PayPufaConfigRuntimeService payPufaConfigRuntimeService;
    private final PayChannelPufaSyncSupport payChannelPufaSyncSupport;
    private final PayChannelConfigService payChannelConfigService;

    public PayPufaConfigInfoVO get(String id) {
        return maskSecrets(PayPufaConfigConvert.INSTANCE.toInfoVO(payPufaConfigService.get(id)));
    }

    public PayPufaConfigInfoVO getActive(String tenantId) {
        PayPufaConfig active = payPufaConfigService.findActive(tenantId);
        PayPufaConfigInfoVO vo = PayPufaConfigConvert.INSTANCE.toInfoVO(active);
        if (vo != null) {
            vo.setStatusName(PayPufaConfigStatusEnum.getDescByValue(vo.getStatus()));
        }
        return maskSecrets(vo);
    }

    /**
     * 管理端「当前配置」解析：优先主表主键；其次按 {@code pay_channel_config.config_code} + 租户（空则平台 {@code 1}）查主表再加载子表；否则 {@link #getActive(String)}。
     */
    public PayPufaConfigInfoVO 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.PFA.getCode(), payChannelConfigCode.trim(), tid);
            if (ch != null) {
                return getByChannelConfigId(ch.getId());
            }
        }
        return getActive(tenantId);
    }

    /**
     * 按 {@code pay_channel_config.id} 加载浦发子配置；无子表行时返回可首次保存的空壳。
     */
    public PayPufaConfigInfoVO getByChannelConfigId(String channelConfigId) {
        PayChannelConfig ch = requirePufaChannel(channelConfigId);
        PayPufaConfig row = payPufaConfigService.findByChannelConfigId(ch.getId());
        if (row == null) {
            PayPufaConfig shell = new PayPufaConfig();
            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(PayPufaConfigStatusEnum.ENABLED.getValue());
            shell.setPfaEnabled(0);
            shell.setPayCenterNotifyPath("/api/pay/payNotify/pfNotify");
            shell.setAppPayTrade(DEFAULT_APP_PAY_TRADE);
            shell.setAppPayStatus(DEFAULT_APP_PAY_STATUS);
            shell.setAppPayReturn(DEFAULT_APP_PAY_RETURN);
            shell.setAppPayCancel(DEFAULT_APP_PAY_CANCEL);
            PayPufaConfig merged = PayChannelConfigMergeSupport.mergePufaNotify(shell, ch);
            PayPufaConfigInfoVO vo = PayPufaConfigConvert.INSTANCE.toInfoVO(merged);
            if (vo != null) {
                vo.setStatusName(PayPufaConfigStatusEnum.getDescByValue(vo.getStatus()));
            }
            return maskSecrets(vo);
        }
        PayPufaConfig merged = PayChannelConfigMergeSupport.mergePufaNotify(row, ch);
        PayPufaConfigInfoVO vo = PayPufaConfigConvert.INSTANCE.toInfoVO(merged);
        if (vo != null) {
            vo.setStatusName(PayPufaConfigStatusEnum.getDescByValue(vo.getStatus()));
        }
        return maskSecrets(vo);
    }

    public PageRespVO<PayPufaConfigListVO> findPage(Page<PayPufaConfig> page, PayPufaConfigQueryVO query) {
        Page<PayPufaConfig> result = payPufaConfigService.findPage(page, query);
        PageRespVO<PayPufaConfigListVO> pageVo = PayPufaConfigConvert.INSTANCE.toPageRespVO(result);
        if (pageVo.getRecords() != null) {
            pageVo.getRecords().forEach(r ->
                    r.setStatusName(PayPufaConfigStatusEnum.getDescByValue(r.getStatus())));
        }
        return pageVo;
    }

    @Transactional(readOnly = false)
    public void save(PayPufaConfigSaveDTO dto) {
        PayPufaConfig entity = PayPufaConfigConvert.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/pfNotify");
        }
        if (StrUtil.isBlank(entity.getAppPayTrade())) {
            entity.setAppPayTrade(DEFAULT_APP_PAY_TRADE);
        }
        if (StrUtil.isBlank(entity.getAppPayStatus())) {
            entity.setAppPayStatus(DEFAULT_APP_PAY_STATUS);
        }
        if (StrUtil.isBlank(entity.getAppPayReturn())) {
            entity.setAppPayReturn(DEFAULT_APP_PAY_RETURN);
        }
        if (StrUtil.isBlank(entity.getAppPayCancel())) {
            entity.setAppPayCancel(DEFAULT_APP_PAY_CANCEL);
        }
        resolveExistingPufa(entity);
        if (StrUtil.isNotBlank(entity.getId())) {
            PayPufaConfig existing = payPufaConfigService.get(entity.getId());
            if (StrUtil.isBlank(entity.getChannelConfigId()) && existing != null
                    && StrUtil.isNotBlank(existing.getChannelConfigId())) {
                entity.setChannelConfigId(existing.getChannelConfigId());
            }
            mergeSecrets(entity, existing, dto);
        } else {
            if (entity.getStatus() == null) {
                entity.setStatus(PayPufaConfigStatusEnum.ENABLED.getValue());
            }
            if (entity.getPfaEnabled() == null) {
                entity.setPfaEnabled(0);
            }
        }
        if (PayPufaConfigStatusEnum.ENABLED.getValue().equals(entity.getStatus())) {
            payPufaConfigService.disableOtherActiveExcept(entity.getTenantId(), entity.getId());
        }
        payChannelPufaSyncSupport.syncFromPufa(entity);
        payPufaConfigService.save(entity);
        payPufaConfigRuntimeService.evictRuntimeCache();
    }

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

    private void resolveExistingPufa(PayPufaConfig entity) {
        if (StrUtil.isNotBlank(entity.getId())) {
            return;
        }
        if (StrUtil.isNotBlank(entity.getChannelConfigId())) {
            PayChannelConfig ch = payChannelConfigService.get(entity.getChannelConfigId().trim());
            if (ch == null || !PayChannelCodeEnum.PFA.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"));
            }
            PayPufaConfig byCh = payPufaConfigService.findByChannelConfigId(entity.getChannelConfigId().trim());
            if (byCh != null) {
                entity.setId(byCh.getId());
            }
            return;
        }
        PayPufaConfig existing = payPufaConfigService.findByConfigCode(entity.getConfigCode(), entity.getTenantId());
        if (existing != null) {
            entity.setId(existing.getId());
            if (StrUtil.isBlank(entity.getChannelConfigId()) && StrUtil.isNotBlank(existing.getChannelConfigId())) {
                entity.setChannelConfigId(existing.getChannelConfigId());
            }
        }
    }

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

    private static void mergeSecrets(PayPufaConfig target, PayPufaConfig existing, PayPufaConfigSaveDTO dto) {
        if (existing == null) {
            return;
        }
        if (isPlaceholderOrBlank(dto.getSecret())) {
            target.setSecret(existing.getSecret());
        }
        if (isPlaceholderOrBlank(dto.getPrivateKey())) {
            target.setPrivateKey(existing.getPrivateKey());
        }
        if (isPlaceholderOrBlank(dto.getSpdbPublicKey())) {
            target.setSpdbPublicKey(existing.getSpdbPublicKey());
        }
    }

    private static boolean isPlaceholderOrBlank(String value) {
        return StrUtil.isBlank(value) || SECRET_PLACEHOLDER.equals(value.trim());
    }

    private static PayPufaConfigInfoVO maskSecrets(PayPufaConfigInfoVO vo) {
        if (vo == null) {
            return null;
        }
        if (StrUtil.isNotBlank(vo.getSecret())) {
            vo.setSecret(SECRET_PLACEHOLDER);
        }
        if (StrUtil.isNotBlank(vo.getPrivateKey())) {
            vo.setPrivateKey(SECRET_PLACEHOLDER);
        }
        if (StrUtil.isNotBlank(vo.getSpdbPublicKey())) {
            vo.setSpdbPublicKey(SECRET_PLACEHOLDER);
        }
        return vo;
    }
}
