package com.zzwtec.wechat.sdk.aop;

import com.zzwtec.wechat.sdk.aop.annotation.ZZWAround;
import com.zzwtec.wechat.sdk.aop.flow.FlowData;
import com.zzwtec.wechat.sdk.aop.inject.InjectHandler;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class ZZWAspect {
    @Autowired
    private ApplicationContext context;

    @Around("@annotation(com.zzwtec.wechat.sdk.aop.annotation.ZZWAround)")
    public Object invocation(ProceedingJoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature();
        Object target = joinPoint.getTarget();
        Object[] args = joinPoint.getArgs();
        Object proceed = null;
        if(signature instanceof MethodSignature){
            MethodSignature methodSignature = (MethodSignature)signature;
            ZZWAround annotation = methodSignature.getMethod().getAnnotation(ZZWAround.class);
            if(annotation != null){
                Class<? extends InjectHandler> injectHandlerClass = annotation.value();
                InjectHandler injectHandler = context.getBean(injectHandlerClass);
                FlowData flowData = injectHandler.preHandle(target, methodSignature.getMethod(), args);
                switch (flowData){
                    case CONTINUE:
                        try {
                            proceed = joinPoint.proceed();
                        } catch (Exception e) {
                            e.printStackTrace();
                            proceed = injectHandler.throwHandler(e);
                        } finally {
                            injectHandler.finallyHandler();
                        }
                        injectHandler.afterHandler(proceed);
                        break;
                    case BREAK:
                        proceed =  flowData.getData();
                        break;
                    default:
                        return null;
                }

            }
        }
        return proceed;
    }

}
