package com.yeejoin.precontrol.common.aop;

import com.yeejoin.precontrol.common.annotations.AfterInsert;
import com.yeejoin.precontrol.common.annotations.BeforeInsert;
import com.yeejoin.precontrol.common.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @program: 实体插入拦截AOP 由AOP转交数据给对应Listener
 * @description:
 * @author: duanwei
 * @create: 2020-07-19 15:05
 **/
@Aspect
@Component
@Slf4j
public class EntityInsertAop {
    @Pointcut("execution(public * com.yeejoin.precontrol.common.service..*.add(..))" +
            "||execution(public * com.yeejoin.precontrol.common.service..*.save(..))")
    public void insert() {
    }

    @Before("insert()")
    public void doBefore(JoinPoint joinPoint) {
        //方法名称 例如add insert
        String name = joinPoint.getSignature().getName();
        Object[] objs = joinPoint.getArgs();
        Object obj;
        if ("add".equals(name) || "insert".equals(name)) {
            obj = objs[0];
            //数据对象的名字 例如task
            String simpleName = obj.getClass().getSimpleName();
            //根据数据对象找到listener监听器对象
            String listenerName = transformName(simpleName) + "EntityListener";
            Object listenerBean = SpringUtils.getBean(listenerName);
            if (listenerBean != null) {
                //进行数据invoke调用
                Method[] methods = listenerBean.getClass().getDeclaredMethods();
                for (Method method : methods) {
                    Annotation annotation = method.getAnnotation(BeforeInsert.class);
                    if (annotation != null) {
                        //当前method就是我需要操作的method
                        try {
//                            method.setAccessible(true);
                            ReflectionUtils.makeAccessible(method);
                            method.invoke(listenerBean, obj);
                        } catch (IllegalAccessException e) {
                            log.error("方法AOP前置处理权限不足");
                        } catch (InvocationTargetException e) {
                            log.error("方法AOP前置处理失败");
                        }
                    }
                }
            }
        }


    }

    //目标方法执行完后执行
    @After("insert()")
    public void doAfter(JoinPoint joinPoint) {
        //方法名称 例如add insert
        String name = joinPoint.getSignature().getName();
        Object[] objs = joinPoint.getArgs();
        Object obj;
        if ("add".equals(name) || "insert".equals(name)) {
            obj = objs[0];
            //数据对象的名字 例如task
            String simpleName = obj.getClass().getSimpleName();
            //根据数据对象找到listener监听器对象
            String listenerName = transformName(simpleName) + "EntityListener";
            Object listenerBean = SpringUtils.getBean(listenerName);
            if (listenerBean != null) {
                //进行数据invoke调用
                Method[] methods = listenerBean.getClass().getDeclaredMethods();
                for (Method method : methods) {
                    Annotation annotation = method.getAnnotation(AfterInsert.class);
                    if (annotation != null) {
                        //当前method就是我需要操作的method
                        try {
                            ReflectionUtils.makeAccessible(method);
                            method.invoke(listenerBean, obj);
                        } catch (IllegalAccessException e) {
                            log.error("方法AOP前置处理权限不足");
                        } catch (InvocationTargetException e) {
                            log.error("方法AOP前置处理失败");
                        }
                    }
                }
            }
        }
    }

    // 前后一起插入的完整逻辑
    @Around("insert()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long time = System.currentTimeMillis();
        Object retVal = pjp.proceed();
        time = System.currentTimeMillis() - time;
        log.info("业务执行时间" + time + "毫秒");
        return retVal;
    }

    //获取目标方法返回数据后执行
//    @AfterReturning(returning = "object", pointcut = "insert()")
//    public void doAfterReturn(Object object) {
//        System.out.println(object.toString());
//    }


    private static String transformName(String originName) {
        if (originName != null && originName.length() > 0) {
            return originName.substring(0, 1).toLowerCase() + originName.substring(1);
        }
        return originName;
    }
}
