package com.elab.spring.aop;

import com.elab.core.exception.BusinessException;
import com.elab.core.utils.StringUtils;
import org.apache.commons.collections.CollectionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.hibernate.validator.constraints.NotBlank;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import javax.validation.ConstraintViolation;
import javax.validation.Valid;
import javax.validation.groups.Default;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Set;

/**
 * 方法实体的参数校验
 *
 * @author : liukx
 * @create : 2018/6/6 13:55
 * @email : liukx@elab-plus.com
 */
@Configuration
public class ValidAspect {

    private final Logger logger = LoggerFactory.getLogger(ValidAspect.class);

    private String defaultParamsError = "CORE.PARAMS.001";

    @Autowired
    private Environment env;

    /**
     * 定义一个消息资源加载器
     *
     * @return
     */
    @Bean
    public ReloadableResourceBundleMessageSource resourceBundleMessageSource() {
        ReloadableResourceBundleMessageSource resourceBundleMessageSource = new ReloadableResourceBundleMessageSource();
        resourceBundleMessageSource.addBasenames(env.getProperty("valid.aspect.base.names", "classpath:message/validation/validationMessages"));
        resourceBundleMessageSource.setDefaultEncoding("UTF-8");
        return resourceBundleMessageSource;
    }

    /**
     * 构建一个本地校验的工厂类
     *
     * @return
     */
    @Bean
    public LocalValidatorFactoryBean localValidatorFactoryBean() {
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
        localValidatorFactoryBean.setValidationMessageSource(resourceBundleMessageSource());
        return localValidatorFactoryBean;
    }

    public void before(JoinPoint point) {
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        Parameter[] parameters = method.getParameters();
        if (parameters != null && parameters.length > 0) {
            Object[] args = point.getArgs();
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[i];
                // 对象校验
                Valid annotation = parameter.getAnnotation(Valid.class);
                Object arg = args[i];
                if (annotation != null) {
                    logger.debug(" 开启参数校验... ");
                    Set<ConstraintViolation<Object>> validate = localValidatorFactoryBean().validate(arg, Default.class);
                    if (CollectionUtils.isNotEmpty(validate)) {
                        for (ConstraintViolation cv : validate) {
                            String message = cv.getPropertyPath().toString() + " - " + cv.getMessage();
                            throw new BusinessException(defaultParamsError, message);
                        }
                    }
                    logger.debug(" 参数校验通过... ");
                }

                // 普通参数不能为空校验
                NotBlank notBlankAnnotation = parameter.getAnnotation(NotBlank.class);
                if (notBlankAnnotation != null) {
                    if (arg == null || !StringUtils.isNotEmpty(arg.toString())) {
                        String message = notBlankAnnotation.message();
                        throw new BusinessException(defaultParamsError, message);
                    }
                }
            }
        }
    }
}
