package com.izouma.nineth.service.security;

import com.izouma.nineth.config.RequestCipherProperties;
import com.izouma.nineth.dto.security.RSAPairDTO;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.utils.CryptoUtil;
import com.izouma.nineth.utils.RSAUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;

/**
 * 请求加密服务
 *
 */
@EnableConfigurationProperties(RequestCipherProperties.class)
@AllArgsConstructor
@Slf4j
@Service
public class RequestCipherService {

    private static CryptoUtil cryptoUtil = new CryptoUtil();

    private RSACacheService rsaCacheService;

    private RequestCipherProperties requestCipherProperties;


    @PostConstruct
    public void init() throws Exception {
        //初始化支付加密工具
        cryptoUtil.init(requestCipherProperties.getPublicKey(),requestCipherProperties.getPrivateKey(),
                requestCipherProperties.getPrivateKeyPwd());
    }

    /**
     * 基于配置的加密数据
     * @return
     */
    public String encryptData(String data){
        if(StringUtils.isEmpty(data)){
            return null;
        }


        try {
            byte[] sourceDataByte = data.getBytes();
            byte[] keyDataByte = cryptoUtil.RSAEncrypt(sourceDataByte, 2048, 11, "RSA/ECB/PKCS1Padding");
            String encryptedData = Base64.getEncoder().encodeToString(keyDataByte);
            return encryptedData;
        } catch (Exception e) {
            throw new RuntimeException("数据加密失败", e);
        }
    }

    /**
     * 基于配置的解密数据
     * @return
     */
    public String decryptData(String encryptedData) {
        if (StringUtils.isEmpty(encryptedData)) {
            return null;
        }

        try {
            String cleanStr = encryptedData.replaceAll("(\r?)\n", "").trim();
            byte[] sourceDataByte = Base64.getDecoder().decode(cleanStr);
            byte[] keyDataByte = cryptoUtil.RSADecrypt(sourceDataByte, 2048, 11, "RSA/ECB/PKCS1Padding");
            String data = new String(keyDataByte);
            //自动清理空白内容
            String result = data.trim();
            return result;
        } catch (Exception e) {
            throw new RuntimeException("数据解密失败", e);
        }

    }


    /**
     * 基于用户的加密数据
     * @return
     */
    public String encryptData(Long userId, String data){
        if(StringUtils.isEmpty(data)){
           return null;
        }

        RSAPairDTO rsaPairDTO = rsaCacheService.readCachedRSAPair(userId);
        if(rsaPairDTO == null){
            throw new BusinessException("缓存的密钥已失效，请重新获取");
        }

        try {
            PublicKey publicKey = RSAUtils.getPublicKey(rsaPairDTO.getPublicKey());
            String encryptedData = RSAUtils.encrypt(data, publicKey);
            return encryptedData;
        } catch (Exception e) {
            throw new RuntimeException("解密数据失败", e);
        }
    }

    /**
     * 基于用户的解密数据
     * @return
     */
    public String decryptData(Long userId, String encryptedData){
        if(StringUtils.isEmpty(encryptedData)){
            return null;
        }

        RSAPairDTO rsaPairDTO = rsaCacheService.readCachedRSAPair(userId);
        if(rsaPairDTO == null){
            throw new BusinessException("缓存的密钥已失效，请重新获取");
        }
        try {
            PrivateKey privateKey = RSAUtils.getPrivateKey(rsaPairDTO.getPrivateKey());
            String data = RSAUtils.decrypt(encryptedData, privateKey);
            return data;
        } catch (Exception e) {
            throw new RuntimeException("解密数据失败", e);
        }
    }

}
