package com.muyu.rule.server.pool.container;

import com.muyu.rule.server.EngineConfig;
import com.muyu.rule.server.annotation.EngineParam;
import com.muyu.rule.server.exception.RuleEngineException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author：张承志
 * @Package：com.muyu.rule.server
 * @Project：cloud-etl-rule
 * @name：EngineContainer
 * @Date：2024/8/22 22:32
 */
public class EngineContainer {

    private static final Logger log = LoggerFactory.getLogger(EngineContainer.class);

    private static final Map<String, Object> methodMap = new ConcurrentHashMap<>(16);
    private static final Map<String, Object> classMap = new ConcurrentHashMap<>(16);
    private static final Map<String, Object> instanceMap = new ConcurrentHashMap<>(16);

    public static void loadEngineInstance(String engineKey, Class<?> clazz) {
        Method method = findMethodByClass(EngineConfig.executionMethodName.get(), clazz);

        if (method == null) {
            log.info("初始化规则引擎 -> {}  失败 缺少 {} 方法", engineKey, EngineConfig.executionMethodName.get());
            return;
        }

        try {
            instanceMap.put(engineKey, clazz.newInstance());
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        classMap.put(engineKey, clazz);
        methodMap.put(engineKey, method);
//获取所有的参数
        Class<?>[] parameterTypes = method.getParameterTypes();
        //获取所有的注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        ArrayList<String> engineParams = new ArrayList<>();

        for (int i = 0; i < parameterTypes.length; i++) {
            Annotation[] paramAnn = parameterAnnotations[i];
            if (paramAnn.length == 0) {
                throw new RuleEngineException("请给所有参数填写注释!");
            }
            if (paramAnn.length > 1) {
                throw new RuleEngineException("参数仅支持一个注释!");
            }
            EngineParam engineParam = null;
            if (paramAnn[0] instanceof EngineParam) {
                engineParam = (EngineParam) paramAnn[0];
            }

            if (engineParam == null) {
                throw new RuleEngineException("请使用EngineParam注解");
            } else if (engineParam.name() == null || engineParam.name().isEmpty()) {
                throw new RuleEngineException("engineParam -- name 不可为null");
            }
            engineParams.add(engineParam.name());
        }
    }

    private static Method findMethodByClass(String methodName, Class<?> clazz) {
        Method[] methods = clazz.getDeclaredMethods();
        return Arrays.stream(methods)
                .filter(method -> method.getName().equals(methodName))
                .findFirst()
                .orElse(null);
    }

    public static List<String> getMethodEngineParamMap(String engineKey) {
        Method method = (Method) methodMap.get(engineKey);
        if (method == null) {
            return new ArrayList<>();
        }
        Class<?>[] parameterTypes = method.getParameterTypes();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        List<String> params = new ArrayList<>();
        for (int i = 0; i < parameterTypes.length; i++) {
            Annotation[] paramAnn = parameterAnnotations[i];
            if (paramAnn.length == 0) {
                continue;
            }
            EngineParam engineParam = (EngineParam) paramAnn[0];
            if (engineParam != null && !engineParam.name().isEmpty()) {
                params.add(engineParam.name());
            }
        }
        return params;
    }

    public static Object getInstanceMap(String engineKey) {
        return instanceMap.get(engineKey);
    }

    public static Method getMethodMap(String engineKey) {
        return (Method) methodMap.get(engineKey);
    }

    public static int getSumEngine() {
        return classMap.size();
    }
}
