package com.ruoyi.execution.produce.dispersed.service.impl;

import java.util.*;

import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.execution.produce.RunImplementationClass;
import com.ruoyi.execution.produce.dispersed.enetity.BpmExecuteNode;
import com.ruoyi.execution.produce.dispersed.enetity.BpmExecuteNodeMiddle;
import com.ruoyi.execution.produce.dispersed.enetity.BpmExecuteProcess;
import com.ruoyi.execution.produce.dispersed.mapper.BpmExecuteNodeMapper;
import com.ruoyi.execution.produce.dispersed.mapper.BpmExecuteNodeMiddleMapper;
import com.ruoyi.execution.produce.dispersed.mapper.BpmExecuteProcessMapper;
import com.ruoyi.execution.produce.dispersed.service.impl.utils.VerifyExecutionProcess;
import com.ruoyi.system.entity.*;
import com.ruoyi.system.entity.runbpm.BpmUserScriptVo;
import com.ruoyi.system.entity.runbpm.IntoProduction;
import com.ruoyi.system.mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.execution.produce.dispersed.service.IBpmExecuteProcessService;

/**
 * 流程执行任务Service业务层处理
 *
 * @author hzh
 * @date 2023-11-01
 */
@Service
public class BpmExecuteProcessServiceImpl implements IBpmExecuteProcessService {

    @Autowired // 执行流程
    private BpmExecuteProcessMapper runBpmExecuteProcessMapper;

    @Autowired  // 执行流程中间表
    private BpmExecuteNodeMiddleMapper runBpmExecuteNodeMiddleMapper;

    @Autowired  // 执行流程节点表
    private BpmExecuteNodeMapper runBpmExecuteNodeMapper;

    @Autowired  // 定义流程
    private BpmProcessMapper bpmProcessMapper;

    @Autowired  // 定义流程节点详细信息
    private BpmProcessConfigurationMapper bpmProcessConfigurationMapper;

    @Autowired  // 节点执行用户
    private BpmNodeHandleUserMapper bpmNodeHandleUserMapper;

    @Autowired  // 节点执行脚本
    private BpmNodeScriptRelevanceMapper bpmNodeScriptRelevanceMapper;

    @Autowired  // 真正执行脚本
    private RunImplementationClass iRunImplementationClass;

    @Autowired
    private VerifyExecutionProcess iVerifyExecutionProcess;
//    @Autowired  // 运行流程
//    private IRunBPM iRunBPM;

    /**
     * 查询流程执行任务
     *
     * @param id 流程执行任务主键
     * @return 流程执行任务
     */
    @Override
    public BpmExecuteProcess selectBpmExecuteProcessById(Long id) {
        return runBpmExecuteProcessMapper.selectBpmExecuteProcessById(id);
    }

    /**
     * 查询流程执行任务列表
     *
     * @param bpmExecuteProcess 流程执行任务
     * @return 流程执行任务
     */
    @Override
    public List<BpmExecuteProcess> selectBpmExecuteProcessList(BpmExecuteProcess bpmExecuteProcess) {
        return runBpmExecuteProcessMapper.selectBpmExecuteProcessList(bpmExecuteProcess);
    }

    /**
     * 新增流程执行任务
     *
     * @param bpmExecuteProcess 流程执行任务
     * @return 结果
     */
    @Override
    public int insertBpmExecuteProcess(BpmExecuteProcess bpmExecuteProcess) {
        return runBpmExecuteProcessMapper.insertBpmExecuteProcess(bpmExecuteProcess);
    }

    /**
     * 修改流程执行任务
     *
     * @param bpmExecuteProcess 流程执行任务
     * @return 结果
     */
    @Override
    public int updateBpmExecuteProcess(BpmExecuteProcess bpmExecuteProcess) {
        return runBpmExecuteProcessMapper.updateBpmExecuteProcess(bpmExecuteProcess);
    }

    /**
     * 批量删除流程执行任务
     *
     * @param ids 需要删除的流程执行任务主键
     * @return 结果
     */
    @Override
    public int deleteBpmExecuteProcessByIds(Long[] ids) {
        return runBpmExecuteProcessMapper.deleteBpmExecuteProcessByIds(ids);
    }

    /**
     * 删除流程执行任务信息
     *
     * @param id 流程执行任务主键
     * @return 结果
     */
    @Override
    public int deleteBpmExecuteProcessById(Long id) {
        return runBpmExecuteProcessMapper.deleteBpmExecuteProcessById(id);
    }

    /**
     * 共通投产流程接口
     *
     * @param intoProduction 预执行流程任务实体
     * @return
     */
    @Override
    public AjaxResult productionScheduling(IntoProduction intoProduction) {

        /**
         * 根据流程key校验当前流程数据的完整性，是否可以运行
         */

        if (!iVerifyExecutionProcess.VerifyProcessData(intoProduction.getTaskProcessKey()))
            return AjaxResult.error(String.valueOf(HttpStatus.EXECUTEPROCESS));

        // 得到流程key 和 投产数据条的id  （做关联查询）
        intoProduction.getTaskProcessKey();
        /**1️⃣ 得到当前投产需要执行的流程详细信息*/
        //--得到当前流程的详细信息
        BpmProcess bpmProcess = bpmProcessMapper.selectBpmProcessByProcessKey(intoProduction.getTaskProcessKey());

        //---根据流程key得到当前流程的所有节点信息
        List<BpmProcessConfiguration> bpmProcessConfigurationList = bpmProcessConfigurationMapper.selectBpmProcessConfigurationList(new BpmProcessConfiguration(intoProduction.getTaskProcessKey()));
        //----根据节点得到所有节点执行用户以及执行脚本的数据 ⬇⬇⬇⬇⬇⬇
        //---------------

        List<String> nodekeyList = new ArrayList<>(); // 当前流程所有节点
        // 根据节点表示得到所有脚本以及所有执行用户信息
        bpmProcessConfigurationList.forEach(item -> nodekeyList.add(item.getNodeKey()));

        // 当前流程的所有节点详细信息
        List<BpmUserScriptVo> bpmUserScriptVoList = new ArrayList<>();
        bpmProcessConfigurationList.forEach(item -> {
            BpmUserScriptVo bpmUserScriptVo = new BpmUserScriptVo();
            bpmUserScriptVo.setNodeKey(item.getNodeKey());
            bpmNodeHandleUserMapper.selectBpmNodeHandleUserList(new BpmNodeHandleUser(item.getNodeRolePermission()));
            bpmUserScriptVo.setBpmNodeScriptRelevanceList(bpmNodeScriptRelevanceMapper.selectBpmNodeScriptRelevanceList(new BpmNodeScriptRelevance(item.getNodeKey())));
            bpmUserScriptVoList.add(bpmUserScriptVo);
        });
        /**2️⃣2️⃣2️⃣ 新增执行流程表数据*/
        BpmExecuteProcess runBpmExecuteProcess = new BpmExecuteProcess();
        // 当前流程启动的唯一标识
        runBpmExecuteProcess.setTaskKey("");
        // 投产数据条的唯一标识
        runBpmExecuteProcess.setTaskPlanKey(intoProduction.getGuid());
        // 当前流程任务名称
        runBpmExecuteProcess.setTaskName("");
        // 定义表中的流程别名
        runBpmExecuteProcess.setTaskProcessKey(bpmProcess.getProcessKey());
        // 定义表中的流程xml标签内容
        runBpmExecuteProcess.setTaskProcessXmlContent(bpmProcess.getProcessXmlContent());
        // 启动流程的状态 默认：0 正常 1暂停 2弃用
        runBpmExecuteProcess.setTaskProcessState(0L);
        // 当前任务流程的版本注释
        runBpmExecuteProcess.setTaskProcessNote(bpmProcess.getNote());
        // 流程类型
        runBpmExecuteProcess.setTaskProcessType(intoProduction.getTaskProcessKey());
        // 执行新增方法
        runBpmExecuteProcessMapper.insertBpmExecuteProcess(runBpmExecuteProcess);
        /**3️⃣3️⃣3️⃣ 插入所有预执行节点*/
        List<BpmExecuteNode> runBpmExecuteNodeList = new ArrayList<>();
        bpmProcessConfigurationList.forEach(item -> {
            BpmExecuteNode bpmExecuteNode = new BpmExecuteNode();
            bpmExecuteNode.setTaskProcessKey(runBpmExecuteProcess.getTaskKey());
            bpmExecuteNode.setTaskNodeKey(item.getNodeKey());
            bpmExecuteNode.setTaskNodeName(item.getNodeName());
            bpmExecuteNode.setTaskNodeFormKey(item.getNodeFormKey());
            bpmExecuteNode.setTaskNodeType(item.getNodeType());
            bpmExecuteNode.setTaskNodeBefore(item.getNodeBefore());
            bpmExecuteNode.setTaskNodeAfter(item.getNodeAfter());
            bpmExecuteNode.setTaskNodeRolePermission(item.getNodeRolePermission());
            bpmExecuteNode.setTaskRemark(item.getRemark());
            bpmExecuteNode.setTaskNodeState("0");  // 状态默认未执行
            bpmExecuteNode.setTaskPriority("1");   // 任务优先级 设计是从排产操作时选中的任务优先级
            runBpmExecuteNodeList.add(bpmExecuteNode);
        });
        runBpmExecuteNodeMapper.insertBpmExecuteNodeList(runBpmExecuteNodeList);
        /**3️⃣3️⃣3️⃣ 执行流程任务所有关联数据执行用户，执行脚本等*/
        List<BpmExecuteNodeMiddle> runBpmExecuteNodeMiddleList = new ArrayList<>();

        int index = 0;
        // bpmUserScriptVoList  当前节点的所有执行用户脚本
        bpmUserScriptVoList.forEach(item -> {
            BpmExecuteNodeMiddle bpmExecuteNodeMiddle = new BpmExecuteNodeMiddle();
            // 节点标识
            bpmExecuteNodeMiddle.setTaskNodeKey(item.getNodeKey());
            // 节点执行角色编码
            bpmExecuteNodeMiddle.setTaskRealRole(item.getBpmNodeHandleUserList().get(index).getRealRole());
            // 节点执行用户id
            bpmExecuteNodeMiddle.setTaskExecuteUserNo(item.getBpmNodeHandleUserList().get(index).getExecuteUserNo());
            // 节点手动触发脚本
            List<String> script0 = new ArrayList<>(), script1 = new ArrayList<>();// 手动触发 // 自动触发

            item.getBpmNodeScriptRelevanceList().forEach(stem -> {
                if (stem.getNodeKey().contains(item.getNodeKey())) {
                    if (stem.getScriptTriggerType() == 0L) {  // 0L 标识手动触发 1L表示自动触发
                        script0.add(stem.getScriptKey());
                    } else {
                        script1.add(stem.getScriptKey());
                    }
                }
            });
            bpmExecuteNodeMiddle.setTaskArtificialScriptKey(script0.toString().replaceAll("\\[", "").replaceAll("\\]", ""));
            // 节点自动触发脚本
            bpmExecuteNodeMiddle.setTaskAutomaticScriptTriggerType(script1.toString().replaceAll("\\[", "").replaceAll("\\]", ""));
            runBpmExecuteNodeMiddleList.add(bpmExecuteNodeMiddle);
        });
        runBpmExecuteNodeMiddleMapper.insertBpmExecuteNodeMiddleList(runBpmExecuteNodeMiddleList);
        /**4️⃣4️⃣4️⃣ 调用执行节点接口 预执行当前投产流程的开始节点，执行开始节点*/
        // bpmUserScriptVoList  节点key对应的脚本
        // 根据节点类型startEvent 筛选得到当前流程的开始节点，进行自动执行    // startEvent  开始节点类型
        Optional<BpmProcessConfiguration> optionalStartNode = bpmProcessConfigurationList.stream().filter(item -> item.getNodeType().equals("startEvent")).findFirst();
        if (optionalStartNode.isPresent()) {
            // optionalStartNode.get().getNodeKey();  当前流程开始节点key
            Optional<BpmUserScriptVo> optionalBpmUserScriptVo = bpmUserScriptVoList.stream().filter(item -> item.getNodeKey().equals(optionalStartNode.get().getNodeKey())).findFirst();
            if (optionalBpmUserScriptVo.isPresent()) {
                // 得到当前节点需要执行的脚本  只需执行自动执行的脚本即可
                List<BpmNodeScriptRelevance> scriptAutoList = optionalBpmUserScriptVo.get().getBpmNodeScriptRelevanceList();
                scriptAutoList.removeIf(item -> item.getScriptTriggerType() == 0L);
                iRunImplementationClass.RunScriptImplementationClassLogicCode(scriptAutoList.get(0).getScriptKey(), intoProduction);
            }
        } else {
            // 数据出现问题
            return AjaxResult.error(String.valueOf(HttpStatus.EXECUTEPROCESS));
        }
        /**5️⃣5️⃣5️⃣ 执行结果返回前端*/
        return AjaxResult.success();
    }
}
