package com.brilliance.isc.common.taskdistributor.service.impl;

import com.brilliance.isc.bo.*;
import com.brilliance.isc.common.api.bch.service.BchService;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.quemod.vo.QueClaStatus;
import com.brilliance.isc.common.quemod.vo.TaskFlowStatus;
import com.brilliance.isc.common.quemod.vo.TaskStatus;
import com.brilliance.isc.common.taskdistributor.comparator.GeneralUserComparator;
import com.brilliance.isc.common.taskdistributor.consts.TaskDistConstants;
import com.brilliance.isc.common.taskdistributor.enums.*;
import com.brilliance.isc.common.taskdistributor.exception.TaskDistException;
import com.brilliance.isc.common.taskdistributor.request.AssignTaskRequest;
import com.brilliance.isc.common.taskdistributor.response.TaskListResponse;
import com.brilliance.isc.common.taskdistributor.service.TaskDistService;
import com.brilliance.isc.common.taskdistributor.util.TaskPoolUtils;
import com.brilliance.isc.common.taskdistributor.util.TimeUtils;
import com.brilliance.isc.common.vo.BaseRequestPageVo;
import com.brilliance.isc.common.vo.PageVo;
import com.brilliance.isc.mda.dao.*;
import com.brilliance.isc.vo.manager.SessionUserVo;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import com.brilliance.mda.runtime.mda.util.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RPriorityQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TaskDistServiceImpl implements TaskDistService {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
//    @Qualifier("taskDistAsyncExecutor")
    private ThreadPoolTaskExecutor taskDistAsyncExecutor;

    @Autowired
    private BchService bchService;

    @Resource
    private QueMapper queMapper;

    @Resource
    private SptMapper sptMapper;

    @Resource
    private TrnMapper trnMapper;

    @Autowired
    private TskquelogMapper tskquelogMapper;

    @Resource
    private TaskDistConfigMapper taskDistConfigMapper;

    @Resource
    private TaskDistUserMapper taskDistUserMapper;

    @Resource
    private TaskPoolConfigMapper taskPoolConfigMapper;

    @Override
    public void handleTaskEnqueue(Que que) {
//        try {
//            queMapper.insert(que);
//        } catch (Exception e) {
//            log.error("任务入队失败", e);
//            throw new TaskDistException("任务入队失败");
//        }
        log.info("任务分配器：新任务进队通知，Que inr = {}", que.getInr());
        taskDistAsyncExecutor.execute(() -> taskEnqueueHandler(que));
    }

    @Override
    public void handleTaskEnqueue(String queinr) {
        Que que = queMapper.selectOneByInr(queinr);
        if (que == null) {
            return;
        }
        log.info("任务分配器：新任务进队通知，Que inr = {}", queinr);
        taskDistAsyncExecutor.execute(() -> taskEnqueueHandler(que));
    }

    // 任务入队事件处理
    private void taskEnqueueHandler(Que que) {
        log.info("进入taskEnqueueHandler");
        //任务hldflg为D时，记录为被删或锁定记录，不作分配
        if(Objects.equals(que.getHldflg(),"D")){
            log.warn("Que inr = {},记录为被删或锁定记录，不作分配", que.getInr());
            return ;
        }
        // 检查对应机构的配置
        TaskDistConfig config = taskDistConfigMapper.selectOneByBranchinr(que.getBchkeyinr());
       if (config == null) {
            log.warn("Que inr = {}, bchkeyinr = {} 未找到任务分配器总配置，无法处理", que.getInr(), que.getBchkeyinr());
            return;
        }
        TaskDistConstants.sortflg.remove();
        TaskDistConstants.sortflg.get().put(config.getBranchinr(),config);
        // 总开关打开，则纳入任务池管理
        if (!TaskDistConstants.SWITCH_ON.equals(config.getMasterSwitch())) {
            log.info("机构【{}】总开关关闭！",config.getBranchinr());
            return;
        }

        //来报自动分配开关关闭，则不纳入任务池管理，柜员自动获取
        if(QueClaStatus.INC.getValue().equals(que.getCla())){
            if(!TaskDistConstants.SWITCH_ON.equals(config.getMasterSwitch())){
                log.info("机构【{}】来报自动分配开关关闭", config.getBranchinr());
                return;
            }
        }
        //非收单行业务总行复核时，不入队
        if(Objects.equals(que.getFlowstatus(), TaskFlowStatus.HEADQUARTER_FIRST_RELEASE.getValue()) || Objects.equals(que.getFlowstatus(), TaskFlowStatus.HEADQUARTER_SECOND_RELEASE.getValue())){
            //非收单行业务总行复核时，不进行分配
            log.info("非收单行交易总行复核不分配，Que = {}", que);
            return;
        }
        log.info("准备加入redis，Que = {}", que);
        // 插入redis任务池，根据组别/池子配置细粒度分配，若未找到细化配置，则放入机构默认池子里
        matchPoolAndEnqueue(que);
        log.info("加入redis完成，Que = {}", que);

//        if(!isAutoDistTask(config,que)){
//           return ;
//        }
        log.info("开始触发自动分配，Que = {}", que);
//        fullAutoDistribute();
        //只分配此机构下的任务
        autoDistributeByBranch(que);
       }

    /**
     * 开关判断
     * @param que
     */
    public boolean isAutoDistTask(TaskDistConfig config,Que que){
        boolean isAutoDistTask = true;
        // 自动分配开关打开，则进行自动分配（异步）
        if (!TaskDistConstants.SWITCH_ON.equals(config.getAutoSwitch())) {
            log.info("自动分配开关关闭！");
            return false;
        }
        //报文分配开关
        if(QueClaStatus.INC.getValue().equals(que.getCla())){
            if(!TaskDistConstants.SWITCH_ON.equals(config.getMasterSwitch())){
                return false;
            }
        }
        //午休模式
        if(Objects.equals(TaskDistConstants.SWITCH_ON,config.getLunchModeSwitch())){
            if(TimeUtils.isModeTime(config.getLunchStartTime(),config.getLunchEndTime())){
                log.info("午休模式开关打开且当前处于午休时间！");
                return false;
            }
        }
        //工作模式
        if(Objects.equals(TaskDistConstants.SWITCH_ON,config.getWorkModeSwitch())){
            if(!TimeUtils.isModeTime(config.getOtherStartTime(),config.getOtherEndTime())){
                    log.info("工作模式已打开且当前不在工作时间！");
                    return false;
                }
//            if(Objects.equals(WorkRank.MORNING_SHIFT.getValue(),config.getWorkRank())){
//                if(!TimeUtils.isModeTime(config.getMorningStartTime(),config.getMorningEndTime())){
//                    log.info("工作模式已打开且当前不在工作时间！");
//                    return false;
//                }else if(TimeUtils.isNearToOffDutyTime(config) && config.getLongHoldingtimeFrm().contains(que.getFrm())){
//                    //临近下班时间且当前业务为占用时间较长业务时不进行分配
//                    log.info("当前处于临近下班时间且当前业务为占用时间较长业务，{}，不予分配",que.getFrm());
//                    return false;
//                }
//            }else if(Objects.equals(WorkRank.NIGHT_SHIFT.getValue(),config.getWorkRank())){
//                if(!TimeUtils.isModeTime(config.getNightStartTime(),config.getNightEndTime())){
//                    log.info("工作模式已打开且当前不在工作时间！");
//                    return false;
//                }else if(TimeUtils.isNearToOffDutyTime(config) && config.getLongHoldingtimeFrm().contains(que.getFrm())){
//                    //临近下班时间且当前业务为占用时间较长业务时不进行分配
//                    log.info("当前处于临近下班时间且当前业务为占用时间较长业务，{}，不予分配",que.getFrm());
//                    return false;
//                }
//            }else{
//                if(!TimeUtils.isModeTime(config.getOtherStartTime(),config.getOtherEndTime())){
//                    log.info("工作模式已打开且当前不在工作时间！");
//                    return false;
//                }else if(TimeUtils.isNearToOffDutyTime(config) && config.getLongHoldingtimeFrm().contains(que.getFrm())){
//                    //临近下班时间且当前业务为占用时间较长业务时不进行分配
//                    log.info("当前处于临近下班时间且当前业务为占用时间较长业务，{}，不予分配",que.getFrm());
//                    return false;
//                }
//            }
        }
        return isAutoDistTask;
    }

    @Override
    public void matchPoolAndEnqueue(Que que) {
        String poolName = matchTaskPoolName(que);
        RPriorityQueue<Que> queue = redissonClient.getPriorityQueue(poolName);
        if (!queue.isEmpty()) {
            for (Que q : queue) {
                if (Objects.equals(q.getInr(), que.getInr())) {
                    log.info("{} 池子中已有Que，跳过 {}", poolName, que);
                    return;
                }
            }
        }
        queue.offer(que);
        log.info("{} 池子加入任务Que = {}", poolName, que);
    }

    /**
     * 退回分配队列
     * @param task
     * @return
     */
    public void corToQueue(Que task){
        TaskDistConfig distConfig = taskDistConfigMapper.selectOneByBranchinr(task.getBchkeyinr());
        Optional<TaskPoolConfig> poolConfig = matchPool(task);
        String poolName = getTaskPoolName(poolConfig.get());
        if(Strings.isEmpty(poolName)){
          throw  new TaskDistException("未查询到此任务对应的任务池！");
        }
        //修改que表任务状态为new
        task.setStatus(TaskStatus.NEW.getValue());
        queMapper.updateByPrimaryKey(task);
        //将任务添加回队列
        RPriorityQueue<Que> queue = redissonClient.getPriorityQueue(poolName);
        matchPoolAndEnqueue(task);
//        queue.offer(task);
    }

    public void corToQueue(AssignTaskRequest request){
        request.getTaskIds().forEach(
                taskId ->{
                    log.info("正在将inr为【{}】的任务退回分配", taskId);
                    Que task = queMapper.selectOneByInr(taskId);
                    String usr = task.getUsr();
                    TaskDistConfig distConfig = taskDistConfigMapper.selectOneByBranchinr(task.getBchkeyinr());
                    Optional<TaskPoolConfig> poolConfig = matchPool(task);
                    String poolName = getTaskPoolName(poolConfig.get());
                    if(Strings.isEmpty(poolName)){
                        throw  new TaskDistException("未查询到此任务对应的任务池！");
                    }
                    //修改que表任务状态为new(只将已分配任务状态修改为new)，退回原因，并将柜员置空
                    if(Objects.equals(task.getStatus(),TaskStatus.ASSIGNED.getValue())){
                        task.setStatus(TaskStatus.NEW.getValue());
                    }
                    task.setRemark(request.getRemark());
                    task.setUsr("");
                    queMapper.updateByPrimaryKey(task);
                    //更新完que表记录后释放柜员阀值
                    commitTask(usr);
                    //将任务添加回队列
//                    RPriorityQueue<Que> queue = redissonClient.getPriorityQueue(poolName);
                    matchPoolAndEnqueue(task);


                }
        );

    }
    @Override
    public String getTaskPoolName(TaskPoolConfig pool) {
        StringBuilder sb = new StringBuilder(TaskDistConstants.TASK_POOL_PREFIX);
        sb.append(pool.getBranchinr())
                .append(":")
                .append(pool.getBizGroup())
                .append(":")
                .append(pool.getPoolNumber());
        return sb.toString();
    }

    @Override
    public String getUserPoolName(TaskPoolConfig pool) {
        StringBuilder sb = new StringBuilder(TaskDistConstants.USER_POOL_PREFIX);
        sb.append(pool.getBranchinr())
                .append(":")
                .append(pool.getBizGroup());
        return sb.toString();
    }

    @Override
    public String getUserPoolName(TaskDistUser user) {
        StringBuilder sb = new StringBuilder(TaskDistConstants.USER_POOL_PREFIX);
        sb.append(user.getBranchinr())
                .append(":")
                .append(user.getBizGroup());
        return sb.toString();
    }

    public String matchTaskPoolName(Que que) {
        if (StringUtils.isBlank(que.getBchkeyinr())) {
            log.error("Que信息不完整： {}", que);
            throw new TaskDistException("Que信息不完整");
        }
        List<TaskPoolConfig> taskPoolConfigs = taskPoolConfigMapper.selectAllByBranchinr(que.getBchkeyinr());
        StringBuilder sb = new StringBuilder(TaskDistConstants.TASK_POOL_PREFIX);
        sb.append(que.getBchkeyinr()).append(":");
        for (TaskPoolConfig pool : taskPoolConfigs) {
            if (pool.getTrades().contains(que.getFrm())) {
                sb.append(pool.getBizGroup())
                        .append(":")
                        .append(pool.getPoolNumber());
                return sb.toString();
            }
        }
        sb.append("default");
        log.warn("任务未找到匹配的任务池，匹配至默认队列：{}", que);
        log.debug("匹配的poolName = {}", sb.toString());
        return sb.toString();
    }

    @Override
    public Optional<TaskPoolConfig> matchPool(Que que) {
        List<TaskPoolConfig> taskPoolConfigs = taskPoolConfigMapper.selectAllByBranchinr(que.getBchkeyinr());
        for (TaskPoolConfig pool : taskPoolConfigs) {
            if (pool.getTrades().contains(que.getFrm())) {
                return Optional.of(pool);
            }
        }
        return Optional.empty();
    }

    // 柜员查询已分配给自己的任务（直接查数据库，因为不在redis里）（查询的其实就是待办列表）
    @Override
    public TaskListResponse queryTodoList(String extkey) {
        List<Que> tasks = queMapper.selectAllByUsrAndStatus(extkey, TaskStatus.ASSIGNED.getValue());
        return new TaskListResponse(tasks);
    }

    @Override
    public TaskListResponse queryTodoList() {
        SessionUserVo vo = SettleContext.getSessionUserVo();
        String logName = vo.getLogName();
        List<Que> tasks = queMapper.selectAllByUsrAndStatus(logName, TaskStatus.ASSIGNED.getValue());
        return new TaskListResponse(tasks);
    }

    // 柜员查询可分配给自己的任务（遍历任务池），当前只看是否为同一机构，后续再分组、查询权限（细粒度）
    @Override
    public PageVo<Que> queryAvailableTasks(BaseRequestPageVo page) {
        SessionUserVo vo = SettleContext.getSessionUserVo();
        String logName = vo.getLogName();
        String branchinr = bchService.getByBranch(vo.getOwnOrgDepartmentNumber()).getInr();

        // 查询当前机构下所有可领用的任务
        List<Que> availableTasks = queMapper.selectAvailableTasks(branchinr);

        // 查询机构配置，若分配器开关打开，则做权限过滤
        TaskDistConfig config = taskDistConfigMapper.selectOneByBranchinr(branchinr);
        if (Objects.equals(TaskDistConstants.SWITCH_ON, config.getMasterSwitch())) {
            TaskDistUser user = taskDistUserMapper.selectOneByExtkey(logName);
            String[] handlePermissions = user.getHandlePermission().split("-");
            Set<String> permissonSet = new HashSet<>(Arrays.asList(handlePermissions));
            List<TaskPoolConfig> pools = taskPoolConfigMapper.selectAllByBranchinr(branchinr);
            Set<String> tradeSet = pools.stream().filter(pool -> permissonSet.contains(pool.getPoolNumber()))
                    .map(pool -> pool.getTrades().split(","))
                    .flatMap(Arrays::stream)
                    .collect(Collectors.toSet());
            availableTasks = availableTasks.stream().filter(task -> tradeSet.contains(task.getFrm()))
                    .collect(Collectors.toList());
        }

        PageVo<Que> result = new PageVo<>();
        int pageNo = page.getPageNo();
        int pageSize = page.getPageSize();
        List<Que> records = availableTasks.stream().skip(pageSize * (pageNo - 1)).limit(pageSize).collect(Collectors.toList());
        result.setTotal(availableTasks.size());
        result.setPageNo(pageNo);
        result.setPageSize(pageSize);
        result.setRecords(records);
        return result;

    }

    /**
     * 将任务置顶
     * @param taskId
     * @return
     */
    @Override
    @Transactional
    public boolean pinTask(String taskId) {
        Date now = new Date();
        Que que = queMapper.selectOneByInr(taskId);
        Assert.notNull(que, "任务ID不存在");
        TaskDistConfig config = taskDistConfigMapper.selectOneByBranchinr(que.getBchkeyinr());
        Assert.notNull(config, "任务所属机构不存在任务分配器相关配置");
        if (Objects.equals(config.getMasterSwitch(), TaskDistConstants.SWITCH_ON)) {
            String poolName = matchTaskPoolName(que);
            RPriorityQueue<Que> taskQueue = redissonClient.getPriorityQueue(poolName);
            TaskPoolUtils.removeByInr(taskQueue, Que::getInr, taskId);
            // 设置最迟分配时间位当前时间，表示需要立即分配
            que.setPinflg(TaskDistConstants.FLAG_ON);
            que.setDistDdl(now);
            que.setUpdateTime(now);
            taskQueue.offer(que);
        }
        queMapper.updateByPrimaryKey(que);
        return true;
    }

    /**
     * 取消置顶
     * @param taskId
     * @return
     */
    @Override
    @Transactional
    public boolean unpinTask(String taskId) {
        Date now = new Date();
        Que que = queMapper.selectOneByInr(taskId);
        Assert.notNull(que, "任务ID不存在");
        TaskDistConfig config = taskDistConfigMapper.selectOneByBranchinr(que.getBchkeyinr());
        Assert.notNull(config, "任务所属机构不存在任务分配器相关配置");
        if (Objects.equals(config.getMasterSwitch(), TaskDistConstants.SWITCH_ON)) {
            String poolName = matchTaskPoolName(que);
            RPriorityQueue<Que> taskQueue = redissonClient.getPriorityQueue(poolName);
            TaskPoolUtils.removeByInr(taskQueue, Que::getInr, taskId);
            que.setPinflg(TaskDistConstants.FLAG_OFF);
            que.setUpdateTime(now);
            taskQueue.offer(que);
        }
        queMapper.updatePinflgAndUpdateTimeByInr(taskId, TaskDistConstants.FLAG_OFF, now);
        return true;
    }


    // 分配任务（将指定ID的任务手动分配给指定ID的柜员）

    @Override
    @Transactional
    public int manualAssignSingleTasks(AssignTaskRequest req) {
        // 判断任务分配器开关是否打开，若打开，还需同步更新redis池
        // 更新Que表，指派柜员
        Date now = new Date();
        TaskDistUser user = taskDistUserMapper.selectOneByExtkey(req.getExtkey());
        if(user == null){
            throw new TaskDistException("柜员配置不存在！");
        }
        TaskDistConfig taskDistConfig = taskDistConfigMapper.selectOneByBranchinr(user.getBranchinr());
        if(taskDistConfig == null){
            throw  new TaskDistException("机构配置不存在！");
        }
        TaskDistConstants.sortflg.remove();
        TaskDistConstants.sortflg.get().put(taskDistConfig.getBranchinr(),taskDistConfig);
        int manualLimit = taskDistConfig.getManualLimit();
        String taskId = req.getInr();

        Que task = queMapper.selectOneByInr(taskId);
        if(task == null){
            throw  new TaskDistException("业务信息不存在！");
        }
        //柜员任务数到达手工阀值，不予分配
        if(user.getAssignedTaskCount() >= manualLimit){
            log.info("柜员【{}】已达手工分配阀值，不予以分配",  user.getExtkey());
            task.setLastErr("柜员【"+ user.getExtkey() +"】已达手工分配阀值，不予以分配");
            saveAssignLog(task,TaskDistMethod.MANUAL.getValue());
            return -1;
        }
        if(Objects.equals(TaskStatus.WAITING.getValue(),task.getStatus())){
            if(Objects.equals(UserPosition.HANDLER.getValue(),user.getBizPosition())){
                log.info("经办柜员不能分配待复核业务！");
                task.setLastErr("经办柜员不能分配待复核业务！");
                saveAssignLog(task,TaskDistMethod.MANUAL.getValue());
                return -2;
            }
            if(Objects.equals(UserPosition.REVIEWE.getValue(),user.getBizPosition()) && Objects.equals(task.getFlowstatus(),TaskFlowStatus.HEADQUARTER_SDH_SECOND_RELEASE.getValue())){
                log.info("复核柜员不能分配待授权业务！");
                task.setLastErr("复核柜员不能分配待授权业务！");
                saveAssignLog(task,TaskDistMethod.MANUAL.getValue());
                return -3;
            }
        }
        String tskStatus = "";
        log.info("正在将inr为【{}】的任务手动分配给柜员【{}】", taskId, user.getExtkey());
        //手工分配只有状态为new的时候需要更新状态
        if(Objects.equals(TaskStatus.NEW.getValue(),task.getStatus())){
            tskStatus = TaskStatus.ASSIGNED.getValue();
        }else{
            tskStatus = task.getStatus();
        }
        queMapper.updateUsrAndStatusAndUpdateTimeByInr(taskId, req.getExtkey(), tskStatus, now,TaskDistMethod.MANUAL.getValue(), TaskDistStatus.OK.getValue());
        // 对应机构的任务分配器开关打开，才对redis进行操作
        if (Objects.equals(taskDistConfig.getMasterSwitch(), TaskDistConstants.SWITCH_ON)) {
            // 查表获取任务详细信息
            Que que = queMapper.selectOneByInr(taskId);
            String poolName = matchTaskPoolName(que);
            RPriorityQueue<Que> taskQueue = redissonClient.getPriorityQueue(poolName);
            TaskPoolUtils.removeByInr(taskQueue, Que::getInr, taskId);
            if(!Objects.equals(TaskStatus.NEW.getValue(),que.getStatus())){
                //已分配任务重新分配后，重新计算原分配柜员阀值
                commitTask(que.getUsr());
            }
        }
        //存入分配日志记录表
        saveAssignLog(queMapper.selectOneByInr(taskId),TaskDistMethod.MANUAL.getValue());
        // 更新Task_Dist_User表，占用阈值
        user.setAssignedTaskCount(calcOccupiedLimit(user.getExtkey()));
        taskDistUserMapper.updateAssignedTaskCountByExtkey(user.getExtkey(), user.getAssignedTaskCount());
        if (Objects.equals(taskDistConfig.getMasterSwitch(), TaskDistConstants.SWITCH_ON)) {
            RPriorityQueue<TaskDistUser> userQueue = redissonClient
                    .getPriorityQueue(getUserPoolName(user));
            TaskPoolUtils.removeByInr(userQueue, TaskDistUser::getExtkey, user.getExtkey());
            userQueue.add(user);
        }
        return 1;
    }
    // 分配任务（将指定个数的任务手动分配给指定ID的柜员）
    @Override
    @Transactional
    public Map<String,Integer> manualAssignTasks(AssignTaskRequest req) {
        // 判断任务分配器开关是否打开，若打开，还需同步更新redis池
        // 更新Que表，指派柜员
//        Date now = new Date();
//        TaskDistUser user = taskDistUserMapper.selectOneByExtkey(req.getExtkey());
//        TaskDistConfig taskDistConfig = taskDistConfigMapper.selectOneByBranchinr(user.getBranchinr());
        AtomicInteger successCount = new AtomicInteger();
        AtomicInteger failedCount = new AtomicInteger();
        AssignTaskRequest request = new AssignTaskRequest();
        req.getTaskIds().forEach(taskId -> {
            request.setInr(taskId);
            request.setExtkey(req.getExtkey());
            int distStatus = this.manualAssignSingleTasks(request);
            if(distStatus == 1){
                successCount.getAndIncrement();
            }else{
                failedCount.getAndIncrement();
            }
//            Que task = queMapper.selectOneByInr(taskId);
//            String tskStatus = "";
//            log.info("正在将inr为【{}】的任务手动分配给柜员【{}】", taskId, user.getExtkey());
//            //手工分配只有状态为new的时候需要更新状态
//            if(Objects.equals(TaskStatus.NEW.getValue(),task.getStatus())){
//                tskStatus = TaskStatus.ASSIGNED.getValue();
//            }else{
//                tskStatus = task.getStatus();
//            }
//            queMapper.updateUsrAndStatusAndUpdateTimeByInr(taskId, req.getExtkey(), tskStatus, now,TaskDistMethod.MANUAL.getValue(), TaskDistStatus.OK.getValue());
//            // 对应机构的任务分配器开关打开，才对redis进行操作
//            if (Objects.equals(taskDistConfig.getMasterSwitch(), TaskDistConstants.SWITCH_ON)) {
//                // 查表获取任务详细信息
//                Que que = queMapper.selectOneByInr(taskId);
//                String poolName = matchTaskPoolName(que);
//                RPriorityQueue<Que> taskQueue = redissonClient.getPriorityQueue(poolName);
//                TaskPoolUtils.removeByInr(taskQueue, Que::getInr, taskId);
//                if(!Objects.equals(TaskStatus.NEW.getValue(),que.getStatus())){
//                    //已分配任务重新分配后，重新计算原分配柜员阀值
//                    commitTask(que.getUsr());
//                }
//            }
//            //存入分配日志记录表
//            saveAssignLog(queMapper.selectOneByInr(taskId),TaskDistMethod.MANUAL.getValue());
        });
//        int count = req.getTaskIds().size();
        // 更新Task_Dist_User表，占用阈值
//        user.setAssignedTaskCount(calcOccupiedLimit(user.getExtkey()));
//        taskDistUserMapper.updateAssignedTaskCountByExtkey(user.getExtkey(), user.getAssignedTaskCount());
//        if (Objects.equals(taskDistConfig.getMasterSwitch(), TaskDistConstants.SWITCH_ON)) {
//            RPriorityQueue<TaskDistUser> userQueue = redissonClient
//                    .getPriorityQueue(getUserPoolName(user));
//            TaskPoolUtils.removeByInr(userQueue, TaskDistUser::getExtkey, user.getExtkey());
//            userQueue.add(user);
//        }
        // 返回成功分配条数
        Map<String, Integer> rtnMsg = new HashedMap();
        rtnMsg.put("successCount",successCount.get());
        rtnMsg.put("failedCount",failedCount.get());
        return rtnMsg;
    }

    // 分配任务（将指定个数的任务自动分配给指定ID的柜员）

    // 分配任务（将指定个数的任务自动分配下去）

    // 分配任务（全自动）

    /**
     * 自动分配任务：
     * 1.获取全量状态为new的任务
     * 2.遍历所有任务池，进行自动分配
     */
    @Override
    public void fullAutoDistribute() {
        // 查询任务分配器配置表
        List<TaskDistConfig> taskDistConfigs = taskDistConfigMapper.selectAll();
        if (CollectionUtils.isEmpty(taskDistConfigs)) {
            return;
        }
        taskDistConfigs.forEach(config -> {
            log.info("准备自动分配机构ID为{}的任务", config.getBranchinr());
            taskDistAsyncExecutor.execute(() -> autoDistributeByBranch(config));
        });
    }

    /**
     * 根据机构号进行分配
     * @param config
     */
    public void autoDistributeByBranch(TaskDistConfig config) {
        log.info("进入autoDistributeByBranch方法，config = {}", config);
        boolean masterSwitchOn = TaskDistConstants.SWITCH_ON.equals(config.getMasterSwitch());
        boolean autoSwitchOn = TaskDistConstants.SWITCH_ON.equals(config.getAutoSwitch());
        // 两个开关均打开时，才进行自动分配
        if (!masterSwitchOn || !autoSwitchOn) {
            return;
        }
        log.info("开始自动分配机构ID为{}的任务", config.getBranchinr());
        Integer autoLimit = config.getAutoLimit();
        // 获取机构下所有任务池
        List<TaskPoolConfig> pools = taskPoolConfigMapper.selectAllByBranchinr(config.getBranchinr());
        if (CollectionUtils.isEmpty(pools)) {
            return;
        }
        pools.forEach(taskPool -> {
            log.info("准备自动分配任务池为{}的任务", taskPool.getPoolName());
            taskDistAsyncExecutor.execute(() -> distributeByPool(config,taskPool,autoLimit));
        });

    }

    /**
     * 根据任务进行分配
     * @param que
     */
    public void autoDistributeByBranch(Que que) {
        TaskDistConfig config = taskDistConfigMapper.selectOneByBranchinr(que.getBchkeyinr());
        if(Objects.isNull(config)){
            log.info("业务所属经办机构未配置！");
            return;
        }
        log.info("进入autoDistributeByBranch方法，config = {}", config);
        boolean masterSwitchOn = TaskDistConstants.SWITCH_ON.equals(config.getMasterSwitch());
        boolean autoSwitchOn = TaskDistConstants.SWITCH_ON.equals(config.getAutoSwitch());
        // 两个开关均打开时，才进行自动分配
        if (!masterSwitchOn || !autoSwitchOn) {
            return;
        }
        log.info("开始自动分配机构ID为{}的任务", config.getBranchinr());
        Integer autoLimit = config.getAutoLimit();
        // 获取机构下所有任务池
        List<TaskPoolConfig> pools = taskPoolConfigMapper.selectAllByBranchinr(config.getBranchinr());
        if (CollectionUtils.isEmpty(pools)) {
            return;
        }
        pools.forEach(taskPool -> {
            if(taskPool.getTrades().contains(que.getFrm())) {
                log.info("准备自动分配任务池为{}的任务", taskPool.getPoolName());
                distributeByPool(config, taskPool, autoLimit);
            }
        });

    }

    /**
     * 根据任务池进行分配
     * @param taskPool
     * @param autoLimit
     */
    public void distributeByPool(TaskDistConfig taskDistConfig,TaskPoolConfig taskPool,Integer autoLimit){
        TaskDistConstants.sortflg.remove();
        TaskDistConstants.sortflg.get().put(taskDistConfig.getBranchinr(),taskDistConfig);
        if (!TaskDistConstants.SWITCH_ON.equals(taskPool.getAutoSwitch())) {
            return;
        }
        // 根据配置拿到任务池
        RPriorityQueue<Que> taskQueue = redissonClient.getPriorityQueue(getTaskPoolName(taskPool));
        // 对每个任务池，找到对应的柜员池
        RPriorityQueue<TaskDistUser> userQueue = redissonClient.getPriorityQueue(getUserPoolName(taskPool));
        if (taskQueue.isEmpty() || userQueue.isEmpty()) {
            // 当前任务池无任务或无柜员可供分配，则跳过
            return;
        }
        //溢出模式
        RPriorityQueue<TaskDistUser> userQueueOverFlow;
        boolean isOverFlow = false;
        if(!Objects.equals(OverFlowMode.OFF.getValue(),taskDistConfig.getOverflowMode())){
            if(taskQueue.size() > taskPool.getOverflowLimit()){
                //溢出模式开关打开且该队列内任务数大于设定溢出阀值数则触发溢出模式
                taskDistConfig.setGrp(taskPool.getBizGroup());
                TaskDistConstants.sortflg.get().put(taskDistConfig.getBranchinr(),taskDistConfig);
                String userPoolName = TaskDistConstants.USER_POOL_PREFIX + taskPool.getBranchinr() + ":OverFlowGroup";
                userQueueOverFlow = redissonClient.getPriorityQueue(userPoolName);
                TaskDistUser distUser =  new TaskDistUser();
                distUser.setBranchinr(taskPool.getBranchinr());
                distUser.setParticipateFlag(TaskDistConstants.FLAG_ON);
                distUser.setStatus(UserStatus.ON_DUTY.getValue());
                List<TaskDistUser> users = taskDistUserMapper.selectConditionList(distUser);
                if(!userQueueOverFlow.isEmpty()){
                    userQueueOverFlow.clear();
                }
                userQueueOverFlow.trySetComparator(new GeneralUserComparator());
                //重新排序
                users.forEach(user -> TaskPoolUtils.putIfAbsent(userQueueOverFlow, user, TaskDistUser::getExtkey));
                isOverFlow = true;
            } else {
                userQueueOverFlow = null;
            }

        } else {
            userQueueOverFlow = null;
        }
        // 用于暂存未能成功分配的任务
        List<Que> tmpList = new ArrayList<>();
        while (!taskQueue.isEmpty()) {
            Que task = taskQueue.poll();
            if(!isAutoDistTask(taskDistConfig,task)){
                //不分配的任务重新回到队列
                tmpList.add(task);
                continue;
            }
            String cla = task.getCla();
            boolean success = false;
            //自动分配
            if (Objects.equals(QueClaStatus.RIM.getValue(), cla)) {
                if(isOverFlow){
                    success = autoDistributeOverFlowRimTask(taskDistConfig, task, taskPool, autoLimit, userQueueOverFlow);
                }else {
                    success = autoDistributeRimTask(taskDistConfig, task, taskPool, autoLimit, userQueue);
                }
            }else if(Objects.equals(QueClaStatus.REL.getValue(), cla)){
                success =  autoDistributeWaitingTask(task, taskPool, autoLimit, userQueue,taskDistConfig);
            }else if(Objects.equals(QueClaStatus.COR.getValue(), cla)){
                success = autoDistributeCorrectTask(task,taskPool, autoLimit, userQueue);
            }else if(Objects.equals(QueClaStatus.INC.getValue(), cla)){
                success =  autoDistributeIncomingTask(taskDistConfig,task, taskPool, autoLimit, userQueue);
            }
            if (!success) {
                tmpList.add(task);
            }
        }
        taskQueue.addAll(tmpList);
    }

    /**
     * 1.退回业务分配给原经办柜员
     * 2.若原经办签退，则再自动分配给其它柜员
     * @param task
     * @param poolConfig
     * @param autoLimit
     * @param userQueue
     * @return
     */
    private boolean autoDistributeCorrectTask(Que task, TaskPoolConfig poolConfig, Integer autoLimit, RPriorityQueue<TaskDistUser> userQueue) {
        Integer tryDistCount = Optional.ofNullable(task.getTryDistCount()).orElse(0);
        task.setTryDistCount(tryDistCount + 1);
        // 拿到原经办柜员
        String usrcon = task.getUsrcon();
        if (StringUtils.isBlank(usrcon)) {
            // 分配异常
            task.setDistMethod(TaskDistMethod.AUTO.getValue());
            task.setDistStatus(TaskDistStatus.ERR.getValue());
            task.setLastErr("退回任务找不到原经办柜员，无法分配");
            task.setUpdateTime(new Date());
            queMapper.updateByPrimaryKey(task);
            //存入分配日志记录表
            saveAssignLog(task,TaskDistMethod.AUTO.getValue());
            return false;
        }else{
          TaskDistUser taskDistUser = taskDistUserMapper.selectOneByExtkey(usrcon);
          //在柜员池中不存在，则不参与分配（未配置、不参与分配或已经签退）
          if(!TaskPoolUtils.exists(userQueue, taskDistUser, TaskDistUser::getExtkey)){
              //退回时，原经办若已签退，则再进行自动分配
              for (TaskDistUser user : userQueue) {
                  // TODO 一堆判断条件，用于找到合适的柜员，此处直接取有权限且阈值未满的，后续再加条件
                  if (user.getAssignedTaskCount() < autoLimit) {
                      if (user.getHandlePermission().contains(poolConfig.getPoolNumber())) {
                          usrcon = user.getExtkey();
                          break;
                      }
                  }
              }
          }
        }
        task.setUsr(usrcon);
        task.setDistMethod(TaskDistMethod.AUTO.getValue());
        task.setDistStatus(TaskDistStatus.OK.getValue());
        task.setUpdateTime(new Date());
        queMapper.updateByPrimaryKey(task);
        // 由于是忽略其他条件的直接分配，所以需要找到对应的柜员及柜员池
        //存入分配日志记录表
        saveAssignLog(task,TaskDistMethod.AUTO.getValue());
        TaskDistUser user = taskDistUserMapper.selectOneByExtkey(usrcon);
        user.setAssignedTaskCount(calcOccupiedLimit(user.getExtkey()));
        taskDistUserMapper.updateAssignedTaskCountByExtkey(user.getExtkey(), user.getAssignedTaskCount());
       // 看一下该柜员在不在池子中，在的话就做一下同步更新
        if (TaskPoolUtils.exists(userQueue, user, TaskDistUser::getExtkey)) {
            TaskPoolUtils.removeByInr(userQueue, TaskDistUser::getExtkey, user.getExtkey());
            // 柜员手头任务数+1，更新数据库，然后重新入队
            userQueue.offer(user);
        }

        return true;
    }



    /**
     * 待复核任务分配：非收单行需要总行复核的业务不进行分配
     * 1.复核任务原经办柜员不能为空
     * 2.原经办柜员需要在柜员配置里面存在
     * 3.查找此笔业务是否有退回记录，有：则将此笔分配给原复核，无：则将业务分配给固定业务组和复核
     * 4.此复核柜员若已经签退，则按照规则进行自动分配
     * 5.此复核柜员需要在柜员配置里面存在
     * @param task
     * @return
     */
    private boolean autoDistributeWaitingTask(Que task, TaskPoolConfig poolConfig, Integer autoLimit, RPriorityQueue<TaskDistUser> userQueue,TaskDistConfig distConfig) {
        if(Objects.equals(task.getFlowstatus(), TaskFlowStatus.HEADQUARTER_FIRST_RELEASE.getValue()) || Objects.equals(task.getFlowstatus(), TaskFlowStatus.HEADQUARTER_SECOND_RELEASE.getValue())){
           //非收单行业务总行复核时，不进行分配
            return false;
        }
        Integer tryDistCount = Optional.ofNullable(task.getTryDistCount()).orElse(0);
        task.setTryDistCount(tryDistCount + 1);
        //优先判断是否有退回记录，分配给退回记录中的复核
        //存在退回记录，则把该笔业务分配给原退回复核柜员
        //获取最新一条被退回的复核记录的复核人员
         Que queCor = getWaitingCorQue(task);
         String reviewerExtkey = "";
        // 拿到原经办柜员,需要从原经办柜员配置中获取指定复核柜员
        String usrcon = task.getUsrcon();
         if(queCor != null){
             reviewerExtkey  = queCor.getUsr();
         }else{
             if (StringUtils.isBlank(usrcon)) {
                 // 分配异常
                 task.setDistMethod(TaskDistMethod.AUTO.getValue());
                 task.setDistStatus(TaskDistStatus.ERR.getValue());
                 task.setLastErr("待复核任务无原经办柜员信息，无法分配");
                 task.setUpdateTime(new Date());
                 queMapper.updateByPrimaryKey(task);
                 //存入分配日志记录表
                 saveAssignLog(task,TaskDistMethod.AUTO.getValue());
                 return false;
             }
             TaskDistUser user = taskDistUserMapper.selectOneByExtkey(usrcon);
             if (user == null) {
                 // 分配异常
                 log.warn("待复核任务 {} 的原经办柜员没有进行柜员配置", task.getInr());
                 task.setDistMethod(TaskDistMethod.AUTO.getValue());
                 task.setDistStatus(TaskDistStatus.ERR.getValue());
                 task.setLastErr("待复核任务的原经办柜员没有进行柜员配置，无法分配");
                 task.setUpdateTime(new Date());
                 queMapper.updateByPrimaryKey(task);
                 //存入分配日志记录表
                 saveAssignLog(task,TaskDistMethod.AUTO.getValue());
                 return false;
             }
            //根据经办柜员配置的指定复核柜员进行分配
            reviewerExtkey = user.getDesignatedReviewer();
         }
         if(reviewerExtkey != null && reviewerExtkey != ""){
             if(!isOnDuty(userQueue,reviewerExtkey)){
                 //判断如果分配的柜员已经签退，则重新分配
                 for (TaskDistUser distUser : userQueue) {
                     // TODO 一堆判断条件，用于找到合适的柜员，此处直接取有权限且阈值未满的复核人员，后续再加条件
                     if (distUser.getAssignedTaskCount() < autoLimit) {
                         //重新分配的柜员需有复核权限
                         if(Objects.equals(distUser.getBizPosition(),UserPosition.REVIEWE.getValue())){
                             if (distUser.getReviewPermission().contains(poolConfig.getPoolNumber())) {
                                 reviewerExtkey = distUser.getExtkey();
                                 break;
                             }
                         }
                     }
                 }
             }
         }else{
             // 分配异常
             log.warn("待复核任务 {} 的经办柜员【{}】未配置复核柜员", task.getInr(),usrcon);
             //防止redis数据与数据库不一致，这里重新查询一遍
             task = queMapper.selectOneByInr(task.getInr());
             task.setDistMethod(TaskDistMethod.AUTO.getValue());
             task.setDistStatus(TaskDistStatus.ERR.getValue());
             task.setLastErr("待复核任务的经办柜员未配置复核柜员，无法分配");
             task.setUpdateTime(new Date());
             queMapper.updateByPrimaryKey(task);
             //存入分配日志记录表
             saveAssignLog(task,TaskDistMethod.AUTO.getValue());
             return false;
         }

        TaskDistUser reviewer = taskDistUserMapper.selectOneByExtkey(reviewerExtkey);
        if (Objects.isNull(reviewer)) {
            // 分配异常
            log.warn("待复核任务 {} 未能找到指定的复核人员", task.getInr());
            //防止redis数据与数据库不一致，这里重新查询一遍
            task = queMapper.selectOneByInr(task.getInr());
            task.setDistStatus(TaskDistStatus.ERR.getValue());
            task.setLastErr("待复核任务找不到指定复核人员，无法分配");
            task.setUpdateTime(new Date());
            queMapper.updateByPrimaryKey(task);
            //存入分配日志记录表
            saveAssignLog(task,TaskDistMethod.AUTO.getValue());
            return false;
        }
        log.info("正在将待复核任务 {} 分配给 {}", task.getInr(), reviewerExtkey);
        //防止redis数据与数据库不一致，这里重新查询一遍
        task = queMapper.selectOneByInr(task.getInr());
        task.setUsr(reviewerExtkey);
        task.setDistMethod(TaskDistMethod.AUTO.getValue());
        task.setDistStatus(TaskDistStatus.OK.getValue());
        task.setUpdateTime(new Date());
        queMapper.updateByPrimaryKey(task);
        //存入分配日志记录表
        saveAssignLog(task,TaskDistMethod.AUTO.getValue());
        // 由于是忽略其他条件的直接分配，所以需要找到对应的柜员及柜员池
        reviewer.setAssignedTaskCount(calcOccupiedLimit(reviewerExtkey));
        taskDistUserMapper.updateAssignedTaskCountByExtkey(reviewer.getExtkey(), reviewer.getAssignedTaskCount());
//        RPriorityQueue<TaskDistUser> userQueue = redissonClient.getPriorityQueue(getUserPoolName(reviewer));
        // 看一下该柜员在不在池子中，在的话就做一下同步更新
        if (TaskPoolUtils.exists(userQueue, reviewer, TaskDistUser::getExtkey)) {
            TaskPoolUtils.removeByInr(userQueue, TaskDistUser::getExtkey, reviewer.getExtkey());
            // 柜员手头任务数+1，更新数据库，然后重新入队
            userQueue.offer(reviewer);
        }

        return true;
    }

    // 自动分配代经办任务，成功返回true
    private boolean autoDistributeRimTask(TaskDistConfig taskDistConfig, Que task, TaskPoolConfig poolConfig, Integer autoLimit, RPriorityQueue<TaskDistUser> userQueue) {
        // 将尝试分配次数+1
        Integer tryDistCount = Optional.ofNullable(task.getTryDistCount()).orElse(0);
        task.setTryDistCount(tryDistCount + 1);
        TaskDistUser assignee = null;

        Que corQue = getRimCorQue(task);
        //若存在退回记录则分配给原经办柜员
        if(corQue != null && isOnDuty(userQueue,corQue.getUsrcon())){
            //获取上一笔退回记录的经办柜员
            assignee = taskDistUserMapper.selectOneByExtkey(corQue.getUsrcon());
            log.info("待经办任务 {} 存在退回记录，原经办柜员为：{}", task.getInr(), assignee.getExtkey());
        }else {
            Que sameQue = getOneCert(task);
            //优先分配开关打开且存在一证项下的前手业务
            if (Objects.equals(TaskDistConstants.SWITCH_ON, taskDistConfig.getPriorityAllocationSwitch()) && (sameQue!= null && isOnDuty(userQueue,sameQue.getUsrcon()))) {
                //一证项下柜员
                assignee = taskDistUserMapper.selectOneByExtkey(sameQue.getUsrcon());
                log.info("待经办任务 {} 存在一证项下记录，原经办柜员为：{}", task.getInr(), assignee.getExtkey());

            } else {
                for (TaskDistUser user : userQueue) {
                    // TODO 一堆判断条件，用于找到合适的柜员，此处直接取有权限且阈值未满的，后续再加条件
                    if (user.getAssignedTaskCount() < autoLimit) {
                        //上收到总行的经办业务 经办、复核、主管都可以经办
//                        if (Objects.equals(user.getBizPosition(), UserPosition.HANDLER.getValue())) {
                            if (user.getHandlePermission().contains(poolConfig.getPoolNumber())) {
                              //工作模式及早晚班临近下班占用时间业务分配判断，工作模式打开时 才进行早晚班工作时间 及临近下班判断
                                if(Objects.equals(TaskDistConstants.SWITCH_ON,taskDistConfig.getWorkModeSwitch())){
                                    if(Objects.equals(WorkRank.MORNING_SHIFT.getValue(),user.getWorkRank())){
                                        if(TimeUtils.isModeTime(taskDistConfig.getMorningStartTime(),taskDistConfig.getMorningEndTime())){
                                            if(!(TimeUtils.isNearToOffDutyTime(taskDistConfig,user) && taskDistConfig.getLongHoldingtimeFrm().contains(task.getFrm()))){
                                                assignee = user;
                                                log.info("待经办任务不存在退回及一证项下记录，分配柜员为：{}", task.getInr(), assignee.getExtkey());
                                                break;
                                            }
                                        }
                                    } else if(Objects.equals(WorkRank.NIGHT_SHIFT.getValue(),user.getWorkRank())){
                                        if(TimeUtils.isModeTime(taskDistConfig.getMorningStartTime(),taskDistConfig.getMorningEndTime())){
                                            if(!(TimeUtils.isNearToOffDutyTime(taskDistConfig,user) && taskDistConfig.getLongHoldingtimeFrm().contains(task.getFrm()))) {
                                                assignee = user;
                                                log.info("待经办任务不存在退回及一证项下记录，分配柜员为：{}", task.getInr(), assignee.getExtkey());
                                                break;
                                            }
                                        }
                                    }
                                }else{
                                    assignee = user;
                                    log.info("待经办任务不存在退回及一证项下记录，分配柜员为：{}", task.getInr(), assignee.getExtkey());
                                    break;
                                }
                            }
//                        }
                    }
                }
            }
        }
        if (assignee != null) {
            // 找到柜员，设置经办柜员、分配状态等多个字段
            log.info("已为代经办任务 {} 找到可分配柜员 {}", task.getInr(), assignee.getExtkey());
            //防止redis数据与数据库不一致，这里重新查询一遍
            task = queMapper.selectOneByInr(task.getInr());
            task.setUsr(assignee.getExtkey());
            //上收业务去掉经办柜员的赋值
//            task.setUsrcon(assignee.getExtkey());
            task.setStatus(TaskStatus.ASSIGNED.getValue());
            task.setDistMethod(TaskDistMethod.AUTO.getValue());
            task.setDistStatus(TaskDistStatus.OK.getValue());
            task.setUpdateTime(new Date());

            queMapper.updateByPrimaryKey(task);
            //存入分配日志记录表
            saveAssignLog(task,TaskDistMethod.AUTO.getValue());
            TaskPoolUtils.removeByInr(userQueue, TaskDistUser::getExtkey, assignee.getExtkey());
            // 柜员手头任务数+1，更新数据库，然后重新入队
            assignee.setAssignedTaskCount(calcOccupiedLimit(assignee.getExtkey()));
            taskDistUserMapper.updateAssignedTaskCountByExtkey(assignee.getExtkey(), assignee.getAssignedTaskCount());
            userQueue.offer(assignee);
            return true;
        } else {
            log.warn("待经办任务 {} 未找到可分配柜员", task.getInr());
            //防止redis数据与数据库不一致，这里重新查询一遍
            task = queMapper.selectOneByInr(task.getInr());
            task.setDistMethod(TaskDistMethod.AUTO.getValue());
            task.setDistStatus(TaskDistStatus.ERR.getValue());
            task.setLastErr("未能找到符合条件的可分配柜员");
            task.setUpdateTime(new Date());
            queMapper.updateByPrimaryKey(task);
            //存入分配日志记录表
            saveAssignLog(task,TaskDistMethod.AUTO.getValue());
            return false;
        }
    }

    /**
     * 溢出模式分配上收业务
     * @param taskDistConfig
     * @param task
     * @param poolConfig
     * @param autoLimit
     * @param userQueue
     * @return
     */
    private boolean autoDistributeOverFlowRimTask(TaskDistConfig taskDistConfig, Que task, TaskPoolConfig poolConfig, Integer autoLimit, RPriorityQueue<TaskDistUser> userQueue){
        // 将尝试分配次数+1
        Integer tryDistCount = Optional.ofNullable(task.getTryDistCount()).orElse(0);
        task.setTryDistCount(tryDistCount + 1);
        TaskDistUser assignee = null;

        Que corQue = getRimCorQue(task);
        //若存在退回记录则分配给原经办柜员
        if(corQue != null && isOnDuty(userQueue,corQue.getUsrcon())){
            //获取上一笔退回记录的经办柜员
            assignee = taskDistUserMapper.selectOneByExtkey(corQue.getUsrcon());
        }else {
            Que sameQue = getOneCert(task);
            //优先分配开关打开且存在一证项下的前手业务
            if (Objects.equals(TaskDistConstants.SWITCH_ON, taskDistConfig.getPriorityAllocationSwitch()) && (sameQue!= null && isOnDuty(userQueue,sameQue.getUsrcon()))) {
                //一证项下柜员
                assignee = taskDistUserMapper.selectOneByExtkey(sameQue.getUsrcon());

            } else {
                for (TaskDistUser user : userQueue) {
                    if (user.getAssignedTaskCount() < autoLimit) {
                        //上收到总行的经办业务 经办、复核、主管都可以经办
                        //溢出柜式不需要考虑柜员所配置的任务池限制
                                assignee = user;
                                break;
                    }
                }
            }
        }
        if (assignee != null) {
            // 找到柜员，设置经办柜员、分配状态等多个字段
            log.info("已为代经办任务 {} 找到可分配柜员 {}", task.getInr(), assignee.getExtkey());
            //防止redis数据与数据库不一致，这里重新查询一遍
            task = queMapper.selectOneByInr(task.getInr());
            task.setUsr(assignee.getExtkey());
            //上收业务去掉经办柜员的赋值
//            task.setUsrcon(assignee.getExtkey());
            task.setStatus(TaskStatus.ASSIGNED.getValue());
            task.setDistMethod(TaskDistMethod.AUTO.getValue());
            task.setDistStatus(TaskDistStatus.OK.getValue());
            task.setUpdateTime(new Date());
            queMapper.updateByPrimaryKey(task);
            //存入分配日志记录表
            saveAssignLog(task,TaskDistMethod.AUTO.getValue());
            RPriorityQueue<TaskDistUser> userQueueByGrp =redissonClient.getPriorityQueue(getUserPoolName(assignee));
            if(!userQueueByGrp.isExists()){
              throw new TaskDistException("柜员池不存在!");
            }
            TaskPoolUtils.removeByInr(userQueueByGrp, TaskDistUser::getExtkey, assignee.getExtkey());
//            TaskPoolUtils.removeByInr(userQueue, TaskDistUser::getExtkey, assignee.getExtkey());
            // 柜员手头任务数+1，更新数据库，然后重新入队
            assignee.setAssignedTaskCount(calcOccupiedLimit(assignee.getExtkey()));
            taskDistUserMapper.updateAssignedTaskCountByExtkey(assignee.getExtkey(), assignee.getAssignedTaskCount());
            userQueueByGrp.offer(assignee);
//            userQueue.offer(assignee);
            return true;
        } else {
            log.warn("待经办任务 {} 未找到可分配柜员", task.getInr());
            //防止redis数据与数据库不一致，这里重新查询一遍
            task = queMapper.selectOneByInr(task.getInr());
            task.setDistMethod(TaskDistMethod.AUTO.getValue());
            task.setDistStatus(TaskDistStatus.ERR.getValue());
            task.setLastErr("未能找到符合条件的可分配柜员");
            task.setUpdateTime(new Date());
            queMapper.updateByPrimaryKey(task);
            //存入分配日志记录表
            saveAssignLog(task,TaskDistMethod.AUTO.getValue());
            return false;
        }
    }
    /**
     * 来报业务分配
     * @param taskDistConfig
     * @param task
     * @param poolConfig
     * @param autoLimit
     * @param userQueue
     * @return
     */
    public boolean autoDistributeIncomingTask(TaskDistConfig taskDistConfig, Que task, TaskPoolConfig poolConfig, Integer autoLimit, RPriorityQueue<TaskDistUser> userQueue){
        // 将尝试分配次数+1
        Integer tryDistCount = Optional.ofNullable(task.getTryDistCount()).orElse(0);
        task.setTryDistCount(tryDistCount + 1);
        TaskDistUser assignee = null;
        for (TaskDistUser user : userQueue) {
            // TODO 一堆判断条件，用于找到合适的柜员，此处直接取有权限且阈值未满的，后续再加条件
            if (user.getAssignedTaskCount() < autoLimit) {
                //只分配给经办柜员
                if (Objects.equals(user.getBizPosition(), UserPosition.HANDLER.getValue())) {
                    if (user.getHandlePermission().contains(poolConfig.getPoolNumber())) {
                        assignee = user;
                        break;
                    }
                }
            }
        }
        if (assignee != null) {
            // 找到柜员，设置经办柜员、分配状态等多个字段
            log.info("已为来报业务 {} 找到可分配柜员 {}", task.getInr(), assignee.getExtkey());
            task.setUsr(assignee.getExtkey());
            task.setUsrcon(assignee.getExtkey());
//            task.setStatus(TaskStatus.ASSIGNED.getValue());
            task.setDistMethod(TaskDistMethod.AUTO.getValue());
            task.setDistStatus(TaskDistStatus.OK.getValue());
            task.setUpdateTime(new Date());
            queMapper.updateByPrimaryKey(task);
            //存入分配日志记录表
            saveAssignLog(task,TaskDistMethod.AUTO.getValue());
            TaskPoolUtils.removeByInr(userQueue, TaskDistUser::getExtkey, assignee.getExtkey());
            // 柜员手头任务数+1，更新数据库，然后重新入队
            assignee.setAssignedTaskCount(calcOccupiedLimit(assignee.getExtkey()));
            taskDistUserMapper.updateAssignedTaskCountByExtkey(assignee.getExtkey(), assignee.getAssignedTaskCount());
            userQueue.offer(assignee);
            return true;
        } else {
            log.warn("待经办任务 {} 未找到可分配柜员", task.getInr());
            task.setDistMethod(TaskDistMethod.AUTO.getValue());
            task.setDistStatus(TaskDistStatus.ERR.getValue());
            task.setLastErr("未能找到符合条件的可分配柜员");
            task.setUpdateTime(new Date());
            queMapper.updateByPrimaryKey(task);
            //存入分配日志记录表
            saveAssignLog(task,TaskDistMethod.AUTO.getValue());
            return false;
        }
    }
    /**
     * 判断柜员是否在线
     */
    public boolean isOnDuty(RPriorityQueue<TaskDistUser> userQueue,String extkey){
        boolean isOnDuty = false;
        //柜员池不存在，直接返回false
        if(!userQueue.isExists()){
            log.warn("当前柜员池不存在，{}",userQueue.getName());
            return isOnDuty;
        }
        //判断柜员是否在柜员池中存在即可 判断柜员是否配置、参与分配及是否在线
            for (TaskDistUser u : userQueue) {
                if (Objects.equals(u.getExtkey(), extkey)) {
                    isOnDuty = true;
                }
            }
        return isOnDuty;

    }

    /**
     * 判断是否为一证项下的业务
     * @param que
     */
    //TODO去掉自己的这笔记录
    public Que getOneCert(Que que){
        Que argQue = new Que();
        argQue.setBchkeyinr(que.getBchkeyinr());
        argQue.setObjref(que.getObjref());
        String objref = que.getObjref();
        String subobjref = objref.substring(0,objref.length()-2);
        argQue.setCla(que.getCla());
        argQue.setStatus(TaskStatus.RELEASE.getValue());
        argQue.setFrm(que.getFrm());//前手业务应判断交易码不同
        List<Que> queList = queMapper.selectByObjref(argQue,subobjref);
        if(queList.size() > 0 ){
            return queList.get(0);
        }
        return null;
    }

    /**
     * 判断是否有复核退回记录
     * @param que
     */
    public Que getWaitingCorQue(Que que){
        Que queTmp = new Que();
        queTmp.setBchkeyinr(que.getBchkeyinr());
        queTmp.setObjref(que.getObjref());
        queTmp.setFrm(que.getFrm());
        queTmp.setCla(QueClaStatus.REL.getValue());
        queTmp.setStatus(TaskStatus.DELETED.getValue());
        List<Que> queCor =  queMapper.selectConditionList(queTmp);
        if(queCor.size() > 0){
            return queCor.get(0);
        }
        return null;
    }
    /**
     * 判断是否有上收退回记录
     * @param que
     */
    public Que getRimCorQue(Que que){
        Que queTmp = new Que();
        queTmp.setBchkeyinr(que.getBchkeyinr());
        queTmp.setObjref(que.getObjref());
        queTmp.setFrm(que.getFrm());
        queTmp.setCla(QueClaStatus.RIM.getValue());
        queTmp.setStatus(TaskStatus.DELETED.getValue());
        queTmp.setOldstatus(TaskStatus.ASSIGNED.getValue());
        List<Que> queCor =  queMapper.selectConditionList(queTmp);
        if(queCor.size() > 0){
            return queCor.get(0);
        }
        return null;
    }

    public Que getCorrectAssignQue(Que que){
        String ordinr=this.getQueOrdinr(que);
        Que rtnQue=new Que();
        List<Que> queCor =  queMapper.getOldAssignUsrQueList(que.getObjref(),que.getFrm(),que.getBchkeyinr());
        if(queCor!=null && queCor.size() > 0){
            for(Que item :queCor){
                if(!StringUtils.isEmpty(ordinr) && ordinr.equals(this.getQueOrdinr(item))){
                    rtnQue = MdaUtils.deepClone(item);
                    break;
                }
            }
        }
        return rtnQue;
    }

    public String getQueOrdinr(Que que){
        String ordinr="";
        if("SPT".equals(que.getObjtyp())){
            Spt spt =sptMapper.getSptByInr(que.getObjinr());
            ordinr=spt!=null?spt.getOrdinr():"";
        }
        if("TRN".equals(que.getObjtyp())){
            Trn trn =trnMapper.selectByTrninr(que.getObjinr());
            ordinr=trn!=null?trn.getOrdinr():"";
        }
        if(StringUtils.isEmpty(ordinr) && StringUtils.isNotEmpty(que.getOrdinr())){
            return que.getOrdinr();
        }
        return ordinr;
    }

    // 柜员提交任务，解除阈值占用
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void commitTask(String extkey) {
        log.info("柜员【{}】正在提交任务", extkey);
        TaskDistUser user = taskDistUserMapper.selectOneByExtkey(extkey);
        if (user == null) {
            log.warn("柜员【{}】尚未在任务分配器柜员表中进行配置", extkey);
            return;
        }
        // 更新数据库阈值
        int count = calcOccupiedLimit(extkey);
        log.info("更新柜员【{}】的任务阈值占用为 {}", extkey, count);
        taskDistUserMapper.updateAssignedTaskCountAndLastCommitTimeByExtkey(extkey, count, new Date());

        // 更新redis阈值
        TaskDistConfig config = taskDistConfigMapper.selectOneByBranchinr(user.getBranchinr());
        if (Objects.isNull(config)) {
            log.warn("柜员【{}】所在机构【{}】尚未在任务分配器柜员表中进行配置", extkey, user.getBranchinr());
            return;
        }
        TaskDistConstants.sortflg.remove();
        TaskDistConstants.sortflg.get().put(config.getBranchinr(),config);
        if (Objects.equals(config.getMasterSwitch(), TaskDistConstants.SWITCH_ON)) {
            log.info("同步更新柜员在redis池中【{}】的任务阈值占用为 {}", extkey, count);
            RPriorityQueue<TaskDistUser> userQueue = redissonClient.getPriorityQueue(getUserPoolName(user));
            //在柜员任务池中存在的柜员才进行更新
            if(isOnDuty(userQueue,user.getExtkey())) {
                TaskPoolUtils.removeByInr(userQueue, TaskDistUser::getExtkey, user.getExtkey());
                user.setAssignedTaskCount(count);
                user.setLastCommitTime(new Date());
                userQueue.offer(user);
            }
        }

    }

    /**
     * 查询当前用户任务数
     * @param extkey
     * @return
     */
    public int calcOccupiedLimit(String extkey) {
        return queMapper.countOccupiedLimit(extkey);
    }

    /**
     * 查询当前组别的任务数量
     */
    public int calcTaskCountByBizGrp(String branchinr,String bizGrp){
        TaskDistUser argUsr = new TaskDistUser();
        argUsr.setBizGroup(bizGrp);
        argUsr.setBranchinr(branchinr);
        RPriorityQueue<TaskDistUser> queue = redissonClient.getPriorityQueue(getUserPoolName(argUsr));
        int taskCount = 0;
        for (TaskDistUser usr: queue) {
           taskCount += usr.getAssignedTaskCount();
        }
        return taskCount;
    }
    /**
     * 插入分配日志
     * @param que
     */
    public void saveAssignLog(Que que,String assignTyp){
        Tskquelog tskquelog = new Tskquelog();
        tskquelog.setQueinr(que.getInr());
        tskquelog.setFrm(que.getFrm());
        tskquelog.setCla(que.getCla());
        tskquelog.setObjref(que.getObjref());
        tskquelog.setRelcur(que.getRelcur());
        tskquelog.setRelamt(que.getRelamt());
        tskquelog.setStatus(que.getStatus());
        tskquelog.setUsrcon(que.getUsrcon());
        tskquelog.setUsr(que.getUsr());
//        if(TaskDistMethod.MANUAL.getValue().equals(assignTyp)) {
//            tskquelog.setAssusr(SettleContext.getSessionUserVo().getLogName());
//        }
        tskquelog.setUpdateTime(new Date());
        tskquelog.setDistStatus(que.getDistStatus());
        if(TaskDistStatus.OK.getValue().equals(que.getDistStatus())){
            tskquelog.setRemarks(TaskDistMethod.getValueName(assignTyp) + ":分配成功");
        }else{
            tskquelog.setRemarks(TaskDistMethod.getValueName(assignTyp) + ":" + que.getLastErr());
        }
        tskquelog.setBizGroup(matchPool(que).get().getBizGroup());
        tskquelogMapper.insert(tskquelog);
    }

}
