
package com.lideeyunji.core.framework.config.aspect.enhance;


import com.lideeyunji.core.framework.config.aspect.enhance.annotation.LideeyunJiEnhance;
import com.lideeyunji.core.framework.config.aspect.enhance.criteria.CriteriaFilterAdvicePluginUtils;
import com.lideeyunji.core.framework.config.aspect.enhance.model.*;
import com.lideeyunji.core.framework.config.aspect.enhance.plugin.*;
import com.lideeyunji.core.framework.config.aspect.enhance.strategy.enums.JavaEnhanceEnums;
import com.lideeyunji.core.framework.config.aspect.enhance.strategy.java.EnhanceJavaStrategy;
import com.lideeyunji.core.framework.entity.EnhanceJavaEntity;
import com.lideeyunji.core.framework.service.IEnhanceJavaService;
import com.lideeyunji.core.framework.utils.Func;
import com.lideeyunji.tool.framework.yunji.constant.EnhanceConstant;
import com.lideeyunji.tool.framework.yunji.model.ExecuteEnhanceModel;
import com.lideeyunji.tool.framework.yunji.model.ResultDataModel;
import com.lideeyunji.tool.framework.yunji.tool.spring.SpringUtils;
import com.lideeyunji.tool.framework.yunji.utils.FuncBase;
import groovy.lang.GroovyClassLoader;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.lideeyunji.tool.framework.yunji.constant.EnhanceConstant.ENHANCE_EXPORT;
import static com.lideeyunji.tool.framework.yunji.constant.EnhanceConstant.ENHANCE_LIST;

/**
 * @author JX
 * @create 2024-08-12 10:26
 * @dedescription:
 */
@Aspect
@Component
@Slf4j
public class LideeYunJiJavaEnhance extends LideeYunJiBaseEnhance {

    //需要处理的增强 key=按钮code value=增强列表
    private static Map<String, List<EnhanceJavaEntity>> javaEnhanceMaps = new HashMap<>();

    @Lazy
    @Autowired
    private IEnhanceJavaService javaService;


    public GroovyClassLoader groovyClassLoader = new GroovyClassLoader();

    public GroovyClassLoader getGroovyClassLoader() {
        return groovyClassLoader;
    }


    //初始化插件
    @PostConstruct
    public void initJavaEnhanceMaps() {
        List<EnhanceJavaEntity> allJavaEnhanceList = javaService.getAllJavaEnhance();
        //Java插件
        allJavaEnhanceList.forEach(enhanceJavaEntity -> {
                    Long dbformId = enhanceJavaEntity.getDbformId();
                    String buttonCode = enhanceJavaEntity.getButtonCode();

                    String pluginKey = dbformId + "_" + buttonCode;
                    javaEnhanceMaps.merge(pluginKey, new ArrayList<>(Collections.singletonList(enhanceJavaEntity)), (oldValue, newValue) -> {
                        oldValue.addAll(newValue);
                        return oldValue;
                    });

                    //初始化控件
                    try {
                        if (FuncBase.equals(enhanceJavaEntity.getJavaType(), EnhanceConstant.ENHANCE_TYPE_SPRING)) {//spring方式
                            String javaClassUrl = enhanceJavaEntity.getJavaClassUrl();//
                            Object bean = SpringUtils.getBean(javaClassUrl);
                            if (Func.isNotEmpty(bean) && bean instanceof BaseAdvicePlugin) {
                                PluginManager.addPlugin(javaClassUrl, (BaseAdvicePlugin) bean);
                            }
                        } else if (FuncBase.equals(enhanceJavaEntity.getJavaType(), EnhanceConstant.ENHANCE_TYPE_CLASS)) {//class方式
                            Class<?> enhanceClass = Class.forName(enhanceJavaEntity.getJavaClassUrl());
                            BaseAdvicePlugin plugin = (BaseAdvicePlugin) enhanceClass.newInstance();
                            PluginManager.addPlugin(enhanceJavaEntity.getJavaClassUrl(), plugin);
                        }
                    } catch (Exception e) {
                        log.error("初始化增强插件失败:{}", e);
                    }
                }

        );

        //初始化脚本
        for (EnhanceJavaEntity enhanceJavaEntity : allJavaEnhanceList) {
            try {
                String javaType = enhanceJavaEntity.getJavaType();
                if(!FuncBase.equals(javaType, EnhanceConstant.ENHANCE_TYPE_ONLINE_EDIT)){
                    continue;
                }
                String onlineScript = enhanceJavaEntity.getOnlineScript();
                if (Func.isEmpty(onlineScript)) {
                    continue;
                }
                groovyClassLoader.parseClass(onlineScript);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    //前置增强
    @Before("@annotation(lideeyunJiEnhance)")
    public void before(JoinPoint joinPoint, LideeyunJiEnhance lideeyunJiEnhance) throws Throwable {

        BuildEnhanceContext enhanceContext = this.getContextAndPlugins("start", lideeyunJiEnhance, joinPoint);//
        if (FuncBase.isEmpty(enhanceContext)) {
            return;
        }
        List<EnhanceJavaEntity> enhanceJavaEntityList = enhanceContext.getEntitys();
        if (Func.isEmpty(enhanceJavaEntityList)) {
            return;
        }
        EnhanceContext context = enhanceContext.getContext();
        //执行增强
        for (EnhanceJavaEntity enhanceJavaEntity : enhanceJavaEntityList) {
            String javaType = enhanceJavaEntity.getJavaType();
            JavaEnhanceEnums javaEnhanceEnums = JavaEnhanceEnums.getByJavaType(javaType);
            EnhanceJavaStrategy strategy = javaEnhanceEnums.getStrategy();
            strategy.execute(enhanceJavaEntity, context, JavaEnhanceEventState.START.getName(), joinPoint);
            if (context.getResult().isExitFlag()) {
                break;
            }
        }
    }

    @AfterReturning(pointcut = "@annotation(lideeyunJiEnhance)", returning = "returnVal")
    public Object afterReturning(JoinPoint joinPoint, Object returnVal, LideeyunJiEnhance lideeyunJiEnhance) throws Throwable {
        //获取参数
        BuildEnhanceContext enhanceContext = this.getContextAndPlugins("end", lideeyunJiEnhance, joinPoint);
        if (FuncBase.isEmpty(enhanceContext)) {
            return returnVal;
        }

        if (!(returnVal instanceof ResultDataModel) && !(returnVal instanceof ExecuteEnhanceModel)) {
            return returnVal;
        }

        List<EnhanceJavaEntity> enhanceJavaEntityList = enhanceContext.getEntitys();
        if (Func.isEmpty(enhanceJavaEntityList)) {//无增强
            return returnVal;
        }
        EnhanceContext context = enhanceContext.getContext();
        boolean resultFlag = false;
        //封装返回值
        if (returnVal instanceof ResultDataModel) {//列表相关
            ResultDataModel resultDataModel = (ResultDataModel) returnVal;
            EnhanceResult enhanceResult = new EnhanceResult();
            enhanceResult.setRecords(resultDataModel.getRecords());
            enhanceResult.setTotal(resultDataModel.getTotal());
            context.getParam().setList(resultDataModel.getRecords());
            context.setResult(enhanceResult);
            resultFlag = true;
        } else if (returnVal instanceof ExecuteEnhanceModel) {//新增，修改，删除
            ExecuteEnhanceModel executeEnhanceModel = (ExecuteEnhanceModel) returnVal;
            EnhanceResult enhanceResult = new EnhanceResult();
            enhanceResult.setId(executeEnhanceModel.getId());
            enhanceResult.setExitFlag(executeEnhanceModel.isExitFlag());
            context.setResult(enhanceResult);
        }

        //集合操作(后置增强)
        List<EnhanceJavaEntity> alferJavaEntityList = enhanceContext.getAlferJavaEntityList();

        CriteriaFilterAdvicePluginUtils.executeAfterJavaEnhance(context, alferJavaEntityList);
        //执行插件
        for (EnhanceJavaEntity enhanceJavaEntity : enhanceJavaEntityList) {
            //里面集合存在，不用执行
            if (Func.isNotEmpty(alferJavaEntityList) && alferJavaEntityList.contains(enhanceJavaEntity)) {
                continue;
            }
            String javaType = enhanceJavaEntity.getJavaType();
            JavaEnhanceEnums javaEnhanceEnums = JavaEnhanceEnums.getByJavaType(javaType);
            EnhanceJavaStrategy strategy = javaEnhanceEnums.getStrategy();
            strategy.execute(enhanceJavaEntity, context, JavaEnhanceEventState.END.getName(), joinPoint);
            if (context.getResult().isExitFlag()) {
                break;
            }
        }


        //返回结果
        Object result = super.getResult(joinPoint, context);
        if (resultFlag) {
            ResultDataModel returnValData = (ResultDataModel) returnVal;
            ResultDataModel resultDataModel = (ResultDataModel) result;
            returnValData.setRecords(resultDataModel.getRecords());
            returnValData.setTotal(resultDataModel.getTotal());
            return returnValData;
        } else {
            ExecuteEnhanceModel returnValData = (ExecuteEnhanceModel) returnVal;
            ExecuteEnhanceModel resultDataModel = (ExecuteEnhanceModel) result;
            returnValData.setId(resultDataModel.getId());
            return returnValData;
        }
    }

    @Around(value = "@annotation(lideeyunJiEnhance)")
    public Object aroudAdvice(ProceedingJoinPoint joinPoint, LideeyunJiEnhance lideeyunJiEnhance) throws Throwable {
        BuildEnhanceContext enhanceContext = this.getContextAndPlugins("around", lideeyunJiEnhance, joinPoint);
        if (FuncBase.isEmpty(enhanceContext)) {
            return joinPoint.proceed();
        }
        List<EnhanceJavaEntity> javaEntityList = enhanceContext.getEntitys();
        if (Func.isEmpty(javaEntityList)) {
            return joinPoint.proceed();
        }
        EnhanceContext context = enhanceContext.getContext();

        for (EnhanceJavaEntity enhanceJavaEntity : javaEntityList) {
            String javaType = enhanceJavaEntity.getJavaType();
            JavaEnhanceEnums javaEnhanceEnums = JavaEnhanceEnums.getByJavaType(javaType);
            EnhanceJavaStrategy strategy = javaEnhanceEnums.getStrategy();
            strategy.execute(enhanceJavaEntity, context, JavaEnhanceEventState.AROUND.getName(), joinPoint);

            if (context.getResult().isExitFlag()) {
                break;
            }
        }
        // 获取目标方法返回类型
        return super.getResult(joinPoint, context);
    }

    @AfterThrowing(pointcut = "@annotation(lideeyunJiEnhance)", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, LideeyunJiEnhance lideeyunJiEnhance, Exception ex) throws Throwable {
        BuildEnhanceContext enhanceContext = this.getContextAndPlugins("throwing", lideeyunJiEnhance, joinPoint);
        if (FuncBase.isEmpty(enhanceContext)) {
            return;
        }
        List<EnhanceJavaEntity> enhanceJavaEntityList = enhanceContext.getEntitys();
        if (Func.isEmpty(enhanceJavaEntityList)) {
            return;
        }
        EnhanceContext context = enhanceContext.getContext();
        for (EnhanceJavaEntity enhanceJavaEntity : enhanceJavaEntityList) {
            String javaType = enhanceJavaEntity.getJavaType();
            JavaEnhanceEnums javaEnhanceEnums = JavaEnhanceEnums.getByJavaType(javaType);
            EnhanceJavaStrategy strategy = javaEnhanceEnums.getStrategy();
            strategy.execute(enhanceJavaEntity, context, JavaEnhanceEventState.THROWING.getName(), joinPoint);
            if (context.getResult().isExitFlag()) {
                break;
            }
        }
    }



    /**
     * @param type      start end around throwing
     * @param joinPoint
     * @return
     */
    public BuildEnhanceContext getContextAndPlugins(String type, LideeyunJiEnhance lideeyunJiEnhance, JoinPoint joinPoint) {
        Map<String, Object> paramMap = super.getJoinPointParam(joinPoint);
        String buttonCode = lideeyunJiEnhance.buttonCode();
        //表单id
        Long dbFormId = (Long) paramMap.get("dbFormId");
        //判断该表单，当前的功能是否有增强
        String key = dbFormId + "_" + buttonCode;
        List<EnhanceJavaEntity> allJavaEntityList = javaEnhanceMaps.getOrDefault(key, null);
        if (Func.isEmpty(allJavaEntityList)) {//不存在增强
            return null;
        }
        List<EnhanceJavaEntity> javaList = this.getEnhanceJavaEntityList(type, allJavaEntityList);
        if (Func.isEmpty(javaList)) {
            return null;
        }


        //判断是否是列表，导出增强
        List<EnhanceJavaEntity> afterJavaEntityList = allJavaEntityList.stream()
                .filter(enhanceJavaEntity -> (FuncBase.equals(enhanceJavaEntity.getButtonCode(), ENHANCE_LIST) ||
                        FuncBase.equals(enhanceJavaEntity.getButtonCode(), ENHANCE_EXPORT)) && FuncBase.isNotEmpty(PluginManager.getPlugin(enhanceJavaEntity)))
                .collect(Collectors.toList());
        if (afterJavaEntityList.size() < 2) {
            //如果只有一条，则直接执行，不用走集合操作
            afterJavaEntityList.clear();
        }

        EnhanceParam param = super.getEnhanceParam(dbFormId, paramMap);

        //把参数放入到上下文
        EnhanceContext context = new EnhanceContext();
        context.setParam(param);

        BuildEnhanceContext buildEnhanceContext = new BuildEnhanceContext(context, javaList, afterJavaEntityList);
        return buildEnhanceContext;
    }

    //新增增强
    public static void addEnhance(EnhanceJavaEntity javaEntity) {
        String key = getPluginKey(javaEntity);
        // 1.处理 pluginNames
        javaEnhanceMaps.merge(key, new ArrayList<>(Collections.singletonList(javaEntity)), (oldValue, newValue) -> {
            oldValue.addAll(newValue);
            return oldValue;
        });
        addPlugins(javaEntity.getJavaType(), javaEntity.getJavaClassUrl());
    }

    //修改增强
    public static void updateEnhance(EnhanceJavaEntity javaEntity) {
        String key = getPluginKey(javaEntity);
        AtomicReference<String> oldJavaClassUrlAtomicRe = new AtomicReference<>();
        // 1.处理 pluginNames
        javaEnhanceMaps.merge(key, new ArrayList<>(Collections.singletonList(javaEntity)), (oldValue, newValue) -> {
            // 先删除再新增
            oldValue.removeIf(oldJavaEntity -> {
                if (FuncBase.equals(oldJavaEntity.getId(), javaEntity.getId())) {
                    oldJavaClassUrlAtomicRe.set(oldJavaEntity.getJavaClassUrl());
                    return true;
                } else {
                    return false;
                }
            });
            oldValue.add(javaEntity);
            return oldValue;
        });
        // 2.处理 plugins 先删除再新增
        removePlugins(oldJavaClassUrlAtomicRe.get());
        addPlugins(javaEntity.getJavaType(), javaEntity.getJavaClassUrl());
    }

    //删除增强
    public static void deleteEnhance(EnhanceJavaEntity javaEntity) {
        String key = getPluginKey(javaEntity);
        // 1.处理 pluginNames
        List<EnhanceJavaEntity> javaEntityList = javaEnhanceMaps.getOrDefault(key, new ArrayList<>());
        AtomicReference<String> oldJavaClassUrlAtomicRe = new AtomicReference<>();
        javaEntityList.removeIf(oldJavaEntity -> {
            if (oldJavaEntity.getId().equals(javaEntity.getId())) {
                oldJavaClassUrlAtomicRe.set(oldJavaEntity.getJavaClassUrl());
                return true;
            } else {
                return false;
            }
        });
        if (FuncBase.isEmpty(javaEntityList)) {
            javaEnhanceMaps.remove(key);
        }

        // 2.处理 plugins
        removePlugins(oldJavaClassUrlAtomicRe.get());
    }

    /**
     * 删除 plugins 中的增强
     */
    private static void removePlugins(String oldJavaClassUrl) {
        if (Func.isEmpty(oldJavaClassUrl)) {
            return;
        }
        Set<String> JavaClassUrlSet = javaEnhanceMaps.values().stream().flatMap(Collection::stream)
                .map(EnhanceJavaEntity::getJavaClassUrl).collect(Collectors.toSet());
        if (!JavaClassUrlSet.contains(oldJavaClassUrl)) {
            PluginManager.removePlugin(oldJavaClassUrl);
        }
    }

    //增加到控件
    private static void addPlugins(String javaType, String javaClassUrl) {
        try {
            // 2.处理 plugins
            if (Func.equals(javaType, JavaEnhanceEnum.SPRING.getType())) {
                Object bean = SpringUtils.getBean(javaClassUrl);
                if (Func.isNotEmpty(bean) && bean instanceof BaseAdvicePlugin) {
                    PluginManager.addPlugin(javaClassUrl, (BaseAdvicePlugin) bean);
                }
            } else if (Func.equals(javaType, JavaEnhanceEnum.CLASS.getType())) {
                Class<?> enhanceClass = Class.forName(javaClassUrl);
                BaseAdvicePlugin plugin = (BaseAdvicePlugin) enhanceClass.newInstance();
                PluginManager.addPlugin(javaClassUrl, plugin);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String getPluginKey(EnhanceJavaEntity javaEntity) {
        String key = javaEntity.getDbformId() + "_" + javaEntity.getButtonCode();
        return key;
    }

    //获取增强列表
    private List<EnhanceJavaEntity> getEnhanceJavaEntityList(String type,List<EnhanceJavaEntity> enhanceJavaEntityAllList){
        List<EnhanceJavaEntity> enhanceJavaEntityList=new ArrayList<>();
        for(EnhanceJavaEntity javaEntity:enhanceJavaEntityAllList){
            String javaClassUrl = javaEntity.getJavaClassUrl();//
            String javaType = javaEntity.getJavaType();
            BaseAdvicePlugin plugin = PluginManager.getPlugin(javaClassUrl);//只有class spring 方式
            switch (type) {
                case "start"://前置增强
                    if (!(plugin instanceof BeforeAdvicePlugin)) {
                        break;
                    }
                    enhanceJavaEntityList.add(javaEntity);
                    break;
                case "end"://后置增强
                    if (!(plugin instanceof AfterAdvicePlugin)) {
                        break;
                    }
                    enhanceJavaEntityList.add(javaEntity);
                    break;
                case "around":
                    //如果是在线编辑和http增强，只有环绕
                    if (FuncBase.equals(javaType, JavaEnhanceEnum.ONLINIE.getType())) {
                        //执行在线增强
                        enhanceJavaEntityList.add(javaEntity);
                        break;
                    } else if (FuncBase.equals(javaType, JavaEnhanceEnum.HTTP.getType())) {
                        //执行http增强
                        enhanceJavaEntityList.add(javaEntity);
                        break;
                    }
                    if (!(plugin instanceof AroundAdvicePlugin)) {
                        break;
                    }
                    enhanceJavaEntityList.add(javaEntity);
                    break;
                case "throwing":
                    enhanceJavaEntityList.add(javaEntity);
                    break;
                default:
                    break;
            }
        }
        return enhanceJavaEntityList;
    }

}
