package com.yihu.hos.common.listener;

import com.yihu.hos.common.constants.BrokerConstant;
import com.yihu.hos.common.dao.BrokerDao;
import com.yihu.hos.core.constants.CoreConstant;
import com.yihu.hos.core.datatype.ClassFileUtil;
import com.yihu.hos.core.datatype.CollectionUtil;
import com.yihu.hos.models.SystemCamelContext;
import com.yihu.hos.models.SystemClassMapping;
import com.yihu.hos.models.SystemServiceFlow;
import com.yihu.hos.models.SystemServiceFlowClass;
import org.apache.camel.builder.RouteBuilder;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ApplicationStartListener implements ApplicationListener<ContextRefreshedEvent> {
    private static Logger logger = LogManager.getLogger(ApplicationStartListener.class);

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        try {
            camelRouteStart(contextRefreshedEvent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 这是一个固定的存储class文件的根路径
     * 正式系统中，这个值可来自于系统的配置文件
     */
    private void camelRouteStart(ContextRefreshedEvent contextRefreshedEvent) throws Exception {
        //从数据库获取所有路由对应的class路径以便动态加载
        BrokerDao brokerDao = (BrokerDao) contextRefreshedEvent.getApplicationContext().getBean(BrokerDao.BEAN_ID);
        List<SystemServiceFlow> systemServiceFlowList = brokerDao.getSystemServiceFlowList();
        List<SystemServiceFlowClass> systemServiceFlowClassList = brokerDao.getSystemServiceFlowClassList();
        //对所有route与processor进行分类存储
        Map<String, List<SystemServiceFlowClass>> systemServiceFlowClassGroupMap = new HashMap<>();
        for (SystemServiceFlowClass systemServiceFlowClass : systemServiceFlowClassList) {
            Integer flowId = systemServiceFlowClass.getFlowId();
            String type = systemServiceFlowClass.getType();
            if (systemServiceFlowClassGroupMap.containsKey(flowId)) {
                List<SystemServiceFlowClass> classList = systemServiceFlowClassGroupMap.get(type + flowId);
                classList.add(systemServiceFlowClass);
                systemServiceFlowClassGroupMap.put(type + flowId.toString(), classList);
            } else {
                List<SystemServiceFlowClass> classList = new ArrayList<>();
                classList.add(systemServiceFlowClass);
                systemServiceFlowClassGroupMap.put(type + flowId.toString(), classList);
            }
        }

        List<File> systemClassFlowPaths = new ArrayList<>();
        List<RouteBuilder> alreadyRouteBuilders = new ArrayList<>();
        for (SystemServiceFlow systemServiceFlow : systemServiceFlowList) {
            Integer flowId = systemServiceFlow.getId();
            String code = systemServiceFlow.getCode();
            // 这是system业务系统在本地存储class的根目录
            File systemClassFlowPath = new File(ClassLoader.getSystemResource("").getPath() + "/" + code);
            if (!systemClassFlowPaths.contains(systemClassFlowPath)) {
                systemClassFlowPaths.add(systemClassFlowPath);
            }

            List<SystemServiceFlowClass> processesClassList = systemServiceFlowClassGroupMap.get("processor" + flowId);
            List<SystemServiceFlowClass> routesClassList = systemServiceFlowClassGroupMap.get("route" + flowId);
            // 创建processor文件
            if (!CollectionUtil.isEmpty(processesClassList)) {
                for (SystemServiceFlowClass processesClass : processesClassList) {
                    String className = processesClass.getClassName();
                    String packageName = processesClass.getPackageName();
                    String classPath = processesClass.getClassPath();
                    // 创建文件
                    ClassFileUtil.createClassfile(systemClassFlowPath.toURI().toURL(), packageName, className, classPath);
                    // 记录到工具类中，以便其它线程需要时进行取用
                    SystemClassMapping.getSystemClassNameMapping().put(code + BrokerConstant.PROCESSOR, code + CoreConstant.DOT + packageName + CoreConstant.DOT + className);
                }
            }
            if (!CollectionUtil.isEmpty(routesClassList)) {
                // 创建route文件
                for (SystemServiceFlowClass routesClass : routesClassList) {
                    String className = routesClass.getClassName();
                    String packageName = routesClass.getPackageName();
                    String classPath = routesClass.getClassPath();
                    // 创建文件
                    ClassFileUtil.createClassfile(systemClassFlowPath.toURI().toURL(), packageName, className, classPath);
                    // 记录到工具类中，以便其它线程需要时进行取用
                    SystemClassMapping.getSystemClassNameMapping().put(code + BrokerConstant.ROUTE, code + CoreConstant.DOT + packageName + CoreConstant.DOT + className);
                    ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
                    try {
                        Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>) currentClassLoader.loadClass(SystemClassMapping.getSystemClassNameMapping().get(code + BrokerConstant.ROUTE));
                        if (routeBuilderClass != null) {
                            RouteBuilder routeBuilder = routeBuilderClass.newInstance();
                            alreadyRouteBuilders.add(routeBuilder);
                        }
                    } catch (Exception e) {
                        logger.info("缺少class文件：" + code);
                        continue;
                    }
                }
            }
        }
        // 4、=============
        // 首先启动Apache Camel服务
        logger.info("Apache Camel Context 启动完成......");
        // 加载和设置ClassLoader
        List<URL> URLs = new ArrayList<>();
        for (File systemClassFlowPath : systemClassFlowPaths) {
            URLs.add(systemClassFlowPath.toURI().toURL());
        }
        ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
        ClassLoader camelESBClassLoader = new URLClassLoader(URLs.toArray(new URL[]{}), currentClassLoader);
        Thread.currentThread().setContextClassLoader(camelESBClassLoader);
        SystemCamelContext.getDefaultCamelContext().setApplicationContextClassLoader(camelESBClassLoader);
        // 然后就可以进行RouteBuilder的加载
        SystemCamelContext.getDefaultCamelContext().setTracing(true);
        SystemCamelContext.getDefaultCamelContext().setUseMDCLogging(true);
        for (RouteBuilder routeBuilder : alreadyRouteBuilders) {
            try {
                SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
            } catch (Exception e) {
                logger.warn(e.getMessage(), e);
            }
        }

        SystemCamelContext.getDefaultCamelContext().start();
    }
}
