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

import cn.hutool.core.util.StrUtil;
import com.jeesharp.business.modules.pay.payalipayconfig.convert.PayAlipayConfigConvert;
import com.jeesharp.business.modules.pay.payalipayconfig.dto.PayAlipayConfigSaveDTO;
import com.jeesharp.business.modules.pay.payalipayconfig.entity.PayAlipayConfig;
import com.jeesharp.business.modules.pay.payalipayconfig.enums.PayAlipayConfigStatusEnum;
import com.jeesharp.business.modules.pay.payalipayconfig.service.PayAlipayConfigRuntimeService;
import com.jeesharp.business.modules.pay.payalipayconfig.service.PayAlipayConfigService;
import com.jeesharp.business.modules.pay.payalipayconfig.vo.PayAlipayConfigInfoVO;
import com.jeesharp.business.modules.pay.payalipayconfig.vo.PayAlipayConfigListVO;
import com.jeesharp.business.modules.pay.payalipayconfig.vo.PayAlipayConfigQueryVO;
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.PayChannelAlipaySyncSupport;
import com.jeesharp.business.modules.pay.paychannelconfig.support.PayChannelConfigMergeSupport;
import com.jeesharp.business.modules.pay.paychannelconfig.support.PayChannelTenantSupport;
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;

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

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

    private final PayAlipayConfigService payAlipayConfigService;
    private final PayAlipayConfigRuntimeService payAlipayConfigRuntimeService;
    private final PayChannelAlipaySyncSupport payChannelAlipaySyncSupport;
    private final PayChannelConfigService payChannelConfigService;

    public PayAlipayConfigInfoVO get(String id) {
        return maskSecrets(PayAlipayConfigConvert.INSTANCE.toInfoVO(payAlipayConfigService.get(id)));
    }

    public PayAlipayConfigInfoVO getActive(String tenantId) {
        PayAlipayConfig active = payAlipayConfigService.findActive(tenantId);
        PayAlipayConfigInfoVO vo = PayAlipayConfigConvert.INSTANCE.toInfoVO(active);
        if (vo != null) {
            vo.setStatusName(PayAlipayConfigStatusEnum.getDescByValue(vo.getStatus()));
        }
        return maskSecrets(vo);
    }

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

    /**
     * 按 {@code pay_channel_config.id} 加载支付宝子配置；无子表行时返回可首次保存的空壳。
     */
    public PayAlipayConfigInfoVO getByChannelConfigId(String channelConfigId) {
        PayChannelConfig ch = requireAlipayChannel(channelConfigId);
        PayAlipayConfig row = payAlipayConfigService.findByChannelConfigId(ch.getId());
        if (row == null) {
            PayAlipayConfig shell = new PayAlipayConfig();
            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(PayAlipayConfigStatusEnum.ENABLED.getValue());
            shell.setAliEnabled(0);
            shell.setCertModel(0);
            shell.setCharset("UTF-8");
            shell.setSignType("RSA2");
            shell.setPayCenterNotifyPath("/api/pay/payNotify/aliPayNotify");
            PayAlipayConfig merged = PayChannelConfigMergeSupport.mergeAlipayNotify(shell, ch);
            PayAlipayConfigInfoVO vo = PayAlipayConfigConvert.INSTANCE.toInfoVO(merged);
            if (vo != null) {
                vo.setStatusName(PayAlipayConfigStatusEnum.getDescByValue(vo.getStatus()));
            }
            return maskSecrets(vo);
        }
        PayAlipayConfig merged = PayChannelConfigMergeSupport.mergeAlipayNotify(row, ch);
        PayAlipayConfigInfoVO vo = PayAlipayConfigConvert.INSTANCE.toInfoVO(merged);
        if (vo != null) {
            vo.setStatusName(PayAlipayConfigStatusEnum.getDescByValue(vo.getStatus()));
        }
        return maskSecrets(vo);
    }

    public PageRespVO<PayAlipayConfigListVO> findPage(Page<PayAlipayConfig> page, PayAlipayConfigQueryVO query) {
        Page<PayAlipayConfig> result = payAlipayConfigService.findPage(page, query);
        PageRespVO<PayAlipayConfigListVO> pageVo = PayAlipayConfigConvert.INSTANCE.toPageRespVO(result);
        if (pageVo.getRecords() != null) {
            pageVo.getRecords().forEach(r ->
                    r.setStatusName(PayAlipayConfigStatusEnum.getDescByValue(r.getStatus())));
        }
        return pageVo;
    }

    @Transactional(readOnly = false)
    public void save(PayAlipayConfigSaveDTO dto) {
        PayAlipayConfig entity = PayAlipayConfigConvert.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/aliPayNotify");
        }
        if (StrUtil.isBlank(entity.getCharset())) {
            entity.setCharset("UTF-8");
        }
        if (StrUtil.isBlank(entity.getSignType())) {
            entity.setSignType("RSA2");
        }
        resolveExistingAlipay(entity);
        if (StrUtil.isNotBlank(entity.getId())) {
            PayAlipayConfig existing = payAlipayConfigService.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(PayAlipayConfigStatusEnum.ENABLED.getValue());
            }
            if (entity.getAliEnabled() == null) {
                entity.setAliEnabled(0);
            }
            if (entity.getCertModel() == null) {
                entity.setCertModel(0);
            }
        }
        if (PayAlipayConfigStatusEnum.ENABLED.getValue().equals(entity.getStatus())) {
            payAlipayConfigService.disableOtherActiveExcept(entity.getTenantId(), entity.getId());
        }
        payChannelAlipaySyncSupport.syncFromAlipay(entity);
        payAlipayConfigService.save(entity);
        payAlipayConfigRuntimeService.evictClientCache();
    }

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

    private void resolveExistingAlipay(PayAlipayConfig entity) {
        if (StrUtil.isNotBlank(entity.getId())) {
            return;
        }
        if (StrUtil.isNotBlank(entity.getChannelConfigId())) {
            PayChannelConfig ch = payChannelConfigService.get(entity.getChannelConfigId().trim());
            if (ch == null || !PayChannelCodeEnum.ALIPAY.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"));
            }
            PayAlipayConfig byCh = payAlipayConfigService.findByChannelConfigId(entity.getChannelConfigId().trim());
            if (byCh != null) {
                entity.setId(byCh.getId());
            }
            return;
        }
        PayAlipayConfig existing = payAlipayConfigService.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 requireAlipayChannel(String channelConfigId) {
        if (StrUtil.isBlank(channelConfigId)) {
            throw new BizErrorException("渠道配置 ID 不能为空");
        }
        PayChannelConfig ch = payChannelConfigService.get(channelConfigId.trim());
        if (ch == null) {
            throw new BizErrorException("渠道配置不存在");
        }
        if (!PayChannelCodeEnum.ALIPAY.getCode().equalsIgnoreCase(StrUtil.trimToEmpty(ch.getChannelCode()))) {
            throw new BizErrorException("该渠道配置不是支付宝渠道");
        }
        return ch;
    }

    private static void mergeSecrets(PayAlipayConfig target, PayAlipayConfig existing, PayAlipayConfigSaveDTO dto) {
        if (existing == null) {
            return;
        }
        if (isPlaceholderOrBlank(dto.getPrivateKey())) {
            target.setPrivateKey(existing.getPrivateKey());
        }
        if (isPlaceholderOrBlank(dto.getAliPayPublicKey())) {
            target.setAliPayPublicKey(existing.getAliPayPublicKey());
        }
    }

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

    private static PayAlipayConfigInfoVO maskSecrets(PayAlipayConfigInfoVO vo) {
        if (vo == null) {
            return null;
        }
        if (StrUtil.isNotBlank(vo.getPrivateKey())) {
            vo.setPrivateKey(SECRET_PLACEHOLDER);
        }
        if (StrUtil.isNotBlank(vo.getAliPayPublicKey()) && !vo.getAliPayPublicKey().startsWith("/")) {
            vo.setAliPayPublicKey(SECRET_PLACEHOLDER);
        }
        return vo;
    }
}
