package cn.axzo.workflow.starter.feign.ext;

import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.util.ThreadUtil;
import feign.InvocationHandlerFactory;
import feign.Target;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.Objects;

/**
 * Workflow Engine Starter Core Service Invocation Handler
 *
 * @author wangli
 * @since 2024/5/29 22:58
 */
class WorkflowEngineStarterInvocationHandler implements InvocationHandler {

    private final Target target;
    private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;

    public WorkflowEngineStarterInvocationHandler(Target target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
        this.target = target;
        this.dispatch = dispatch;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("equals".equals(method.getName())) {
            try {
                Object otherHandler =
                        args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                return equals(otherHandler);
            } catch (IllegalArgumentException e) {
                return false;
            }
        } else if ("hashCode".equals(method.getName())) {
            return hashCode();
        } else if ("toString".equals(method.getName())) {
            return toString();
        }

        parseInvokeModelAnnotation(method);

        return dispatch.get(method).invoke(args);
    }

    private void parseInvokeModelAnnotation(Method method) {
        InvokeMode annotation = AnnotationUtils.getAnnotation(method, InvokeMode.class);
        if (Objects.nonNull(annotation)) {
            ThreadUtil.set(annotation.value());
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof WorkflowEngineStarterInvocationHandler) {
            WorkflowEngineStarterInvocationHandler other = (WorkflowEngineStarterInvocationHandler) obj;
            return target.equals(other.target);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return target.hashCode();
    }

    @Override
    public String toString() {
        return target.toString();
    }

    public Class<?> getTargetClass() {
        return target.getClass();
    }
}
