package com.zkqy.execution.produce.dispersed.runbpm;

import com.zkqy.common.core.domain.AjaxResult;
import com.zkqy.execution.produce.dispersed.entity.runbpm.BpmRunNodeFromVo;
import com.zkqy.execution.produce.dispersed.entity.runbpm.IRunBPMEntity;
import com.zkqy.execution.produce.dispersed.entity.runbpm.IScriptEntity;
import com.zkqy.execution.produce.dispersed.service.IRunBPMService;
import com.zkqy.execution.produce.dispersed.service.IScriptService;
import com.zkqy.system.entity.CommonEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;


/**
 * 调用脚本逻辑执行类
 * * 执行所有脚本类
 * * 将IScriptService的实现类的Spring Bean的作用域设置为prototype，
 * * 这样每次调用applicationContext.getBean()时都会返回一个新的实例。
 * * 这样可以避免多线程环境下共享实例的问题
 * <p>
 * 节点逻辑代码根脚本不同的是 节点脚本是有表单数据的，单独的脚本是并没有表单数据的
 *
 * @author hanzihang
 * @date 2023/11/13
 */
@Component
public class RunImplementationClass<J> {

    @Autowired
    private ApplicationContext applicationContext;

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

    /**
     * @param iRunBPMEntity 节点执行参数
     * @return
     */
    @Transactional
    public AjaxResult RunBPMImplementationClassLogicCode(IRunBPMEntity iRunBPMEntity) {
        AjaxResult ajaxResult = new AjaxResult(); // 节点逻辑执行完成返回提示
        if (applicationContext.containsBean(iRunBPMEntity.getImplementationName())) {
            IRunBPMService iRunBPMService = (IRunBPMService) applicationContext.getBean(iRunBPMEntity.getImplementationName(), IRunBPMService.class);
            // 校验当前需要执行的脚本是否存在
            if (iRunBPMService.isVerificationMethod()) {
                // 脚本执行前验证
                AjaxResult preValidationAjaxResult = iRunBPMService.preValidation(iRunBPMEntity);
                if (preValidationAjaxResult.get("code").toString().equals("200")) {
                    iRunBPMService.executeNode(iRunBPMEntity);
                    // 节点后置验证
                    ajaxResult = iRunBPMService.afterValidation(iRunBPMEntity);
                } else {
                    // 执行清理操作
                    iRunBPMService.preDestroy();
                    return preValidationAjaxResult;
                }
                // 执行清理操作
                iRunBPMService.preDestroy();
            }
            log.info("Service execution successful：" + iRunBPMEntity.getImplementationName());
            return ajaxResult;
        } else {
            log.error("Service not found for name: " + iRunBPMEntity.getImplementationName());
            return AjaxResult.error("网络出现问题！请联系管理员！！！");
        }
    }


    /**
     * @param iScriptEntity 定位执行脚本所需参数
     * @param parameter     脚本实现逻辑其他参数
     * @return
     */
    @Transactional
    public boolean RunScriptImplementationClassLogicCode(IScriptEntity iScriptEntity, J parameter) {
        if (applicationContext.containsBean(iScriptEntity.getImplementationName())) {
            IScriptService iScriptService = (IScriptService) applicationContext.getBean(iScriptEntity.getImplementationName(), IScriptService.class);
            // 校验当前需要执行的脚本是否存在
            if (iScriptService.isVerificationMethod()) {
                // 脚本执行前验证
                if ((Boolean) iScriptService.preExecutionScript(parameter)) {
                    iScriptService.executionScript(parameter);
                    iScriptService.afterExecutionScript(parameter);
                }
                // 执行清理操作
                return iScriptService.preDestroy();
            }
            log.info("Service execution successful：" + iScriptEntity.getImplementationName());
            return true;
        } else {
            log.error("Service not found for name: " + iScriptEntity.getImplementationName());
            return false;
        }
    }

    /**
     * 获取当前节点的表单回显数据
     *
     * @param bpmRunNodeFromVo
     * @return
     */
    public CommonEntity getNodeFormData(BpmRunNodeFromVo bpmRunNodeFromVo) {
        // 首先检查容器当中是否存在当前JavaBean
        if (applicationContext.containsBean(bpmRunNodeFromVo.getTaskAutomaticScriptTriggerType())) {
            IRunBPMService iRunBPMService = applicationContext.getBean(bpmRunNodeFromVo.getTaskAutomaticScriptTriggerType(), IRunBPMService.class);
            // 二次验证节点bean是否存在，无需校验节点前验证是否通过
            if (iRunBPMService.isVerificationMethod()) {
                // 调用当前节点回显表单数据处理逻辑
                return iRunBPMService.getNodeFormData(bpmRunNodeFromVo);
            }
            return new CommonEntity();
        } else {
            return new CommonEntity();
        }
    }


    /**
     * 根据脚本名称校验脚本是否存在
     *
     * @param implementationName 脚本名称
     * @return
     */
    public boolean isVerificationMethod(String implementationName) {
        if (applicationContext.containsBean(implementationName)) {
            boolean state = false;
            try {
                // 尝试获取bean
                applicationContext.getBean(implementationName);
                state = true;
            } catch (NoSuchBeanDefinitionException e) {
                state = false;
            } finally {
                return state;
            }
        } else {
            return false;
        }
    }
}
