package com.kingdee.eas.custom.integration.base.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kingdee.eas.cp.eip.sso.ltpa.LtpaTokenManager;
import com.kingdee.eas.cp.eip.sso.util.PropertiesUtil;
import com.kingdee.eas.custom.integration.base.exception.CommonErrorCodes;
import com.kingdee.eas.custom.integration.base.exception.IntegrationException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Map;
import java.util.Properties;

/**
 * 加密工具类
 */
public class EncryptUtil {
    private final static Logger logger = LoggerFactory.getLogger(EncryptUtil.class);

    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
    private static final ObjectMapper objectMapper = new ObjectMapper();


    /**
     * 根据键获取配置属性值
     * <p>
     * 该方法从LTPA配置文件中获取指定键对应的属性值。如果属性对象尚未初始化，则先加载配置文件。
     * </p>
     *
     * @param key 属性键名
     * @return String 属性值，如果键不存在则返回null
     */
    public static String getProperty(String key) {
        String value = getProperties().getProperty(key);
        if (StringUtils.isBlank(value)) {
            throw new IntegrationException(CommonErrorCodes.SYSTEM_ERROR, "配置项为空：" + key);
        }
        return value;
    }


    /**
     * 使用服务端配置的密钥加密字符串
     *
     * @param content 加密字符串
     * @return
     * @throws Exception
     */
    public static String encryptStr(String content) throws Exception {
        if (StringUtils.isBlank(content)) {
            throw new IntegrationException(CommonErrorCodes.PARAM_MISSING, "加密内容为空");
        }
        // 获取加密密钥
        String dominoSecret = getProperty(LtpaTokenManager.DOMINO_SECRET);
        if (StringUtils.isBlank(dominoSecret)) {
            throw new IntegrationException(CommonErrorCodes.PARAM_MISSING, "加密密钥为空！");
        }
        // AES加密
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(dominoSecret));
        byte[] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));

        return Base64.getEncoder().encodeToString(encrypted);
    }


    /**
     * 使用服务端配置的密钥解密字符串
     *
     * @param encryptedStr 加密字符串
     * @return
     * @throws Exception
     */
    public static String decryptToStr(String encryptedStr) throws Exception {
        if (StringUtils.isBlank(encryptedStr)) {
            throw new IntegrationException(CommonErrorCodes.PARAM_MISSING, "解密内容为空");
        }
        // 获取加密密钥
        String dominoSecret = getProperty(LtpaTokenManager.DOMINO_SECRET);
        if (StringUtils.isBlank(dominoSecret)) {
            throw new IntegrationException(CommonErrorCodes.PARAM_MISSING, "加密密钥为空！");
        }

        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, getSecretKey(dominoSecret));

        byte[] decoded = Base64.getDecoder().decode(encryptedStr);
        byte[] decrypted = cipher.doFinal(decoded);

        return new String(decrypted, StandardCharsets.UTF_8);
    }


    /**
     * 根据密钥加密字符串
     *
     * @param content 需要加密的字符串
     * @param secret  密钥
     * @return
     * @throws Exception
     */
    public static String encryptStrBySecret(String content, String secret) throws Exception {
        if (StringUtils.isBlank(content)) {
            throw new IntegrationException(CommonErrorCodes.PARAM_MISSING, "加密内容为空");
        }
        if (StringUtils.isBlank(secret)) {
            throw new IntegrationException(CommonErrorCodes.PARAM_MISSING, "加密密钥为空！");
        }
        // AES加密
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(secret));
        byte[] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));

        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * 解密字符串
     */
    public static String decryptToStrBySecret(String encryptedStr, String secret) throws Exception {
        if (StringUtils.isBlank(encryptedStr)) {
            throw new IntegrationException(CommonErrorCodes.PARAM_MISSING, "解密内容为空");
        }
        if (StringUtils.isBlank(secret)) {
            throw new IntegrationException(CommonErrorCodes.PARAM_MISSING, "加密密钥为空！");
        }
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, getSecretKey(secret));

        byte[] decoded = Base64.getDecoder().decode(encryptedStr);
        byte[] decrypted = cipher.doFinal(decoded);

        return new String(decrypted, StandardCharsets.UTF_8);
    }

    /**
     * 解密为 Map
     */
    public static Map<String, Object> decryptToMap(String encryptedStr, String key) throws Exception {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));

        byte[] decoded = Base64.getDecoder().decode(encryptedStr);
        byte[] decrypted = cipher.doFinal(decoded);

        String json = new String(decrypted, StandardCharsets.UTF_8);

        return objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {
        });
    }

    /**
     * 加密 Map
     */
    public static String encryptMap(Map<String, Object> map, String key) {
        try {
            // 1. Map转JSON
            String json = objectMapper.writeValueAsString(map);

            // 2. AES加密
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));
            byte[] encrypted = cipher.doFinal(json.getBytes(StandardCharsets.UTF_8));

            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            logger.error("加密失败: {}", e.getMessage(), e);
            throw new IntegrationException(CommonErrorCodes.SYSTEM_ERROR, "加密失败");
        }
    }


    /**
     * 生成密钥
     */
    private static SecretKeySpec getSecretKey(String key) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8));
        keyGenerator.init(128, secureRandom);
        SecretKey secretKey = keyGenerator.generateKey();
        return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM);
    }

    /**
     * 加载配置文件
     */
    private static class PropertiesHolder {
        static final Properties PROPERTIES = loadProperties();

        private static Properties loadProperties() {
            String configFile = LtpaTokenManager.getDefaultLtpaConfig();
            File file = new File(configFile);
            if (!file.exists()) {
                throw new IntegrationException(CommonErrorCodes.SYSTEM_ERROR, "配置文件不存在!");
            }
            return PropertiesUtil.getProperties(configFile);
        }
    }

    private static Properties getProperties() {
        return PropertiesHolder.PROPERTIES;
    }
}