package com.rj.common;

import org.springframework.util.DigestUtils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 密码工具类
 *
 * @author 系统生成
 * @since 2025-08-07
 */
public class PasswordUtil {

    /**
     * 默认盐值
     */
    public static final String DEFAULT_SALT = "rj_system_2025";

    /**
     * 可逆加密标记，避免重复加密
     */
    private static final String ENC_PREFIX = "ENC$";

    private static final SecureRandom SECURE_RANDOM = new SecureRandom();

    /**
     * MD5加密密码
     *
     * @param password 原始密码
     * @return 加密后的密码
     */
    public static String encryptPassword(String password) {
        return DigestUtils.md5DigestAsHex(password.getBytes());
    }

    /**
     * MD5加密密码（带盐值）
     *
     * @param password 原始密码
     * @param salt     盐值
     * @return 加密后的密码
     */
    public static String encryptPassword(String password, String salt) {
        String saltedPassword = password + salt;
        return DigestUtils.md5DigestAsHex(saltedPassword.getBytes());
    }

    /**
     * 使用默认盐值加密密码
     *
     * @param password 原始密码
     * @return 加密后的密码
     */
    public static String encryptPasswordWithDefaultSalt(String password) {
        return encryptPassword(password, DEFAULT_SALT);
    }

    /**
     * 可逆加密（AES-GCM），输出格式：ENC$base64(iv).base64(cipherText)
     * <p>
     * 说明：此方法用于需要可解密的配置值（例如企微配置），不要用于用户密码。
     */
    public static String encryptReversibleWithDefaultSalt(String plainText) {
        if (plainText == null) {
            plainText = "";
        }
        if (isEncryptedReversible(plainText)) {
            return plainText;
        }
        try {
            byte[] iv = new byte[12]; // GCM recommended IV length
            SECURE_RANDOM.nextBytes(iv);

            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec spec = new GCMParameterSpec(128, iv);
            cipher.init(Cipher.ENCRYPT_MODE, deriveAesKey(DEFAULT_SALT), spec);

            byte[] cipherBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            String ivB64 = Base64.getEncoder().encodeToString(iv);
            String ctB64 = Base64.getEncoder().encodeToString(cipherBytes);
            return ENC_PREFIX + ivB64 + "." + ctB64;
        } catch (Exception e) {
            throw new IllegalStateException("encrypt reversible failed: " + e.getMessage(), e);
        }
    }

    /**
     * 可逆解密（AES-GCM），支持未加密值直接原样返回。
     */
    public static String decryptReversibleWithDefaultSalt(String encryptedOrPlain) {
        if (encryptedOrPlain == null) {
            return null;
        }
        if (!isEncryptedReversible(encryptedOrPlain)) {
            return encryptedOrPlain;
        }
        try {
            String payload = encryptedOrPlain.substring(ENC_PREFIX.length());
            int dot = payload.indexOf('.');
            if (dot <= 0 || dot >= payload.length() - 1) {
                throw new IllegalArgumentException("bad encrypted format");
            }
            byte[] iv = Base64.getDecoder().decode(payload.substring(0, dot));
            byte[] cipherBytes = Base64.getDecoder().decode(payload.substring(dot + 1));

            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec spec = new GCMParameterSpec(128, iv);
            cipher.init(Cipher.DECRYPT_MODE, deriveAesKey(DEFAULT_SALT), spec);
            byte[] plain = cipher.doFinal(cipherBytes);
            return new String(plain, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new IllegalStateException("decrypt reversible failed: " + e.getMessage(), e);
        }
    }

    public static boolean isEncryptedReversible(String value) {
        return value != null && value.startsWith(ENC_PREFIX);
    }

    private static SecretKey deriveAesKey(String salt) {
        try {
            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
            byte[] keyBytes = sha256.digest(String.valueOf(salt).getBytes(StandardCharsets.UTF_8));
            // 256-bit AES key
            return new SecretKeySpec(keyBytes, "AES");
        } catch (Exception e) {
            throw new IllegalStateException("derive key failed: " + e.getMessage(), e);
        }
    }

    /**
     * 验证密码
     *
     * @param inputPassword    输入的密码
     * @param encryptedPassword 数据库中存储的加密密码
     * @return 是否匹配
     */
    public static boolean verifyPassword(String inputPassword, String encryptedPassword) {
        String inputEncrypted = encryptPassword(inputPassword,DEFAULT_SALT);
        return inputEncrypted.equals(encryptedPassword);
    }

    /**
     * 验证密码（带盐值）
     *
     * @param inputPassword    输入的密码
     * @param encryptedPassword 数据库中存储的加密密码
     * @param salt             盐值
     * @return 是否匹配
     */
    public static boolean verifyPassword(String inputPassword, String encryptedPassword, String salt) {
        String inputEncrypted = encryptPassword(inputPassword, DEFAULT_SALT);
        return inputEncrypted.equals(encryptedPassword);
    }

    /**
     * 使用默认盐值验证密码
     *
     * @param inputPassword    输入的密码
     * @param encryptedPassword 数据库中存储的加密密码
     * @return 是否匹配
     */
    public static boolean verifyPasswordWithDefaultSalt(String inputPassword, String encryptedPassword) {
        return verifyPassword(inputPassword, encryptedPassword, DEFAULT_SALT);
    }
}























































































































