package com.usky.vpp.crypto;

import com.usky.common.core.exception.BusinessException;
import com.usky.vpp.config.VppUnProperties;
import com.usky.vpp.config.VppUnPropertiesRegistry;
import com.usky.vpp.config.VppUnTenantContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Base64;

/**
 * 运管平台 UN/DN 加解密门面（除 TokenRequest 外均启用）。
 */
@Service
public class VppUnCryptoService {

    private static final Logger log = LoggerFactory.getLogger(VppUnCryptoService.class);

    @Autowired
    private VppUnPropertiesRegistry propertiesRegistry;

    public boolean isActive() {
        return isCryptoActive(currentProperties());
    }

    public boolean isAnyActive() {
        return propertiesRegistry.hasCryptoEnabledTenant();
    }

    /** DN 主动请求 UN：UN 公钥加密 + DN 私钥对密文字节签名。 */
    public VppUnSmCryptoUtil.EncryptedPayload prepareRequest(String plainJson) {
        VppUnProperties properties = requireCryptoProperties();
        try {
            return VppUnSmCryptoUtil.encryptAndSignRequest(
                    plainJson, properties.getUnPublicKey(), properties.getDnPrivateKey());
        } catch (Exception ex) {
            throw new BusinessException("UN 请求加密签名失败: " + ex.getMessage());
        }
    }

    /** DN 解析 UN 响应：UN 公钥验签 + DN 私钥解密。 */
    public String parseResponse(String cipherBase64, String signBase64) {
        if (!StringUtils.hasText(signBase64)) {
            log.warn("UN 响应缺少 X-Sign");
            throw new BusinessException("UN 响应验签失败");
        }
        VppUnProperties properties = requireCryptoProperties();
        try {
            return VppUnSmCryptoUtil.verifyAndDecryptResponse(
                    cipherBase64, signBase64, properties.getUnPublicKey(), properties.getDnPrivateKey());
        } catch (BusinessException ex) {
            throw ex;
        } catch (Exception ex) {
            if (ex.getMessage() != null && ex.getMessage().toLowerCase().contains("sign verify")) {
                throw new BusinessException("UN 响应验签失败");
            }
            throw new BusinessException("UN 响应解密失败: " + ex.getMessage());
        }
    }

    /** UN 被动调用 DN：验签后解密。 */
    public String decryptInboundWithAutoTenant(String cipherBase64, String signBase64) {
        Integer tenantId = VppUnTenantContext.getTenantId();
        if (tenantId != null) {
            assertInboundVerified(cipherBase64, signBase64);
            return decryptInbound(cipherBase64);
        }
        for (VppUnProperties properties : propertiesRegistry.getAll()) {
            if (!isCryptoActive(properties)) {
                continue;
            }
            VppUnTenantContext.setTenantId(properties.getTenantId());
            try {
                if (verifyInbound(cipherBase64, signBase64)) {
                    return decryptInbound(cipherBase64);
                }
            } finally {
                VppUnTenantContext.clear();
            }
        }
        throw new BusinessException("UN 请求验签失败");
    }

    /** UN→DN 请求验签（UN 公钥，对密文字节验签）。 */
    public boolean verifyInbound(String cipherBase64, String signBase64) {
        if (!StringUtils.hasText(signBase64)) {
            log.warn("UN 请求缺少 X-Sign");
            return false;
        }
        VppUnProperties properties = currentProperties();
        if (!isCryptoActive(properties)) {
            return true;
        }
        try {
            byte[] cipherBytes = Base64.getDecoder().decode(cipherBase64.trim());
            return VppUnSmCryptoUtil.verifyCipherBytes(
                    cipherBytes, signBase64, properties.getUnPublicKey());
        } catch (Exception ex) {
            log.warn("UN 请求验签异常: {}", ex.getMessage());
            return false;
        }
    }

    /** UN→DN 请求解密（DN 私钥）。 */
    public String decryptInbound(String cipherBase64) {
        VppUnProperties properties = requireCryptoProperties();
        try {
            return VppUnSmCryptoUtil.decryptByDnPrivateKey(cipherBase64, properties.getDnPrivateKey());
        } catch (Exception ex) {
            throw new BusinessException("UN 请求解密失败: " + ex.getMessage());
        }
    }

    /** DN→UN 被动响应。 */
    public VppUnSmCryptoUtil.EncryptedPayload prepareOutbound(String plainJson) {
        return prepareRequest(plainJson);
    }

    private void assertInboundVerified(String cipherBase64, String signBase64) {
        if (!verifyInbound(cipherBase64, signBase64)) {
            throw new BusinessException("UN 请求验签失败");
        }
    }

    private VppUnProperties requireCryptoProperties() {
        VppUnProperties properties = currentProperties();
        if (!isCryptoActive(properties)) {
            throw new BusinessException("运管平台国密加解密未启用或密钥未配置");
        }
        return properties;
    }

    private VppUnProperties currentProperties() {
        return propertiesRegistry.getCurrent();
    }

    private boolean isCryptoActive(VppUnProperties properties) {
        return properties != null
                && Boolean.TRUE.equals(properties.getCryptoEnabled())
                && StringUtils.hasText(properties.getUnPublicKey())
                && StringUtils.hasText(properties.getDnPrivateKey());
    }
}
