package com.yunzhupaas.flowable.job;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.config.ConfigValueUtil;
import com.yunzhupaas.database.util.TenantDataSourceUtil;
import com.yunzhupaas.exception.WorkFlowException;
import com.yunzhupaas.flowable.entity.OperatorEntity;
import com.yunzhupaas.flowable.entity.TaskEntity;
import com.yunzhupaas.flowable.model.task.FlowMethod;
import com.yunzhupaas.flowable.model.task.FlowModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.NodeModel;
import com.yunzhupaas.flowable.model.time.FlowTimeModel;
import com.yunzhupaas.flowable.service.OperatorService;
import com.yunzhupaas.flowable.service.TaskService;
import com.yunzhupaas.flowable.util.*;
import com.yunzhupaas.permission.entity.UserEntity;
import com.yunzhupaas.util.RedisUtil;
import com.yunzhupaas.util.context.SpringContext;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 类的描述
 *
 * @author YUNZHUPAASYUNZHUPAAS开发组
 * @version 5.0.x
 * @since 2024/5/23 17:42
 */
@Slf4j
public class AutoAuditJob extends QuartzJobBean {

    private static RedisUtil redisUtil;
    private static ConfigValueUtil configValueUtil;
    private static OperatorService operatorService;
    private static ConditionService conditionService;
    private static TaskUtil taskUtil;
    private static TaskService taskService;
    private static ServiceUtil serviceUtil;
    private static OperatorUtil operatorUtil;

    static {
        redisUtil = SpringContext.getBean(RedisUtil.class);
        configValueUtil = SpringContext.getBean(ConfigValueUtil.class);
        operatorService = SpringContext.getBean(OperatorService.class);
        conditionService = SpringContext.getBean(ConditionService.class);
        taskUtil = SpringContext.getBean(TaskUtil.class);
        taskService = SpringContext.getBean(TaskService.class);
        serviceUtil = SpringContext.getBean(ServiceUtil.class);
        operatorUtil = SpringContext.getBean(OperatorUtil.class);
    }

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        List<FlowTimeModel> list = FlowJobUtil.getOperator(redisUtil);
        if (CollectionUtil.isNotEmpty(list)) {
            for (FlowTimeModel timeModel : list) {
                FlowModel flowModel = timeModel.getFlowModel();
                Map<String, Object> formData = flowModel.getFormData();
                String deploymentId = flowModel.getDeploymentId();
                Map<String, NodeModel> nodes = flowModel.getNodes();

                UserInfo userInfo = flowModel.getUserInfo();
                if (configValueUtil.isMultiTenancy()) {
                    TenantDataSourceUtil.switchTenant(userInfo.getTenantId());
                }

                TaskEntity taskEntity = taskService.getById(timeModel.getTaskId());
                if (null == taskEntity) {
                    taskEntity = flowModel.getTaskEntity();
                }

                String operatorId = timeModel.getOperatorId();
                try {
                    OperatorEntity operator = operatorService.getInfo(operatorId);
                    if (null != operator) {
                        flowModel.setTaskEntity(taskEntity);
                        if (operator.getSignTime() == null) {
                            operator.setSignTime(new Date());
                        }
                        if (operator.getStartHandleTime() == null) {
                            operator.setStartHandleTime(new Date());
                        }
                        FlowMethod flowMethod = new FlowMethod();
                        flowMethod.setTaskEntity(taskEntity);
                        flowMethod.setFormData(formData == null ? new HashMap<>() : formData);
                        flowMethod.setDeploymentId(deploymentId);
                        flowMethod.setNodeCode(operator.getNodeCode());
                        flowMethod.setNodes(nodes);
                        // 判断节点的线的条件
                        Map<String, Boolean> resMap = conditionService.handleCondition(flowMethod);
                        try {
                            conditionService.checkCondition(resMap, nodes);
                        } catch (WorkFlowException e) {
                            continue;
                        }
                        List<NodeModel> nextApprover;
                        boolean mark = true;
                        try {
                            nextApprover = taskUtil.getNextApprover(flowMethod);
                        } catch (WorkFlowException e) {
                            nextApprover = null;
                            mark = false;
                        }
                        if (!mark) {
                            continue;
                        }
                        NodeModel nodeModel = nodes.get(operator.getNodeCode());
                        if (!taskUtil.checkBranch(nodeModel) && taskUtil.checkNextCandidates(nextApprover)
                                && taskUtil.checkNextError(flowModel, nextApprover, false, false) == 0) {
                            String handleId = operator.getHandleId();
                            String username = "";
                            UserEntity user = serviceUtil.getUserInfo(handleId);
                            if (user != null) {
                                username = user.getAccount() + "(" + user.getRealName() + ")";
                            }
                            String str = ObjectUtil.equals(operator.getIsProcessing(), 0) ? "自动审批通过" : "自动办理通过";
                            flowModel.setHandleOpinion(username + str);
                            UserEntity userEntity = serviceUtil.getUserInfo(operator.getHandleId());
                            if (null != userEntity) {
                                userInfo.setUserId(userEntity.getId());
                                userInfo.setUserName(userEntity.getRealName());
                                userInfo.setUserAccount(userEntity.getAccount());
                            }
                            operatorService.auditWithCheck(operator.getId(), flowModel);
                            operatorUtil.handleEvent();
                            List<OperatorEntity> operatorList = flowModel.getList();
                            if (CollectionUtil.isNotEmpty(operatorList)) {
                                TimeUtil.timeModel(operatorList, flowModel, redisUtil);
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("超时自动审批异常", e);
                    try {
                        operatorUtil.compensate(taskEntity);
                    } catch (Exception ex) {
                        log.error("超时自动审批补偿异常", ex);
                    }
                } finally {
                    // TimeUtil.deleteJob(timeModel.getId());
                    FlowJobUtil.remove(timeModel, redisUtil);
                }
            }
        }

    }
}
