package com.yonge.toolset.utils.validator;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 个别功能在传参时只需要部分成员变量赋值，但是接收类加入了@Valid的验证，
 * 从而不得已要在传参时把接收类所有的成员变量都赋值。
 * 该功能可以让加入了@Valid的验证的接收类中分成员变量没有赋值的时不报出异
 * 常，只针对你需要的值进行验证再报出异常。
 *
 * @author hgw
 * Created by 2021-12-20
 */
public class ValidationKit {

    /**
     * 校验
     *
     * @param result BindingResult
     * @param fields 只校验的字段
     */
    public static void validFields(BindingResult result, String... fields) {
        checkFields(result, field -> ArrayUtils.contains(fields, field));
    }

    /**
     * 忽略校验部分字段
     *
     * @param result       BindingResult
     * @param ignoreFields 忽略验证的字段
     */
    public static void ignoreFields(BindingResult result, String... ignoreFields) {
        checkFields(result, field -> !ArrayUtils.contains(ignoreFields, field));
    }

    private static void checkFields(BindingResult result, Function<String, Boolean> function) {
        if (!result.hasFieldErrors()) {
            return;
        }
        Stream<String> stringStream = result.getFieldErrors().stream()
                .map(FieldError::getField)
                .filter(function::apply);

        String errorCollect = concat(result, stringStream);
        if (StringUtils.isNotBlank(errorCollect)) {
            throw new RuntimeException(errorCollect);
        }
    }

    private static String concat(BindingResult result, Stream<String> stringStream) {
        return stringStream.filter(f -> Objects.nonNull(result.getFieldError(f)))
                .map(result::getFieldError)
                .filter(Objects::nonNull)
                .map(FieldError::getDefaultMessage)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.joining());
    }

}
