package com.cf.imes.framework.common.validation;

import cn.hutool.core.util.ObjectUtil;
import org.apache.commons.lang3.StringUtils;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Locale;

/**
 * @author Gqr
 * @since 2024/10/17 11:27
 */
@Component
public class NumberValidator implements ConstraintValidator<NumberValid, Number> {
    private static final String ZERO = "0";

    private static final String GREATER_THAN_ZERO_NOTIFICATION = "number.greaterThanZero";

    private static final String FLOAT_NUMBER_LENGTH_ERROR_NOTIFICATION = "number.float.length.error";

    private String name;

    private int integer;

    private int fraction;

    private final MessageSource messageSource;

    public NumberValidator(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    @Override
    public void initialize(NumberValid constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
        this.name = constraintAnnotation.name();
        this.integer = constraintAnnotation.integer();
        this.fraction = constraintAnnotation.fraction();
    }

    @Override
    public boolean isValid(Number value, ConstraintValidatorContext context) {
        // 空的不校验，由原生@NotNull之类的进行判断
        if (ObjectUtil.isNull(value)) {
            return true;
        }
        // 提示信息
        String notification = null;
        if (value instanceof Integer) {
            notification = handleInteger(value.intValue());
        } else if (value instanceof Long) {
            notification = handleLong(value.longValue());
        } else if (value instanceof Double) {
            notification = handleDouble(value.doubleValue());
        } else if (value instanceof BigDecimal bigvalue) {
            notification = handleBigDecimal(bigvalue);
        }
        if (StringUtils.isNotEmpty(notification)) {
            context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
            context.buildConstraintViolationWithTemplate(notification).addConstraintViolation();
            return false;
        }
        return true;
    }

    /**
     * 校验整型
     *
     * @param value
     * @return
     */
    private String handleInteger(Integer value) {
        if (value < Integer.parseInt(ZERO)) {
            Locale locale = LocaleContextHolder.getLocale();
            return messageSource.getMessage(GREATER_THAN_ZERO_NOTIFICATION, new Object[]{
                    getFieldMessage(name, locale)
            }, locale);
        }
        return null;
    }

    /**
     * 校验长整型
     *
     * @param value
     * @return
     */
    private String handleLong(Long value) {
        if (value < Long.parseLong(ZERO)) {
            Locale locale = LocaleContextHolder.getLocale();
            return messageSource.getMessage(GREATER_THAN_ZERO_NOTIFICATION, new Object[]{
                    getFieldMessage(name, locale)
            }, locale);
        }
        return null;
    }

    /**
     * 校验浮点型
     *
     * @param value
     * @return
     */
    private String handleDouble(Double value) {
        Locale locale = LocaleContextHolder.getLocale();
        String fieldName = getFieldMessage(name, locale);
        if (value < Double.parseDouble(ZERO)) {
            return messageSource.getMessage(GREATER_THAN_ZERO_NOTIFICATION, new Object[]{fieldName}, locale);
        }
        // 处理科学计数法,保留小数点后四位
        DecimalFormat decimalFormat = new DecimalFormat("#.####");
        String valueString = decimalFormat.format(value);

        String[] split = valueString.split("\\.");
        // 获取小数点前的位数
        int integerPartLength = split[0].length();
        // 获取小数点后的位数
        int fractionalPartLength = 0;
        if (split.length == 2) {
            fractionalPartLength = split[1].length();
        }

        // 总位数不超过 8 位，小数点后位数不超过 3 位
        if (integerPartLength > integer || fractionalPartLength > fraction) {
            return messageSource.getMessage(FLOAT_NUMBER_LENGTH_ERROR_NOTIFICATION, new Object[]{
                    fieldName, integer, fraction
            }, locale);
        }
        return null;
    }

    /**
     * 校验大浮点型
     *
     * @param value
     * @return
     */
    private String handleBigDecimal(BigDecimal value) {
        Locale locale = LocaleContextHolder.getLocale();
        String fieldName = getFieldMessage(name, locale);
        if (value.compareTo(BigDecimal.ZERO) < 0) {
            return messageSource.getMessage(GREATER_THAN_ZERO_NOTIFICATION, new Object[]{fieldName}, locale);
        }

        String[] split = value.toPlainString().split("\\.");
        // 获取小数点前的位数
        int integerPartLength = split[0].length();
        // 获取小数点后的位数
        int fractionalPartLength = 0;
        if (split.length == 2) {
            fractionalPartLength = split[1].length();
        }

        // 总位数不超过 8 位，小数点后位数不超过 3 位
        if (integerPartLength > integer || fractionalPartLength > fraction) {
            return messageSource.getMessage(FLOAT_NUMBER_LENGTH_ERROR_NOTIFICATION, new Object[]{
                    fieldName, integer, fraction
            }, locale);
        }
        return null;
    }

    /**
     * 获取属性描述语种
     *
     * @return
     */
    private String getFieldMessage(String name, Locale locale) {
        try {
            return messageSource.getMessage(name, null, locale);
        } catch (Exception e) {
            return name;
        }
    }
}
