package com.elab.spring.intercept;

import com.elab.core.aop.annotations.ExceptionHandle;
import com.elab.core.exception.CheckException;
import com.elab.core.utils.ObjectUtils;
import com.elab.core.utils.StringUtils;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;

/**
 * @describe ：代码检测
 * @Author ： liukx
 * @time ： 2019/3/6 - 11:44
 */
public class CheckAnnotationProcess implements BeanPostProcessor, BeanFactoryPostProcessor {

    private Logger logger = LoggerFactory.getLogger(com.elab.spring.intercept.CheckAnnotationProcess.class);
    private ConfigurableListableBeanFactory beanFactory;

    private Environment environment;
    private boolean isException = false;
    /**
     * 排除不需要扫描验证的包名
     */
    private String excludePackage;

    public CheckAnnotationProcess(Environment environment) {
        this.environment = environment;
        this.isException = ObjectUtils.isNotEmpty(environment.getProperty("elab.isException")) ? Boolean.parseBoolean(environment.getProperty("elab.isException")) : false;
        this.excludePackage = environment.getProperty("elab.excludePackage", "");
    }

    public void setException(boolean exception) {
        isException = exception;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        String[] checkPackageList = excludePackage.split(",");
        if (checkPackageList != null && checkPackageList.length > 0) {
            String proxyName = "com.sun.proxy";
            if (AopUtils.isAopProxy(bean)) {
                Class<?> targetClass = AopUtils.getTargetClass(bean);
                String name = targetClass.getName();

                for (String singlePackage : checkPackageList) {
                    if (!name.startsWith(singlePackage) && !name.startsWith(proxyName)) {
                        checkAnnotationValid(targetClass, name);
                    }
                }
            }
        } else {
            if (AopUtils.isAopProxy(bean)) {
                Class<?> targetClass = AopUtils.getTargetClass(bean);
                String name = targetClass.getName();
                checkAnnotationValid(targetClass, name);
            }
        }
        return bean;
    }

    private void checkAnnotationValid(Class<?> targetClass, String name) {
        Method[] declaredMethods = targetClass.getDeclaredMethods();
        for (int i = 0; i < declaredMethods.length; i++) {
            Method declaredMethod = declaredMethods[i];
            String author = "";
            Transactional annotation = declaredMethod.getAnnotation(Transactional.class);
            ApiOperation apiOperation = declaredMethod.getAnnotation(ApiOperation.class);
            if (apiOperation != null && StringUtils.isNotEmpty(apiOperation.nickname())) {
                author = apiOperation.nickname();
            }
            if (annotation != null || apiOperation != null) {
                ExceptionHandle exceptionHandle = declaredMethod.getAnnotation(ExceptionHandle.class);
                if (exceptionHandle != null) {
                    if (StringUtils.isEmpty(exceptionHandle.username())) {
                        String message = "请在" + name + " \t " + declaredMethod.getName() + " --> " + author + " 方法头的@ExceptionHandle 加上username属性";
                        notifyWarning(message);
                    }
                } else {
                    String message = "请在" + name + " \t " + declaredMethod.getName() + " --> " + author + " 方法头加上 @ExceptionHandle(username = '')";
                    notifyWarning(message);
                }
            }
        }
    }

    private void notifyWarning(String message) {
        if (isException) {
            throw new CheckException(message);
        } else {
            logger.error(message);
        }
    }
}
