package org.jeecg.common.util.idCard;

import org.apache.commons.lang3.StringUtils;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * 18位身份证工具类（生产环境专用）
 */
public class ChineseIdCard18Utils {

    // 身份证校验码系数
    private static final int[] WEIGHT_COEFFICIENT = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    // 校验码对应值
    private static final char[] CHECK_CODE = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
    // 18位身份证正则
    private static final Pattern ID_18_REGEX = Pattern.compile(
            "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9X]$"
    );

    /**
     * 从身份证号提取出生日期
     *
     * @param idCard 18位身份证号码
     * @return 出生日期(yyyy - MM - dd格式)
     * @throws IllegalArgumentException 身份证号无效时抛出
     */
    public static String extractBirthDate(String idCard) {
        validateIdCard(idCard);
        String birthDateStr = idCard.substring(6, 14);

        try {
            DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            return LocalDate.parse(birthDateStr, inputFormatter)
                    .format(outputFormatter);
        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("无效的出生日期编码", e);
        }
    }

    /**
     * 从身份证号提取性别
     *
     * @param idCard 18位身份证号码
     * @return 性别枚举
     * @throws IllegalArgumentException 身份证号无效时抛出
     */
    public static Gender extractGender(String idCard) {
        validateIdCard(idCard);
        char genderChar = idCard.charAt(16);
        return (genderChar % 2 == 1) ? Gender.MALE : Gender.FEMALE;
    }

    /**
     * 身份证脱敏
     *
     * @param idCard 18位身份证号码
     * @param prefixKeepLen 保留前几位
     * @param suffixKeepLen 保留后几位
     * @return 脱敏后的身份证号
     */
    public static String getDesensitization(String idCard,int prefixKeepLen, int suffixKeepLen) {
//        validateIdCard(idCard);
        return mask(idCard,prefixKeepLen,suffixKeepLen);
    }

    /**
     * 自定义脱敏方法
     * @param idCard 身份证号码
     * @param prefixKeepLen 保留前几位
     * @param suffixKeepLen 保留后几位
     * @return 脱敏后的身份证号
     */
    private static String mask(String idCard, int prefixKeepLen, int suffixKeepLen) {

        // 计算需要脱敏的部分
        int totalMaskLen = 18 - prefixKeepLen - suffixKeepLen;
        if (totalMaskLen <= 0) {
            return idCard; // 无需脱敏
        }

        // 构建脱敏字符串
        StringBuilder sb = new StringBuilder();
        sb.append(idCard.substring(0, prefixKeepLen));
        sb.append("*".repeat(totalMaskLen));
        sb.append(idCard.substring(18 - suffixKeepLen));

        return sb.toString();
    }


    /**
     * 验证18位身份证有效性
     *
     * @throws IllegalArgumentException 身份证号无效时抛出
     */
    public static void validateIdCard(String idCard) {
        Objects.requireNonNull(idCard, "身份证号不能为空");

        if (StringUtils.isBlank(idCard)) {
            throw new IllegalArgumentException("身份证号不能为空");
        }

        idCard = idCard.trim().toUpperCase();

        if (!ID_18_REGEX.matcher(idCard).matches()) {
            throw new IllegalArgumentException("身份证号格式不正确");
        }

        if (!validateCheckDigit(idCard)) {
            throw new IllegalArgumentException("身份证校验码无效");
        }

        validateBirthDate(idCard);
    }

    /**
     * 校验码验证
     */
    private static boolean validateCheckDigit(String idCard) {
        int sum = 0;
        for (int i = 0; i < 17; i++) {
            sum += (idCard.charAt(i) - '0') * WEIGHT_COEFFICIENT[i];
        }
        char checkCode = CHECK_CODE[sum % 11];
        return checkCode == idCard.charAt(17);
    }

    /**
     * 出生日期验证
     */
    private static void validateBirthDate(String idCard) {
        String birthDateStr = idCard.substring(6, 14);
        try {
            LocalDate.parse(birthDateStr, DateTimeFormatter.ofPattern("yyyyMMdd"));
        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("无效的出生日期编码");
        }
    }

}