package com.yunzhupaas.flowable.job;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yunzhupaas.base.ActionResult;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.config.ConfigValueUtil;
import com.yunzhupaas.database.util.TenantDataSourceUtil;
import com.yunzhupaas.flowable.entity.OperatorEntity;
import com.yunzhupaas.flowable.entity.RecordEntity;
import com.yunzhupaas.flowable.entity.TaskEntity;
import com.yunzhupaas.flowable.enums.OperatorStateEnum;
import com.yunzhupaas.flowable.model.task.FlowModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.NodeModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.TemplateJsonModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.TimeConfig;
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.AuthUtil;
import com.yunzhupaas.util.RedisUtil;
import com.yunzhupaas.util.StringUtil;
import com.yunzhupaas.util.UserProvider;
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.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 类的描述
 *
 * @author YUNZHUPAASYUNZHUPAAS开发组
 * @version 5.0.x
 * @since 2024/12/10 9:17
 */
@Slf4j
public class AutoTransferJob extends QuartzJobBean {
    private static RedisUtil redisUtil;
    private static ConfigValueUtil configValueUtil;
    private static OperatorService operatorService;
    private static TaskUtil taskUtil;
    private static TaskService taskService;
    private static ServiceUtil serviceUtil;
    private static MsgUtil msgUtil;
    private static RedisLock redisLock;

    static {
        redisUtil = SpringContext.getBean(RedisUtil.class);
        configValueUtil = SpringContext.getBean(ConfigValueUtil.class);
        operatorService = SpringContext.getBean(OperatorService.class);
        taskUtil = SpringContext.getBean(TaskUtil.class);
        taskService = SpringContext.getBean(TaskService.class);
        serviceUtil = SpringContext.getBean(ServiceUtil.class);
        msgUtil = SpringContext.getBean(MsgUtil.class);
        redisLock = SpringContext.getBean(RedisLock.class);
    }

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        List<FlowTimeModel> list = FlowJobUtil.getTransfer(redisUtil);
        if (CollectionUtil.isNotEmpty(list)) {
            Set<String> nodeCodes = new TreeSet<>();
            for (FlowTimeModel timeModel : list) {
                FlowModel flowModel = timeModel.getFlowModel();

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

                String operatorId = timeModel.getOperatorId();

                boolean lock = redisLock.lock("transfer-" + operatorId, operatorId, 2, TimeUnit.SECONDS);
                if (!lock)
                    continue;

                String nodeCode = flowModel.getNodeCode();

                Map<String, Object> formData = flowModel.getFormData();
                Map<String, NodeModel> nodes = flowModel.getNodes();

                NodeModel nodeModel = nodes.get(nodeCode);
                TimeConfig config = nodeModel.getOverTimeConfig();

                if (ObjectUtil.equals(config.getOverTimeType(), 6) || ObjectUtil.equals(config.getOverTimeType(), 9)) {
                    if (nodeCodes.contains(flowModel.getNodeCode())) {
                        log.info("自动转审失败，该经办已处理（id：" + operatorId + "，code：" + nodeCode + "）");
                        FlowJobUtil.removeTransfer(timeModel, redisUtil);
                        continue;
                    }
                    nodeCodes.add(nodeCode);
                }
                OperatorEntity operator = operatorService.getById(operatorId);
                if (null == operator || operator.getHandleStatus() != null) {
                    TimeUtil.deleteJob(timeModel.getId());
                    FlowJobUtil.remove(timeModel, redisUtil);
                    continue;
                }
                if (ObjectUtil.equals(operator.getStatus(), OperatorStateEnum.Transfer.getCode())) {
                    log.info("转审状态的经办，不执行: " + operator.getId());
                    FlowJobUtil.removeTransfer(timeModel, redisUtil);
                    continue;
                }
                // 指派类型的转审，判断整个节点 是否存在转审类型的经办
                if (ObjectUtil.equals(config.getOverTimeType(), 6) || ObjectUtil.equals(config.getOverTimeType(), 9)) {
                    QueryWrapper<OperatorEntity> queryWrapper = new QueryWrapper<>();
                    queryWrapper.lambda().eq(OperatorEntity::getTaskId, operator.getTaskId())
                            .eq(OperatorEntity::getNodeId, operator.getNodeId())
                            .eq(OperatorEntity::getStatus, OperatorStateEnum.Transfer.getCode());
                    long count = operatorService.count(queryWrapper);
                    if (count > 0) {
                        log.info("节点存在转审状态的经办，不执行: " + operator.getId() + " " + operator.getNodeId());
                        FlowJobUtil.removeTransfer(timeModel, redisUtil);
                        continue;
                    }
                }

                String userId = operator.getHandleId();
                if (!ObjectUtil.equals(userInfo.getUserId(), userId)) {
                    String token = AuthUtil.loginTempUser(userId, userInfo.getTenantId());
                    userInfo = UserProvider.getUser(token);
                    UserProvider.setLoginUser(userInfo);
                    flowModel.setUserInfo(userInfo);
                }
                UserProvider.setLocalLoginUser(userInfo);

                try {
                    TaskEntity taskEntity = taskService.getById(operator.getTaskId());
                    if (null == taskEntity) {
                        taskEntity = flowModel.getTaskEntity();
                    }
                    String handleIds = null;
                    if (ObjectUtil.equals(config.getOverTimeType(), 6)) {
                        // 指定人员
                        // 349057407209541--user
                        if (CollectionUtil.isNotEmpty(config.getReApprovers())) {
                            String handleId = config.getReApprovers().get(0).split("--")[0];
                            UserEntity userEntity = serviceUtil.getUserInfo(handleId);
                            if (!ObjectUtil.equals(userId, handleId) && null != userEntity
                                    && ObjectUtil.equals(userEntity.getEnabledMark(), 1)) {
                                handleIds = handleId;
                            }
                        }
                        if (StringUtil.isNotEmpty(handleIds)) {
                            flowModel.setHandleIds(handleIds);
                            flowModel.setAutoTransferFlag(true);
                            taskService.assign(operator.getTaskId(), flowModel);
                            this.delete(timeModel);
                        }
                    } else if (ObjectUtil.equals(config.getOverTimeType(), 9)) {
                        // 接口
                        String interfaceId = config.getInterfaceId();
                        List<TemplateJsonModel> templateJson = config.getTemplateJson();
                        if (StringUtil.isNotEmpty(interfaceId)) {
                            RecordEntity record = new RecordEntity();
                            record.setTaskId(taskEntity.getId());
                            record.setNodeCode(operator.getNodeCode());
                            record.setHandleId(operator.getHandleId());

                            // UserEntity createUser =
                            // serviceUtil.getUserInfo(taskEntity.getCreatorUserId());
                            // UserEntity delegate = StringUtil.isNotEmpty(taskEntity.getDelegateUserId()) ?
                            // serviceUtil.getUserInfo(taskEntity.getDelegateUserId()) : null;

                            Map<String, String> parameterMap = msgUtil.parameterMap(formData, templateJson, record,
                                    taskEntity);
                            ActionResult result = serviceUtil.infoToId(interfaceId, parameterMap);
                            if (Objects.equals(200, result.getCode())) {
                                Object data = result.getData();
                                if (data instanceof Map) {
                                    JSONObject map = new JSONObject((Map) data);
                                    List<String> handleId = StringUtil.isNotEmpty(map.getString("handleId"))
                                            ? Arrays.asList(map.getString("handleId").split(","))
                                            : new ArrayList<>();
                                    handleId = serviceUtil.getUserName(handleId, true)
                                            .stream().map(UserEntity::getId).filter(e -> !ObjectUtil.equals(userId, e))
                                            .sorted().collect(Collectors.toList());
                                    handleIds = CollectionUtil.isNotEmpty(handleId) ? handleId.get(0) : null;
                                }
                            }
                            if (StringUtil.isNotEmpty(handleIds)) {
                                flowModel.setHandleIds(handleIds);
                                flowModel.setAutoTransferFlag(true);
                                taskService.assign(operator.getTaskId(), flowModel);
                                this.delete(timeModel);
                            }
                        }
                    } else {
                        // 超时审批人，2.同一部门 7.同一角色 3.同一岗位 8.同一分组
                        UserEntity userEntity = serviceUtil.getUserInfo(userId);
                        if (null != userEntity) {
                            Integer overTimeExtraRule = config.getOverTimeExtraRule();
                            List<String> userIds = new ArrayList<>();
                            taskUtil.getByRule(userIds, userEntity, overTimeExtraRule);
                            userIds = serviceUtil.getUserName(userIds, true)
                                    .stream().map(UserEntity::getId).filter(e -> !ObjectUtil.equals(userId, e)).sorted()
                                    .collect(Collectors.toList());
                            if (CollectionUtil.isNotEmpty(userIds)) {
                                handleIds = userIds.get(0);
                            }
                        }
                        if (StringUtil.isNotEmpty(handleIds)) {
                            flowModel.setHandleIds(handleIds);
                            operatorService.transfer(operatorId, flowModel);
                            this.delete(timeModel);
                        }
                    }

                } catch (Exception e) {
                    log.error("超时自动转审异常", e);
                    this.delete(timeModel);
                } finally {
                    FlowJobUtil.removeTransfer(timeModel, redisUtil);
                }
            }
        }
    }

    private void delete(FlowTimeModel timeModel) {
        TimeUtil.deleteJob(timeModel.getId());
        FlowJobUtil.remove(timeModel, redisUtil);
    }
}
