package com.testor.module.wf.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import com.testor.common.core.utils.StringUtils;
import com.testor.module.wf.dao.RuTaskDao;
import com.testor.module.wf.service.RuTaskService;
import com.testor.module.wf.utils.CastUtils;
import com.testor.module.wf.utils.ExpressionCmd;
import com.testor.module.wf.utils.VariableUtils;
import com.testor.module.wf.vo.ProcessDefListRequestVO;
import com.tongtech.tfw.backend.common.biz.constants.BizConstants;
import com.tongtech.tfw.backend.common.biz.models.BaseResponseList;
import com.tongtech.tfw.backend.core.helper.StringHelper;
import com.tongtech.tfw.backend.core.helper.bean.BeanHelper;
import com.tongtech.tfw.workflow.apis.definition.model.domain.ActReDeployment;
import com.tongtech.tfw.workflow.apis.definition.model.domain.ActReProcdef;
import com.tongtech.tfw.workflow.apis.definition.model.dto.ProcessDefListResponse;
import com.tongtech.tfw.workflow.apis.definition.service.ActReDeploymentService;
import com.tongtech.tfw.workflow.apis.definition.service.ActReProcdefService;
import com.tongtech.tfw.workflow.apis.task.model.dto.HisTask;
import com.tongtech.tfw.workflow.apis.task.model.dto.HisTaskListRequest;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.*;
import org.flowable.engine.*;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.User;
import org.flowable.task.api.Task;
import com.tongtech.tfw.workflow.apis.task.model.dto.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
public class RuTaskServiceImpl implements RuTaskService {

    @Autowired
    private RuTaskDao ruTaskMapper;
    @Autowired
    private ActReProcdefService actReProcdefService;

    @Autowired
    private ActReDeploymentService actReDeploymentService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private TaskService taskService;
    @Autowired
    private IdentityService identityService;

    @Override
    public HisTask getHisTask(HisTaskListRequest hisTaskListRequest) {
        HisTask hisTask = ruTaskMapper.getHisTask(hisTaskListRequest);
        //可能是查的子流程但传的流程id是主流程的
        if(null == hisTask){
            if(!StringUtils.isEmpty(hisTaskListRequest.getTaskId())){
                hisTask = ruTaskMapper.getTaskId(hisTaskListRequest.getTaskId());
            }
        }
        return hisTask;
    }

    /**
     * 获取流程定义列表
     * @param param 请求参数
     * @return 流程定义响应列表
     */
    @Override
    public BaseResponseList<ProcessDefListResponse> getProcessDefList(ProcessDefListRequestVO param) {
        // 页码和每页限制，默认值通过常量
        Long page = StringHelper.isEmpty(param.getPage()) ? BizConstants.PAGE : Long.valueOf(param.getPage());
        Long limit = StringHelper.isEmpty(param.getLimit()) ? BizConstants.LIMIT : Long.valueOf(param.getLimit());
        Page<ActReProcdef> resultPage = new Page<>(page, limit);
        QueryWrapper<ActReProcdef> queryWrapper = new QueryWrapper<>();

        if (StringHelper.isNotEmpty(param.getName())) {
            queryWrapper.like("NAME_", param.getName());
        }
        if (StringHelper.isNotEmpty(param.getKey())) {
            queryWrapper.like("KEY_", param.getKey());
        }
        if (StringHelper.isNotEmpty(param.getCategory())) {
            queryWrapper.eq("CATEGORY_", param.getCategory());
        }
        if (StringHelper.isNotEmpty(param.getTabType())) {
            //如果是待办
            if ("1".equals(param.getTabType())) {
                if (StringHelper.isNotBlank(param.getType())) {
                    if ("PC".equals(param.getType())) {
                        queryWrapper.ne("NAME_", "危险作业");
                    }
                }
            }
        }

        // 获取分页查询结果
        Page<ActReProcdef> actReProcdefIPage = actReProcdefService.page(resultPage, queryWrapper);

        // 获取查询结果列表
        List<ActReProcdef> queryList = actReProcdefIPage.getRecords();

        // 使用Map存储每个key对应的最大版本号流程定义
        Map<String, ActReProcdef> maxVersionProcessDefs = new HashMap<>();

        for (ActReProcdef actReProcdef : queryList) {
            String key = actReProcdef.getKey();
            Long version = actReProcdef.getVersion();
            // 如果当前key还未出现，或者发现了更大的版本号，更新该key对应的最大版本号流程定义
            if (!maxVersionProcessDefs.containsKey(key) || version > maxVersionProcessDefs.get(key).getVersion()) {
                maxVersionProcessDefs.put(key, actReProcdef);
            }
        }

        // 获取所有最大版本号的流程定义
        List<ActReProcdef> maxVersionList = new ArrayList<>(maxVersionProcessDefs.values());

        // 按name分组，并合并key
        Map<String, StringBuilder> nameKeyMap = new HashMap<>();

        for (ActReProcdef actReProcdef : maxVersionList) {
            String name = actReProcdef.getName();
            String key = actReProcdef.getKey();

            // 如果该name已经存在，则将key拼接到已有的StringBuilder中
            nameKeyMap.computeIfAbsent(name, k -> new StringBuilder()).append(key).append(",");
        }

        // 转换为目标格式，并设置合并后的key
        List<ProcessDefListResponse> resultList = nameKeyMap.entrySet().stream().map(entry -> {
            String name = entry.getKey();
            String keys = entry.getValue().toString();

            // 去掉最后一个逗号
            if (keys.endsWith(",")) {
                keys = keys.substring(0, keys.length() - 1);
            }

            // 获取其中一个最大版本号的流程定义，用于获取部署信息等
            ActReProcdef actReProcdef = maxVersionProcessDefs.values().stream()
                    .filter(p -> p.getName().equals(name))
                    .findFirst()
                    .orElse(null);

            // 创建响应对象
            ProcessDefListResponse processDefListResponse = BeanHelper.beanToBean(actReProcdef, ProcessDefListResponse.class);
            processDefListResponse.setName(name);
            processDefListResponse.setKey(keys); // 设置合并后的key

            if (actReProcdef != null && StringHelper.isNotEmpty(actReProcdef.getDeploymentId())) {
                ActReDeployment actReDeployment = actReDeploymentService.getById(actReProcdef.getDeploymentId());
                if (actReDeployment != null) {
                    processDefListResponse.setDeployTime(actReDeployment.getDeployTime());
                    processDefListResponse.setCategory(actReDeployment.getCategory());
                }
            }

            // 设置是否暂停
            processDefListResponse.setSuspended(actReProcdef != null && actReProcdef.getSuspensionState() != 1L);

            return processDefListResponse;
        }).collect(Collectors.toList());

        // 构建返回的响应对象
        BaseResponseList<ProcessDefListResponse> responseList = new BaseResponseList<>();
        responseList.setData(resultList);
        return responseList;
    }

    public List<Map> countToDo(String userId, String orgId) {
        return StrUtil.isBlank(userId) ? null : this.ruTaskMapper.countToDo(userId, orgId);
    }

    @Override
    public IPage<TodoTask> selectToDoList(IPage<TodoTask> page, TodoTaskSqlParam todoTaskSqlParam) {
        return this.ruTaskMapper.selectToDoList(page, todoTaskSqlParam);
    }

    @Override
    public IPage<HisTask> selectHisTaskList(IPage<HisTask> page, HisTaskSqlParam hisTaskSqlParam) {
        return this.ruTaskMapper.selectHisTaskList(page, hisTaskSqlParam);
    }

    @Override
    public boolean getElValue(String exp, Map<String, Object> variableMap) {
        return this.getElValue(null, exp, variableMap);
    }

    @Override
    public boolean getElValue(String processInstanceId, String exp, Map<String, Object> variableMap) {
        if (StringUtils.isBlank(exp)) {
            return true;
        }

        ManagementService managementService = processEngine.getManagementService();
        boolean flag = managementService.executeCommand(new ExpressionCmd(processEngine, processInstanceId, exp, variableMap));

        //删除垃圾数据
        this.deleteException();
        return flag;
    }

    public void deleteException(){
        //删除垃圾数据
        ruTaskMapper.deleteRuVariableException();
        ruTaskMapper.deleteHiVariableException();
    }




    @Override
    public List<String> getNextNameTasks(String taskId, Map<String, Object> variables) {
        List<String> nextFlowNodeNames = new ArrayList<>();
        try {
            if (StringUtils.isBlank(taskId)) {
                return new ArrayList<>();
            }
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            log.info("RuTaskServiceImpl-getNextNameTasks-当前任务task,参数：taskId={}，variables={},task={}" , taskId , variables, task.getName()+task.getId());
            if (null == task) {
                log.error("RuTaskServiceImpl-getNextNameTasks-当前任务不存在,参数：taskId={}，variables={}" , taskId , variables);
                return new ArrayList<>();
            }
            Map<String, Object> variableMap = taskService.getVariables(task.getId());
            variableMap.putAll(variables);
            List<FlowElement> nextFlowNodes = this.getNextFlowNodes(task, variableMap);
            log.info("RuTaskServiceImpl-getNextNameTasks-当前任务nextFlowNodes,参数：task={}，variableMap={},nextFlowNodes={}" ,
                    task.getName()+task.getId() , variableMap, JSON.toJSONString(nextFlowNodes));
            for (FlowElement nextFlowNode : nextFlowNodes) {
                nextFlowNodeNames.add(nextFlowNode.getName());
            }
        }catch (Exception e) {
            e.printStackTrace();
            log.error("RuTaskServiceImpl-getNextNameTasks-获取下一任务节点集合异常", e);
        }
        return nextFlowNodeNames;
    }


    /**
     * 获取下一任务节点集合
     *
     * @param task 当前任务
     * @param variables 参数
     * @return 下一任务节点集合
     */
    public List<FlowElement> getNextFlowNodes(Task task, Map<String, Object> variables) {
        if (null == task) {
            return new ArrayList<>();
        }

        // 当前审批节点
        String currentActivityId = task.getTaskDefinitionKey(); //当前环节id
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());

        //复制一份
        List<FlowElement> flowElements = new ArrayList<>(bpmnModel.getMainProcess().getFlowElements());
        List<FlowElement> nextElements = new ArrayList<>();

        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(currentActivityId);
        // 输出连线
        List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();

        FlowElement targetElement;
        List<SequenceFlow> sequenceFlows = this.getSequenceFlows(variables, outFlows);
        for (SequenceFlow sequenceFlow : sequenceFlows) {
            targetElement = this.getFlowElement(flowElements, sequenceFlow.getTargetRef());
            this.getNextElementList(nextElements, flowElements, targetElement, variables);
        }
        return nextElements;
    }



    public boolean getSkipElValue(String exp, Map<String, Object> variableMap) {
        //表达式为空，节点不跳过
        if (StringUtils.isBlank(exp)) {
            return false;
        }

        //skip：true 跳过节点/false 不跳过节点
        boolean skip = false;
        Map<String, Object> variables = new HashMap<>(variableMap);
        Object flowableSkipExpressionEnabled = variables.get("_FLOWABLE_SKIP_EXPRESSION_ENABLED");
        //流程参数含有_FLOWABLE_SKIP_EXPRESSION_ENABLED，且为true时，表示FLOWABLE跳过表达式已启用
        if (null != flowableSkipExpressionEnabled && "true".equals(flowableSkipExpressionEnabled.toString())) {
            //返回true，表示跳过该任务节点；
            ManagementService managementService = processEngine.getManagementService();
            skip = managementService.executeCommand(new ExpressionCmd(exp, variables));

            //删除垃圾数据
            this.deleteException();
        }

        return skip;
    }

    /**
     * 任务节点
     */
    private void dueUserTaskElement(List<FlowElement> nextElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap) {
        UserTask userTask = (UserTask) curFlowElement;
        //skip：true 跳过节点/false 不跳过节点
        boolean skip = this.getSkipElValue(userTask.getSkipExpression(), variableMap);
        if (!skip) {
            //不跳过节点，
            nextElements.add(curFlowElement);
        } else {

            //跳过节点，查询下一节点
            List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
            if (outgoingFlows.size() > 0) {
                String targetRef = outgoingFlows.get(0).getTargetRef();
                if (outgoingFlows.size() > 1) {
                    // 找到表达式成立的sequenceFlow
                    SequenceFlow sequenceFlow = getSequenceFlow(variableMap, outgoingFlows);
                    targetRef = sequenceFlow.getTargetRef();
                }
                // 根据ID找到FlowElement
                FlowElement targetElement = this.getFlowElement(flowElements, targetRef);
                this.getNextElementList(nextElements, flowElements, targetElement, variableMap);
            }
        }
    }

    /**
     * 排他网关
     */
    private void dueExclusiveGateway(List<FlowElement> nextElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap) {
        // 获取符合条件的sequenceFlow的目标FlowElement
        List<SequenceFlow> exclusiveGatewayOutgoingFlows = ((ExclusiveGateway) curFlowElement).getOutgoingFlows();
        flowElements.remove(curFlowElement);
        // 找到表达式成立的sequenceFlow
        SequenceFlow sequenceFlow = this.getSequenceFlow(variableMap, exclusiveGatewayOutgoingFlows);
        // 根据ID找到FlowElement
        FlowElement targetElement = this.getFlowElement(flowElements, sequenceFlow.getTargetRef());
        this.getNextElementList(nextElements, flowElements, targetElement, variableMap);
    }

    /**
     * 并行网关
     */
    private void dueParallelGateway(List<FlowElement> nextElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap) {
        FlowElement targetElement;
        List<SequenceFlow> parallelGatewayOutgoingFlows = ((ParallelGateway) curFlowElement).getOutgoingFlows();
        for (SequenceFlow sequenceFlow : parallelGatewayOutgoingFlows) {
            targetElement = this.getFlowElement(flowElements, sequenceFlow.getTargetRef());
            this.getNextElementList(nextElements, flowElements, targetElement, variableMap);
        }
    }

    /**
     * 包含网关
     */
    private void dueInclusiveGateway(List<FlowElement> nextElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap) {
        FlowElement targetElement;
        List<SequenceFlow> inclusiveGatewayOutgoingFlows = ((InclusiveGateway) curFlowElement).getOutgoingFlows();
        List<SequenceFlow> sequenceFlows = this.getSequenceFlows(variableMap, inclusiveGatewayOutgoingFlows);
        for (SequenceFlow sequenceFlow : sequenceFlows) {
            targetElement = this.getFlowElement(flowElements, sequenceFlow.getTargetRef());
            this.getNextElementList(nextElements, flowElements, targetElement, variableMap);
        }
    }

    /**
     * 获取下一环节任务节点集合
     */
    private void getNextElementList(List<FlowElement> nextElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap) {
        if (null == curFlowElement) {
            return;
        }

        // 任务节点
        if (curFlowElement instanceof UserTask) {
            this.dueUserTaskElement(nextElements, flowElements, curFlowElement, variableMap);
            return;
        }
        // 排他网关
        if (curFlowElement instanceof ExclusiveGateway) {
            this.dueExclusiveGateway(nextElements, flowElements, curFlowElement, variableMap);
            return;
        }
        // 并行网关
        if (curFlowElement instanceof ParallelGateway) {
            this.dueParallelGateway(nextElements, flowElements, curFlowElement, variableMap);
        }
        // 包含网关
        if (curFlowElement instanceof InclusiveGateway) {
            this.dueInclusiveGateway(nextElements, flowElements, curFlowElement, variableMap);
        }
        // 事件网关
        if (curFlowElement instanceof EventGateway) {
            this.dueEventGateway(nextElements, flowElements, curFlowElement, variableMap);
        }
    }

    /**
     * 事件网关
     */
    private void dueEventGateway(List<FlowElement> nextElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap) {
    }

    /**
     * 根据ID找到FlowElement
     * @param flowElements 流程节点集合
     * @param targetRef id
     * @return FlowElement
     */
    private FlowElement getFlowElement(Collection<FlowElement> flowElements, String targetRef) {
        return flowElements.stream().filter(flowElement -> targetRef.equals(flowElement.getId())).findFirst().orElse(null);
    }

    /**
     * 根据传入的变量，计算出表达式成立的那一条SequenceFlow
     *
     * @param variableMap   变量map
     * @param outgoingFlows 输出流
     * @return SequenceFlow连线
     */
    private SequenceFlow getSequenceFlow(Map<String, Object> variableMap, List<SequenceFlow> outgoingFlows) {
        List<SequenceFlow> sequenceFlows = this.getSequenceFlows(variableMap, outgoingFlows);
        if (null != sequenceFlows && sequenceFlows.size() > 0) {
            return sequenceFlows.get(0);
        }

        return outgoingFlows.get(0);
    }

    /**
     * 根据传入的变量，计算出表达式成立的SequenceFlow连线集合
     *
     * @param variableMap   变量map
     * @param outgoingFlows 输出流
     * @return SequenceFlow连线集合
     */
    private List<SequenceFlow> getSequenceFlows(Map<String, Object> variableMap, List<SequenceFlow> outgoingFlows) {
        List<SequenceFlow> sequenceFlows;
        sequenceFlows = outgoingFlows.stream().filter(item -> {
            try {
                return this.getElValue(item.getConditionExpression(), variableMap);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }).collect(Collectors.toList());
        return sequenceFlows;
    }

}
