package org.dromara.zjk.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.shaded.com.google.common.base.Splitter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.DynamicTask;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.resource.api.RemoteMessageService;
import org.dromara.system.api.RemoteConfigService;
import org.dromara.zjk.domain.*;
import org.dromara.zjk.domain.bo.ZjkExpertItemBo;
import org.dromara.zjk.domain.bo.ZjkItemExtreationBo;
import org.dromara.zjk.domain.bo.ZjkProjectExpertItemBo;
import org.dromara.zjk.domain.dto.OnchainDto;
import org.dromara.zjk.domain.dto.SmsSendDto;
import org.dromara.zjk.domain.dto.SmsUpEventDto;
import org.dromara.zjk.domain.vo.*;
import org.dromara.zjk.enums.*;
import org.dromara.zjk.event.OnchainEvent;
import org.dromara.zjk.mapper.*;
import org.dromara.zjk.service.IZjkExpertItemService;
import org.dromara.zjk.service.IZjkExpertService;
import org.dromara.zjk.service.IZjkItemExtreationService;
import org.dromara.zjk.service.ZjkSmsInfoService;
import org.dromara.zjk.utils.NumberGenerator;
import org.dromara.zjk.zwy.utils.StringCryptoUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 专家抽取Service业务层处理
 *
 * @author ygh
 * @date 2024-10-29
 */
@RequiredArgsConstructor
@Transactional
@Service
public class ZjkExpertItemServiceImpl implements IZjkExpertItemService {
    private static final Logger log = LoggerFactory.getLogger(ZjkExpertItemServiceImpl.class);
    @Resource
    private final ZjkExpertItemMapper baseMapper;

    private final IZjkExpertService zjkExpertService;

    private final IZjkItemExtreationService zjkItemExtreationService;
    @Resource
    private final ZjkItemExtreationMapper zjkItemExtreationMapper;
    @Resource
    private final ZjkProductMapper zjkProductMapper;
    @Resource
    private final ZjkExpertMapper zjkExpertMapper;
    @Resource
    private final ZjkReviewPhaseMapper zjkReviewPhaseMapper;
    @Resource
    private ScheduledExecutorService scheduledExecutorService;
    @Resource
    private RemoteMessageService remoteMessageService;
    @Resource
    private final ZjkCreditUserMapper zjkCreditUserMapper;

    @Resource
    private final ZjkExpertMajorMapper zjkExpertMajorMapper;

    @Resource
    private final ZjkSmsInfoService zjkSmsInfoService;


    @DubboReference
    private RemoteConfigService remoteConfigService;
    @Resource
    private DynamicTask dynamicTask;
    private final ApplicationEventPublisher eventPublisher;


    @Autowired
    private StringCryptoUtil stringCryptoUtil;
    /**
     * 查询专家抽取
     *
     * @param id 根据项目id获取详情信息
     * @return专家抽取
     */
    @Override
    public ZjkExpertItemVo queryById(Long id) {
        ZjkExpertItem zjkExpertItem = baseMapper.selectById(id);
        LambdaQueryWrapper<ZjkItemExtreation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(zjkExpertItem.getItemId() != null, ZjkItemExtreation::getItemId, zjkExpertItem.getItemId());
        ZjkItemExtreationVo zjkExpertItemVos = zjkItemExtreationMapper.selectVoOne(wrapper);
        //获取专家信息
        LambdaQueryWrapper<ZjkExpertItem> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(zjkExpertItemVos.getItemId() != null, ZjkExpertItem::getItemId, zjkExpertItemVos.getItemId());
        List<ZjkExpertItem> zjkExpertItems = baseMapper.selectList(lambdaQueryWrapper);
        List<Long> idSet = zjkExpertItems.stream()
            .map(ZjkExpertItem::getExpertId)
            .collect(Collectors.toList());
        LambdaQueryWrapper<ZjkExpert> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(!idSet.isEmpty(), ZjkExpert::getExpertId, idSet);
        List<ZjkExpertVo> zjkExpertVos = zjkExpertMapper.selectVoList(queryWrapper);
        ZjkExpertItemVo zjkExpertItemVo = new ZjkExpertItemVo();
        zjkExpertItemVo.setZjkExpertVo(zjkExpertVos);
//        zjkExpertItemVo.setZjkProjectVo();
//        zjkExpertItemVo.setZjkExpertVo(zjkExpertItems);
        return zjkExpertItemVo;
    }

    /**
     * 分页查询专家抽取列表
     *
     * @param zjkItemExtreationBo 查询条件
     * @param pageQuery           分页参数
     * @return 专家抽取分页列表
     */
    @Override
    public TableDataInfo<ZjkItemExtreationVo> queryPageList(ZjkItemExtreationBo zjkItemExtreationBo, PageQuery pageQuery) {
//        if (zjkItemExtreationBo.getExtractionStatus() != null) {
//            zjkItemExtreationBo.setExtractionStatus(zjkItemExtreationBo.getExtractionStatus());
//        }
//        if (zjkItemExtreationBo.getExtractionTime() != null) {
//            zjkItemExtreationBo.setExtractionTime(zjkItemExtreationBo.getExtractionTime());
//        }
        zjkItemExtreationBo.setRecordsExpert("records");
        TableDataInfo<ZjkItemExtreationVo> zjkItemExtreationVoTableDataInfo = zjkItemExtreationService.queryPageList(zjkItemExtreationBo, pageQuery);
        return zjkItemExtreationVoTableDataInfo;
    }

    /**
     * 查询符合条件的专家抽取列表
     *
     * @param bo 查询条件
     * @return 专家抽取列表
     */
    @Override
    public List<ZjkExpertItemVo> queryList(ZjkExpertItemBo bo) {
        LambdaQueryWrapper<ZjkExpertItem> lqw = buildQueryWrapper(bo);
        List<ZjkExpertItemVo> zjkExpertItemVos = baseMapper.selectVoList(lqw);
        for (ZjkExpertItemVo zjkExpertItemVo : zjkExpertItemVos) {
            if (zjkExpertItemVo.getItemId() != null) {
                Long itemId = zjkExpertItemVo.getItemId();
                ZjkProductVo zjkProjectVo = zjkProductMapper.selectVoById(itemId);
                zjkExpertItemVo.setZjkProjectVo(zjkProjectVo);
            }
        }
        return zjkExpertItemVos;
    }

    private LambdaQueryWrapper<ZjkExpertItem> buildQueryWrapper(ZjkExpertItemBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ZjkExpertItem> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getExpertId() != null, ZjkExpertItem::getExpertId, bo.getExpertId());
        lqw.eq(bo.getItemId() != null, ZjkExpertItem::getItemId, bo.getItemId());
        return lqw;
    }

    /**
     * 新增专家抽取
     *
     * @param bo 专家抽取
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(ZjkExpertItemBo bo) {
        ZjkExpertItem add = MapstructUtils.convert(bo, ZjkExpertItem.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改专家抽取
     *
     * @param b 专家抽取
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(ZjkExpertItemBo b) {
        ZjkReviewPhase zjkReviewPhase1 = zjkReviewPhaseMapper.selectById(b.getReviewId());
        //专家确认的截至时间
        Date noticeTime = zjkReviewPhase1.getNoticeTime();
        int compare = DateUtil.compare(noticeTime, new Date());
        if(compare<0){
            throw new ServiceException("当前时间已超过专家确认截止时间,请修改抽取规则");
        }
        Long reviewId = zjkReviewPhase1.getId();
        if (zjkReviewPhase1.getParentId() != 0L) {
            reviewId = zjkReviewPhase1.getParentId();
        }
        //根据规则获取所有项目id，阶段，已发送的
        Long zjkItemExtreationId = zjkReviewPhaseMapper.selectListByItem(reviewId);
        //修改之前的项目数据为失效
        ZjkItemExtreation zjkItemExtreation = zjkItemExtreationMapper.selectById(zjkItemExtreationId);

        ZjkProduct zjkProduct = zjkProductMapper.selectById(zjkItemExtreation.getItemId());

        zjkItemExtreation.setIsSure(1L);
        zjkItemExtreation.setExtractionStatus(ItemExpertTypeEnum.EXTRACTION_SUCCESS_TYPE.getCode());
        //修改规则为有效
        ZjkReviewPhase zjkReviewPhase = new ZjkReviewPhase();
        zjkReviewPhase.setId(b.getReviewId());
        zjkReviewPhase.setEffective(ReviewTypeEnum.REVIEW_LOSE_TYPE.getCode());
        //完成按钮 把重抽原因清除
        zjkReviewPhase.setCauseRepum(null);
        // 拿到这次的抽取记录
        List<ZjkExpertItem> zjkExpertItemList = baseMapper.selectList(new LambdaQueryWrapper<ZjkExpertItem>()
            .eq(ZjkExpertItem::getReviewId, b.getReviewId()));
        zjkItemExtreation.setExpertSum(zjkExpertItemList.size());
        zjkItemExtreation.setReviewId(b.getReviewId());
        zjkItemExtreationMapper.updateById(zjkItemExtreation);
        // 根据这次的规则拿到上次的规则
        ZjkReviewPhase beforZjkReviewPhase = zjkReviewPhaseMapper.selectOne(new LambdaQueryWrapper<ZjkReviewPhase>()
            .eq(ZjkReviewPhase::getReviewSn,zjkReviewPhase1.getReviewSn())
            .eq(ZjkReviewPhase::getItemId,zjkReviewPhase1.getItemId())
            .orderByDesc(ZjkReviewPhase::getId) // 按 id 降序排序
            .last("LIMIT 1")                   // 只取一条记录
            );
        // 提取所有 userId
        List<Long> expertIds = zjkExpertItemList.stream()
            .map(ZjkExpertItem::getExpertId)
            .collect(Collectors.toList());
        List<ZjkExpert> zjkExpertList = zjkExpertMapper.selectList(new LambdaQueryWrapper<ZjkExpert>().in(ZjkExpert::getExpertId,expertIds));
        Map<Long, ZjkExpert> groupedByUserId = zjkExpertList.stream()
            .collect(Collectors.toMap(
                ZjkExpert::getUserId,
                expert -> expert,
                (existing, replacement) -> existing));
        if (beforZjkReviewPhase != null) {
            // 根据上次的规则拿到上次的抽取记录
            List<ZjkExpertItem> beforeZjkExpertItemList = baseMapper.selectList(new LambdaQueryWrapper<ZjkExpertItem>()
                .eq(ZjkExpertItem::getReviewId, beforZjkReviewPhase.getId()));
            //  循环更新状态
            Map<Long, ZjkExpertItem> beforeItemMap = beforeZjkExpertItemList.stream()
                .collect(Collectors.toMap(ZjkExpertItem::getExpertId, item -> item));
            // 遍历 zjkExpertItemList，更新匹配记录
            for (ZjkExpertItem currentItem : zjkExpertItemList) {
                ZjkExpertItem beforeItem = beforeItemMap.get(currentItem.getExpertId());
                if (beforeItem != null && (beforeItem.getAcceptStatus().equals("1")|| beforeItem.getAcceptStatus().equals("0"))) {
                    currentItem.setAcceptStatus(beforeItem.getAcceptStatus());
                    currentItem.setConfirmCode(beforeItem.getConfirmCode());
                    currentItem.setRefuseCode(beforeItem.getRefuseCode());
                } else {
                    // 新数据为待接受
                    currentItem.setAcceptStatus(String.valueOf(ExpertItemTypeEnum.EXPERTITEM_NOTAFFIRM_TYPE.getCode()));
                    //获取每个被抽取到的专家的userid;发送消息
                    scheduledExecutorService.schedule(() -> {
                        remoteMessageService.publishMessage(currentItem.getUserId(), "您有新的评审任务，请尽快确认");
                    }, 3, TimeUnit.SECONDS);
                    currentItem.setConfirmCode(NumberGenerator.generateRandomNumber(4)+"1");
                    currentItem.setRefuseCode(NumberGenerator.generateRandomNumber(4)+"0");
                    // 构建短信参数
                    SmsSendDto smsSendDto = buildSmsSendDto(currentItem, groupedByUserId, zjkReviewPhase1, zjkProduct);
                    try {
                        zjkSmsInfoService.sendSms(smsSendDto);
                    } catch (Exception smsException) {
                        log.error("短信发送异常,发送参数:{}",smsSendDto);
                        smsException.printStackTrace(); // 记录日志或做其他处理
                    }
                }
                //2024/12/3 add操作 确认时改变zjkExpertItem 记录的接受状态为确认(1)  借用枚举内的1
                currentItem.setExtractionStatus(ExtractionStautsEnum.CONFIRM.getCode());
                currentItem.setIsSure(1);
                baseMapper.updateById(currentItem);
            }
        } else {
            // 首次确认 进行随机码构建
            for (ZjkExpertItem currentItem : zjkExpertItemList) {
                // 异步发送站内消息
                scheduledExecutorService.schedule(() ->
                        remoteMessageService.publishMessage(currentItem.getUserId(), "您有新的评审任务，请尽快确认"),
                    3, TimeUnit.SECONDS
                );
                currentItem.setConfirmCode(NumberGenerator.generateRandomNumber(4)+"1");
                currentItem.setRefuseCode(NumberGenerator.generateRandomNumber(4)+"0");
                // 更新当前条目的状态
                currentItem.setIsSure(1);
                currentItem.setAcceptStatus(String.valueOf(ExpertItemTypeEnum.EXPERTITEM_NOTAFFIRM_TYPE.getCode()));
                baseMapper.updateById(currentItem);

                // 构建短信参数
                SmsSendDto smsSendDto = buildSmsSendDto(currentItem, groupedByUserId, zjkReviewPhase1, zjkProduct);
                try {
                    zjkSmsInfoService.sendSms(smsSendDto);
                } catch (Exception smsException) {
                    log.error("短信发送异常,发送参数:{}",smsSendDto);
                    smsException.printStackTrace(); // 记录日志或做其他处理
                }
            }
        }
        zjkReviewPhaseMapper.updateById(zjkReviewPhase);

        //到达该时间后需要向项目管理员发送专家确认的情况
        long between = DateUtil.between(noticeTime, new Date(), DateUnit.SECOND);
        String key= "zjcq_"+zjkReviewPhase1.getId();
        dynamicTask.startDelay(key, () -> sendConfirmSmsToXmManager(zjkReviewPhase1, zjkProduct), 1000 * between);
        //专家抽取结果数据上区块链
        OnchainDto onchainDto = new OnchainDto();
        onchainDto.setReviewId(reviewId);
        eventPublisher.publishEvent(new OnchainEvent(this, onchainDto));
        return true;
    }

    /**
     * 抽取截至通知短信发送
     * @param phase
     * @param zjkProduct
     */
    private void sendConfirmSmsToXmManager(ZjkReviewPhase phase, ZjkProduct zjkProduct){
    List<ZjkExpertItem> zjs= baseMapper.getCheckZjAccetpt(phase.getId());
    if (!CollectionUtil.isEmpty(zjs)) {
        Integer size=zjs.size();
        //获取项目管理员的用户id
        Long createBy = zjs.get(0).getCreateBy();
        String phone = baseMapper.checkUserPhoneExist(createBy);
        if(!StringUtils.isEmpty(phone)){
            int acceptedCount = (int) zjs.stream()
                .filter(zjkExpertItem -> ZjkExpertItemAcceptStatus.accept.getValue().equals(zjkExpertItem.getAcceptStatus()))
                .count();

            int unacceptedCount = (int) zjs.stream()
                .filter(zjkExpertItem -> ZjkExpertItemAcceptStatus.no_accept.getValue().equals(zjkExpertItem.getAcceptStatus()))
                .count();

            int rejectedCount = (int) zjs.stream()
                .filter(zjkExpertItem -> ZjkExpertItemAcceptStatus.reject.getValue().equals(zjkExpertItem.getAcceptStatus()))
                .count();

            int canceledCount = (int) zjs.stream()
                .filter(zjkExpertItem -> ZjkExpertItemAcceptStatus.cancel.getValue().equals(zjkExpertItem.getAcceptStatus()))
                .count();

            SmsSendDto smsSendDto = new SmsSendDto();
            smsSendDto.setBatchType(1);
            smsSendDto.setReceiveUserIds(Arrays.asList(createBy));
            smsSendDto.setSendBy(createBy);
            JSONObject jsonObject = new JSONObject();
            String reviewSnDesc = ReviewSnEnum.getByCode(phase.getReviewSn()).getDesc();
            jsonObject.put("productName", zjkProduct.getProductName());
            jsonObject.put("reviewSn", reviewSnDesc != null ? reviewSnDesc : "");
            jsonObject.put("num", size);
            if(size==acceptedCount){
                //全部接收
                smsSendDto.setTemplateId(SmsTemplateEnum.SMS_NOTICE_ACCEPT.getCode());

            }else{
                //部分接收
                smsSendDto.setTemplateId(SmsTemplateEnum.SMS_NOTICE_NO_ACCEPT.getCode());
                jsonObject.put("noAcceptNum", unacceptedCount);
                jsonObject.put("rejectNum", rejectedCount);
                jsonObject.put("acceptNum", acceptedCount);
                //部分接收修改抽取状态
                // 更新抽取人数
                ZjkItemExtreation zjkItemExtreation =zjkItemExtreationMapper.selectOne(new LambdaQueryWrapper<ZjkItemExtreation>()
                    .eq(ZjkItemExtreation::getId,phase.getItemExtreationId()));
                if (zjkItemExtreation != null){
                    zjkItemExtreation.setExtractedSum(zjkItemExtreation.getExtractedSum()-unacceptedCount-rejectedCount);
                    zjkItemExtreation.setExtractionStatus(1);
                    zjkItemExtreationMapper.updateById(zjkItemExtreation);
                }
            }
            smsSendDto.setParamJson(jsonObject);
            try {
                zjkSmsInfoService.sendSms(smsSendDto);
            } catch (Exception smsException) {
                log.error("抽取截至通知短信发送异常,发送参数:{}",smsSendDto);
                smsException.printStackTrace(); // 记录日志或做其他处理
            }
        }


    }

    }


    /**
     * 构建短信发送 DTO
     */
    private SmsSendDto buildSmsSendDto(ZjkExpertItem currentItem, Map<Long, ZjkExpert> groupedByUserId,
                                       ZjkReviewPhase zjkReviewPhase1, ZjkProduct zjkProduct) {
        SmsSendDto smsSendDto = new SmsSendDto();
        smsSendDto.setBatchType(1);
        smsSendDto.setReceiveUserIds(Collections.singletonList(currentItem.getUserId()));
        smsSendDto.setSendBy(LoginHelper.getUserId());
        smsSendDto.setTemplateId("1");

        JSONObject jsonObject = new JSONObject();
        ZjkExpert zjkExpert = groupedByUserId.get(currentItem.getUserId());
        if (zjkExpert != null) {
            jsonObject.put("expertName", zjkExpert.getExpertName());
        }
        jsonObject.put("reviewTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, zjkReviewPhase1.getReviewTime()));
        jsonObject.put("productName", zjkProduct.getProductName());
        String reviewSnDesc = ReviewSnEnum.getByCode(zjkReviewPhase1.getReviewSn()).getDesc();
        jsonObject.put("reviewSn", reviewSnDesc != null ? reviewSnDesc : "");
        jsonObject.put("reviewPlace", zjkReviewPhase1.getReviewPlace());
        jsonObject.put("confirmCode",currentItem.getConfirmCode());
        jsonObject.put("noticeTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, zjkReviewPhase1.getNoticeTime()));
        jsonObject.put("refuseCode",currentItem.getRefuseCode());
        smsSendDto.setParamJson(jsonObject);
        return smsSendDto;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ZjkExpertItem entity) {
    }

    /**
     * 校验并批量删除信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {

        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 专家抽取功能
     *
     * @param zjkProjectExpertItemBo 需抽取的项目
     * @return 是否删除成功
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public long expertltem(ZjkProjectExpertItemBo zjkProjectExpertItemBo) {
        // 是否补抽
        if (zjkProjectExpertItemBo.getRedraw() != null && !zjkProjectExpertItemBo.getRedraw()) {
            //校验是否重复抽取
            Long itemid = zjkProjectExpertItemBo.getItemid();
            String reviewSn = zjkProjectExpertItemBo.getReviewSn();
            LambdaQueryWrapper<ZjkItemExtreation> lamdaQuery = new LambdaQueryWrapper<>();
            lamdaQuery.eq(ZjkItemExtreation::getItemId, itemid);
            lamdaQuery.ne(ZjkItemExtreation::getExtractionStatus, ItemExpertTypeEnum.EXTRACTION_FAILURE_TYPE.getCode());
            lamdaQuery.eq(ZjkItemExtreation::getIsSure, ExpertItemTypeEnum.EXPERTITEM_AFFIRM_TYPE.getCode());
            //获取有效项目
            List<ZjkItemExtreationVo> zjkItemExtreationVoList = zjkItemExtreationMapper.selectVoList(lamdaQuery);
            //之前抽取表关联reviewId   现在是规则表外键item_extraction_id
            for (ZjkItemExtreationVo zjkItemExtreationVo : zjkItemExtreationVoList) {
                LambdaQueryWrapper<ZjkReviewPhase> zjkReviewPhaseLambdaQueryWrapper = new LambdaQueryWrapper<>();
                zjkReviewPhaseLambdaQueryWrapper.eq(ZjkReviewPhase::getItemExtreationId, zjkItemExtreationVo.getId());//抽取id和规则表里的抽取id对应
                zjkReviewPhaseLambdaQueryWrapper.eq(ZjkReviewPhase::getReviewSn, reviewSn);//抽取阶段
                zjkReviewPhaseLambdaQueryWrapper.eq(ZjkReviewPhase::getIsSummarize, 0);
                zjkReviewPhaseLambdaQueryWrapper.eq(ZjkReviewPhase::getEffective, 1);
                Long phaseCount = zjkReviewPhaseMapper.selectCount(zjkReviewPhaseLambdaQueryWrapper);
                if (phaseCount > 0) {//有是否总结字段为0的规则记录   抛出异常
                    throw new ServiceException("该项目当前阶段没有总结,请先总结");
                }
            }
        }

        Long reviewId = null;
        Long parenId = null;

        // 专家数量
        Integer expertSum = 0;
        //抽取次数
        Integer expertCount = 0;
        // 补抽的重抽
        Integer supplementCause = 0;
        // id 不为 null  重抽
        if (zjkProjectExpertItemBo.getId() != null && zjkProjectExpertItemBo.getRedraw() == null) {
            LambdaQueryWrapper<ZjkItemExtreation> lambdaQuery = new LambdaQueryWrapper<>();
            lambdaQuery.eq(ZjkItemExtreation::getId, zjkProjectExpertItemBo.getId());
            // 获取抽取记录
            ZjkItemExtreationVo zjkItemExtreation = zjkItemExtreationMapper.selectVoOne(lambdaQuery);
            expertCount = zjkItemExtreation.getExtractionCount();
            expertSum = zjkItemExtreation.getExpertSum();

            LambdaQueryWrapper<ZjkReviewPhase> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(ZjkReviewPhase::getItemExtreationId, zjkItemExtreation.getId());
            lambdaQueryWrapper.eq(ZjkReviewPhase::getEffective, 1);
            //根据id获取规则
            ZjkReviewPhaseVo zjkReviewPhaseVo = zjkReviewPhaseMapper.selectVoOne(lambdaQueryWrapper);

            // 是否为补抽的重抽
            if (zjkReviewPhaseVo.getSource() > 0) {
                supplementCause = 1;
                zjkProjectExpertItemBo.setRedraw(true);
                zjkProjectExpertItemBo.setSupplementNum(zjkReviewPhaseVo.getPlannedIntake());
                if (zjkReviewPhaseVo.getExtractArea() != null) {
                    parenId = zjkReviewPhaseVo.getParentId();
                    if (zjkReviewPhaseVo.getExtractArea() != null) {
                        zjkProjectExpertItemBo.setExtractArea(Splitter.on(",").splitToList(zjkReviewPhaseVo.getExtractArea()));
                    }
                    List<String> extractArea = zjkProjectExpertItemBo.getExtractArea();
                    String s = extractArea.get(extractArea.size() - 1);
                    zjkProjectExpertItemBo.setProvinces(s);
                }
            }
            // 规则
            zjkProjectExpertItemBo.setCount(zjkReviewPhaseVo.getPlannedIntake());
            zjkProjectExpertItemBo.setMode(zjkReviewPhaseVo.getExtractionMode());
            // todo 回避专家冲突
            String avoidanceExpert1 = zjkReviewPhaseVo.getAvoidanceExpert();
            List<Long> avoidanceExperts = new ArrayList<>();
            // 回避专家
            if (avoidanceExpert1 != null && avoidanceExpert1.length() > 2) {
                avoidanceExperts = Arrays.stream(avoidanceExpert1.substring(1, avoidanceExpert1.length() - 1).split(","))
                    .map(str -> Long.valueOf(str.trim()))
                    .collect(Collectors.toList());
            }
            // 回避专家
            zjkProjectExpertItemBo.setExpertIds(avoidanceExperts);
            // 回避单位
            String avoidanceUnit = zjkReviewPhaseVo.getAvoidanceUnit();
            List<String> avoidanceUnits = new ArrayList<>();
            if (avoidanceUnit != null && avoidanceUnit.length() > 2) {
                avoidanceUnit = avoidanceUnit.replace("[", "").replace("]", "");
                String[] elements = avoidanceUnit.split(", ");

                // 将数组转换为 List
                List<String> workList = Arrays.asList(elements);
                zjkProjectExpertItemBo.setUnit(workList);

            }
            // 抽取限制
            String extractioRestriction = zjkReviewPhaseVo.getExtractioRestriction();
            List<Long> restrictioList = new ArrayList<>();
            if (extractioRestriction.length() > 2) {
                restrictioList = Arrays.stream(extractioRestriction.substring(1, extractioRestriction.length() - 1).split(","))
                    .map(str -> Long.valueOf(str.trim()))
                    .collect(Collectors.toList());
            }
            zjkProjectExpertItemBo.setExtractioRestrictio(restrictioList);
            //  回避专家冲突
            String avoidanceExpert = zjkReviewPhaseVo.getDesignatedNumber();//根据下面的setExpertsId 此处从规则VO取出指定专家
            List<Long> expertList = new ArrayList<>();
            if (avoidanceExpert != null && avoidanceExpert.length() > 3) {
                expertList = Arrays.stream(avoidanceExpert.substring(1, avoidanceExpert.length() - 1).split(","))
                    .map(str -> Long.valueOf(str.trim()))
                    .collect(Collectors.toList());
            }
            // 指定专家
            zjkProjectExpertItemBo.setExpertsId(expertList);

            zjkProjectExpertItemBo.setReviewSn(zjkReviewPhaseVo.getReviewSn());
            zjkProjectExpertItemBo.setReviewPlace(zjkReviewPhaseVo.getReviewPlace());
            zjkProjectExpertItemBo.setReviewTime(zjkReviewPhaseVo.getReviewTime());
            zjkProjectExpertItemBo.setItemid(zjkReviewPhaseVo.getItemId());
            // 每个领域需要抽多少人
            if (zjkReviewPhaseVo.getArea() != null && zjkReviewPhaseVo.getArea() != "") {
                String[] pairs = zjkReviewPhaseVo.getArea().split(",");
                Map<Long, Long> map = new HashMap<>();
                // 遍历拆分后的数组，将键值对添加到Map中
                for (String pair : pairs) {
                    String[] entry = pair.split("=");
                    map.put(Long.valueOf(entry[0]), Long.valueOf(entry[1]));
                }
                zjkProjectExpertItemBo.setAreaList(map);
            }
            // 指定的专家
            String designatedNumber = zjkReviewPhaseVo.getDesignatedNumber();
            List<Long> desList = new ArrayList<>();
            if (designatedNumber != null && designatedNumber.length() > 3) {
                desList = Arrays.stream(designatedNumber.substring(1, designatedNumber.length() - 1).split(","))
                    .map(str -> Long.valueOf(str.trim()))
                    .collect(Collectors.toList());
            }
            zjkProjectExpertItemBo.setExpertsId(desList);
            // false 不是补抽
            if (zjkProjectExpertItemBo.getRedraw() == null) {
                zjkProjectExpertItemBo.setRedraw(false);
            }
        }
        String mode = zjkProjectExpertItemBo.getMode();
        // 抽取的专家
        ZjkExpertItem zjkExpertItem = new ZjkExpertItem();
        zjkExpertItem.setItemId(zjkProjectExpertItemBo.getItemid());
        // 结果集
        ZjkItemExtreation zjkItemExtreation = new ZjkItemExtreation();
        // 抽取规则
        ZjkReviewPhase zjkReviewPhase = new ZjkReviewPhase();
        zjkReviewPhase.setReviewSn(zjkProjectExpertItemBo.getReviewSn());
        zjkReviewPhase.setReviewPlace(zjkProjectExpertItemBo.getReviewPlace());
        zjkReviewPhase.setReviewTime(zjkProjectExpertItemBo.getReviewTime());
        zjkReviewPhase.setItemId(zjkProjectExpertItemBo.getItemid());
        zjkReviewPhase.setPlannedIntake(zjkProjectExpertItemBo.getCount());
        zjkReviewPhase.setExtractionMode(zjkProjectExpertItemBo.getMode());
        zjkReviewPhase.setNoticeTime(zjkProjectExpertItemBo.getNoticeTime());

        StringBuilder stringBuilder = new StringBuilder();
        // 每个领域抽多少人
        if (zjkProjectExpertItemBo.getAreaList() != null && !zjkProjectExpertItemBo.getAreaList().isEmpty()) {
            zjkProjectExpertItemBo.getAreaList().forEach((key, value) -> stringBuilder.append(key).append("=").append(value).append(","));
        }
        if (stringBuilder != null && stringBuilder.length() != 0) {
            String result = stringBuilder.deleteCharAt(stringBuilder.length() - 1).toString();
            zjkReviewPhase.setArea(result);
        }
        if (zjkProjectExpertItemBo.getExtractioRestrictio() != null) {
            zjkReviewPhase.setExtractioRestriction(zjkProjectExpertItemBo.getExtractioRestrictio().toString());
        }
        if (zjkProjectExpertItemBo.getExpertIds() != null && zjkProjectExpertItemBo.getExpertIds().size() > 0) {
            zjkReviewPhase.setAvoidanceExpert(JSONUtil.toJsonStr(zjkProjectExpertItemBo.getExpertIds()));

        }
        if (zjkProjectExpertItemBo.getExpertsId().size() > 0) {
            zjkReviewPhase.setDesignatedNumber(JSONUtil.toJsonStr(zjkProjectExpertItemBo.getExpertsId()));
        }
        if (zjkProjectExpertItemBo.getUnit() != null) {
            zjkReviewPhase.setAvoidanceUnit(zjkProjectExpertItemBo.getUnit().toString());
        }
        if (zjkProjectExpertItemBo.getRedraw() == null || !zjkProjectExpertItemBo.getRedraw()) {
            zjkReviewPhase.setEffective(ReviewTypeEnum.REVIEW_LOSE_TYPE.getCode());
            zjkReviewPhaseMapper.insert(zjkReviewPhase);
            reviewId = zjkReviewPhase.getId();
        }

        List<Long> expertIds = new ArrayList<>();
        long redrawExpertId = 0;
        //补抽  屏蔽已抽专家
        if (zjkProjectExpertItemBo.getRedraw()) {
            expertCount++;
            // 获取补抽之前的规则id
            LambdaQueryWrapper<ZjkReviewPhase> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(ZjkReviewPhase::getReviewSn, zjkProjectExpertItemBo.getReviewSn());
            lambdaQueryWrapper.eq(ZjkReviewPhase::getItemId, zjkProjectExpertItemBo.getItemid());
            if (parenId != null) {
                lambdaQueryWrapper.eq(ZjkReviewPhase::getParentId, parenId)
                    // 按照更新时间降序排序
                    .orderByDesc(ZjkReviewPhase::getCreateTime)
                    // 限制结果为1条，即最新的一条
                    .last("LIMIT 1");
            } else {
                lambdaQueryWrapper.eq(ZjkReviewPhase::getParentId, 0);
            }
//            lambdaQueryWrapper.eq(ZjkReviewPhase::getEffective, 1);
            lambdaQueryWrapper.orderBy(true, false, ZjkReviewPhase::getCreateTime);
            lambdaQueryWrapper.last("LIMIT 1");
            // 获取补抽之前的规则
            ZjkReviewPhase convert = zjkReviewPhaseMapper.selectOne(lambdaQueryWrapper);
            parenId = convert.getId();
            LambdaQueryWrapper<ZjkReviewPhase> lambdaQueryWrappers = new LambdaQueryWrapper<>();
            lambdaQueryWrappers.eq(ZjkReviewPhase::getReviewSn, zjkProjectExpertItemBo.getReviewSn());
            lambdaQueryWrappers.eq(ZjkReviewPhase::getItemId, zjkProjectExpertItemBo.getItemid());
            lambdaQueryWrappers.eq(ZjkReviewPhase::getParentId, 0);
            lambdaQueryWrappers.orderBy(true, false, ZjkReviewPhase::getCreateTime);
            lambdaQueryWrappers.last("LIMIT 1");
            // 获取第一次的规则
            ZjkReviewPhase converts = zjkReviewPhaseMapper.selectOne(lambdaQueryWrappers);
            expertSum = converts.getPlannedIntake();
            zjkReviewPhase.setParentId(parenId);
            if (zjkProjectExpertItemBo.getExtractArea() != null && zjkProjectExpertItemBo.getExtractArea().size() > 0) {
                String stringFromList = String.join(",", zjkProjectExpertItemBo.getExtractArea());
                zjkReviewPhase.setExtractArea(stringFromList);
            }
            zjkReviewPhase.setPlannedIntake(zjkProjectExpertItemBo.getSupplementNum());
            zjkReviewPhase.setEffective(ReviewTypeEnum.REVIEW_LOSE_TYPE.getCode());
            zjkReviewPhase.setSource(ExpertItemTypeEnum.EXPERTITEM_REDRAW_TYPE.getCode());
            // 新增补抽的规则
            zjkReviewPhaseMapper.insert(zjkReviewPhase);

            reviewId = zjkReviewPhase.getId();
            ZjkReviewPhase zjkReviewPhases = new ZjkReviewPhase();
            if (convert.getParentId() != 0L) {
                zjkReviewPhases.setEffective(ReviewTypeEnum.REVIEW_NOT_TYPE.getCode());
            }
            zjkReviewPhases.setCauseRepum(zjkProjectExpertItemBo.getCauseRepum());
            zjkReviewPhases.setId(convert.getId());
            // 补抽的规则的新纪录 需要把之前的设置为无效
            zjkReviewPhaseMapper.updateById(zjkReviewPhases);
            redrawExpertId = zjkReviewPhase.getId();

            LambdaQueryWrapper<ZjkExpertItem> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(zjkProjectExpertItemBo.getId() != null, ZjkExpertItem::getReviewId, zjkProjectExpertItemBo.getId());
            // 只查询确认发送过信息的专家 为已抽过的
            wrapper.eq(ZjkExpertItem::getIsSure, 1);
            List<ZjkExpertItem> zjkExpertItems = baseMapper.selectList(wrapper);
            expertIds = zjkProjectExpertItemBo.getExpertIds();
            if (expertIds == null) {
                expertIds = new ArrayList<>();
            }
            List<Long> idList = zjkExpertItems.stream()
                .map(ZjkExpertItem::getExpertId)
                .collect(Collectors.toList());
            expertIds.addAll(idList);
            zjkProjectExpertItemBo.setExpertIds(expertIds);
            //设置抽取区域
            if (zjkProjectExpertItemBo.getExtractArea() != null && zjkProjectExpertItemBo.getExtractArea().size() > 0) {
                List<String> extractArea = zjkProjectExpertItemBo.getExtractArea();
                String s = extractArea.get(extractArea.size() - 1);
                zjkProjectExpertItemBo.setProvinces(s);
            }
        }
        List<ZjkReviewPhaseVo> zjkReviewPhaseVos = new ArrayList<>();

        if (zjkProjectExpertItemBo.getRedraw()) {
            Long rown = 1L;
            zjkReviewPhaseVos = zjkReviewPhaseMapper.selectVoListByZjkItemExpertBylast(zjkProjectExpertItemBo.getItemid(), zjkProjectExpertItemBo.getReviewSn(), rown, 1);
        } else {
            Long rown = 0L;
            zjkReviewPhaseVos = zjkReviewPhaseMapper.selectVoListByZjkItemExpert(zjkProjectExpertItemBo.getItemid(), zjkProjectExpertItemBo.getReviewSn(), rown, null);
        }

        Set<Long> list = zjkReviewPhaseVos.stream().map(ZjkReviewPhaseVo::getId).collect(Collectors.toSet());
        // 需要剔除的集合
        Set<ZjkExpertItem> remoZjkExpertItems = new HashSet<>();
        if (list != null && list.size() > 0 && zjkProjectExpertItemBo.getRedraw() && parenId != null) {
            LambdaQueryWrapper<ZjkExpertItem> lambdaQueryWrapper = new LambdaQueryWrapper();
            lambdaQueryWrapper.in(ZjkExpertItem::getReviewId, list);
            lambdaQueryWrapper.eq(ZjkExpertItem::getLeaveStatus, 0);
            lambdaQueryWrapper.notIn(ZjkExpertItem::getAcceptStatus, 2, 4);
            Long reviewId1 = reviewId;
            // 获取 请假状态为未请假    接收状态为  接受 未接受
            List<ZjkExpertItem> zjkExpertItems = baseMapper.selectList(lambdaQueryWrapper);
            remoZjkExpertItems.addAll(zjkExpertItems);
        }
        int sum = 0;
        Set<ZjkExpertItem> zjkExpertItems = new HashSet<>();
        //记录抽取条件信息
        switch (mode) {
            // 指定
            case "appoint":
                List<Long> expertIds1 = zjkProjectExpertItemBo.getExpertsId();
                //校验是否被抽取
                if (remoZjkExpertItems != null && remoZjkExpertItems.size() > 0) {
                    Set<Long> collect = remoZjkExpertItems.stream().map(ZjkExpertItem::getExpertId).collect(Collectors.toSet());
                    for (Long l : expertIds1) {
                        if (collect.contains(l)) {
                            ZjkExpert zjkExpert = zjkExpertMapper.selectById(l);
                            throw new ServiceException(zjkExpert.getExpertName() + ":  已被抽取");
                        }
                    }
                }
                //黑名单和抽取记录得指定校验
                blacklistCheck(expertIds1);
                if (parenId != null) {
                    // 补抽的请假逻辑校验
                    leaveDenialCheck(expertIds1, parenId);
                }
                if (expertIds1 == null || expertIds1.size() <= 0) {
                    throw new ServiceException("未指定专家，无法指定抽取");
                }


                //校验指定专家是否在同一天有评审项目
                //List<ZjkExpertItem> zjkExpertItems1 = baseMapper.selectList(new LambdaQueryWrapper<ZjkExpertItem>()
                //    .in(ZjkExpertItem::getExpertId, expertIds1)
                //    .eq(ZjkExpertItem::getItemId, zjkProjectExpertItemBo.getItemid()));
                //if (zjkExpertItems1 != null && zjkExpertItems1.size() > 0) {
                //    List<Long> collect = zjkExpertItems1.stream()
                //        .filter(item -> item.getIsSure().equals(1))
                //        .map(ZjkExpertItem::getExpertId)
                //        .collect(Collectors.toList());
                //    if (collect != null && collect.size() > 0) {
                //        List<ZjkExpert> zjkExperts = zjkExpertMapper.selectByIds(collect);
                //        List<String> collect1 = zjkExperts.stream().map(ZjkExpert::getExpertName).collect(Collectors.toList());
                //        throw new ServiceException(collect1 + "： 存在未评审完成项目不可指定");
                //    }
                //}
                //获取专家id
                LambdaQueryWrapper<ZjkExpert> lambdaQueryWrapper = new LambdaQueryWrapper();
                lambdaQueryWrapper.in(ZjkExpert::getExpertId, expertIds1);
                if (zjkProjectExpertItemBo.getId() == null || zjkProjectExpertItemBo.getRedraw()) {
                    //获取抽取过的专家
                    redrawExpertId = zjkReviewPhase.getId();
                    LambdaQueryWrapper<ZjkReviewPhase> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(ZjkReviewPhase::getParentId, 0)
                        .eq(ZjkReviewPhase::getItemId, zjkReviewPhase.getItemId())
                        .eq(ZjkReviewPhase::getReviewSn, zjkReviewPhase.getReviewSn());
                    // 补抽的指定抽取  获取第一次的抽取规则
                    List<ZjkReviewPhase> zjkReviewPhase1 = zjkReviewPhaseMapper.selectList(wrapper);
                    Set<Long> collect1 = zjkReviewPhase1.stream().map(ZjkReviewPhase::getId).collect(Collectors.toSet());
                    LambdaQueryWrapper<ZjkExpertItem> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
                    if (collect1 != null && collect1.size() > 0) {
                        lambdaQueryWrapper1.in(ZjkExpertItem::getReviewId, collect1);
                        lambdaQueryWrapper1.eq(ZjkExpertItem::getLeaveStatus, 1);
                        // 获取已经请假的专家
                        List<ZjkExpertItem> zjkExpertItems2 = baseMapper.selectList(lambdaQueryWrapper1);
                        List<Long> collect = zjkExpertItems2.stream().map(ZjkExpertItem::getExpertId).collect(Collectors.toList());
                        zjkProjectExpertItemBo.setExpertIds(collect);
                        for (Long l : collect) {
                            if (zjkProjectExpertItemBo.getExpertsId().contains(l)) {
                                ZjkExpert zjkExpert = zjkExpertMapper.selectById(l);
                                throw new ServiceException(zjkExpert.getExpertName() + "专家已请假");
                            }
                        }
                    }
                }
                if (zjkProjectExpertItemBo.getExpertIds() != null && zjkProjectExpertItemBo.getExpertIds().size() > 0) {
                    lambdaQueryWrapper.notIn(ZjkExpert::getExpertId, zjkProjectExpertItemBo.getExpertIds());
                }
                if (zjkProjectExpertItemBo.getUnit() != null && zjkProjectExpertItemBo.getUnit().size() > 0) {
                    lambdaQueryWrapper.notIn(ZjkExpert::getWorkUnit, zjkProjectExpertItemBo.getUnit());
                }
                lambdaQueryWrapper.eq(ZjkExpert::getStatus, ZjkExpertTypeEnum.NORMAL.getCode());
                // 查询有效专家
                List<ZjkExpertVo> zjkExpertVos = zjkExpertMapper.selectVoList(lambdaQueryWrapper);
                // todo 需要加一个 年检未通过的校验异常
                if (zjkExpertVos == null || zjkExpertVos.size() == 0 || zjkExpertVos.size() < expertIds1.size()) {
                    Set<Long> collect = zjkExpertVos.stream().map(ZjkExpertVo::getExpertId).collect(Collectors.toSet());
                    expertIds1.removeAll(collect);
                    List<ZjkExpert> zjkExperts = zjkExpertMapper.selectByIds(expertIds1);
                    Set<String> collect1 = zjkExperts.stream().map(ZjkExpert::getExpertName).collect(Collectors.toSet());
                    throw new ServiceException(collect1 + "：专家已被抽取无法选择");
                }
                for (ZjkExpertVo experId : zjkExpertVos) {
                    zjkExpertItem = new ZjkExpertItem();
                    zjkExpertItem.setExpertId(experId.getExpertId());
                    zjkExpertItem.setItemId(zjkProjectExpertItemBo.getItemid());
                    if (reviewId == null) {
                        zjkExpertItem.setReviewId(zjkReviewPhase.getId());
                        reviewId = zjkReviewPhase.getId();
                    } else {
                        zjkExpertItem.setReviewId(reviewId);
                    }
                    //部门id
                    UserVo userVo = baseMapper.selectUser(experId.getExpertId());
                    if (userVo != null) {
                        zjkExpertItem.setUserId(experId.getUserId());
                        zjkExpertItem.setDeptId(userVo.getDeptId());
                    }
                    zjkExpertItems.add(zjkExpertItem);
                }
                break;
            // 随机抽取
            case "random":
                zjkProjectExpertItemBo.setZjkReviewPhase(zjkReviewPhase);
                // 随机抽取获取满足条件的专家 id
                List<Long> randomed = random(zjkProjectExpertItemBo, remoZjkExpertItems,new ArrayList<>());
                if (CollectionUtil.isEmpty(randomed)) {
                    //抽取失败
                    throw new ServiceException("抽取失败");
                }
                //获取专家id
                LambdaQueryWrapper<ZjkExpert> lambda = new LambdaQueryWrapper();
                lambda.in(ZjkExpert::getExpertId, randomed);
                lambda.eq(ZjkExpert::getStatus, ZjkExpertTypeEnum.NORMAL.getCode());
                if (zjkProjectExpertItemBo.getExpertIds() != null && zjkProjectExpertItemBo.getExpertIds().size() > 0) {
                    lambda.notIn(ZjkExpert::getExpertId, zjkProjectExpertItemBo.getExpertIds());
                }
                if (zjkProjectExpertItemBo.getUnit() != null && zjkProjectExpertItemBo.getUnit().size() > 0) {
                    lambda.notIn(ZjkExpert::getWorkUnit, zjkProjectExpertItemBo.getUnit());
                }
                if (zjkProjectExpertItemBo.getProvinces() != null) {
                    if (zjkProjectExpertItemBo.getExtractArea().size() == 1) {
                        lambda.eq(ZjkExpert::getProvince, zjkProjectExpertItemBo.getProvinces());
                    }
                    if (zjkProjectExpertItemBo.getExtractArea().size() == 2) {
                        lambda.eq(ZjkExpert::getCity, zjkProjectExpertItemBo.getProvinces());
                    }
                    if (zjkProjectExpertItemBo.getExtractArea().size() == 3) {
                        lambda.eq(ZjkExpert::getArea, zjkProjectExpertItemBo.getProvinces());
                    }
                }
                List<ZjkExpertVo> lambdas = zjkExpertMapper.selectVoList(lambda);
                if (lambdas.size() < randomed.size()) {
                    List<Long> collect2 = lambdas.stream().map(ZjkExpertVo::getExpertId).collect(Collectors.toList());
                    randomed.removeAll(collect2);
                    List<ZjkExpert> zjkExperts = zjkExpertMapper.selectByIds(randomed);
                    List<String> collect = zjkExperts.stream().map(ZjkExpert::getExpertName).collect(Collectors.toList());
                    throw new ServiceException(collect + "：状态异常，请重新指定");
                }
                for (ZjkExpertVo experId : lambdas) {
                    zjkExpertItem = new ZjkExpertItem();
                    zjkExpertItem.setExpertId(experId.getExpertId());
                    zjkExpertItem.setItemId(zjkProjectExpertItemBo.getItemid());
                    if (reviewId == null) {
                        zjkExpertItem.setReviewId(zjkReviewPhase.getId());
                        reviewId = zjkReviewPhase.getId();
                    } else {
                        zjkExpertItem.setReviewId(reviewId);
                    }
                    if (zjkProjectExpertItemBo.getRedraw()) {
                        zjkExpertItem.setReviewId(redrawExpertId);
                    }
                    //部门id
                    UserVo userVo = baseMapper.selectUser(experId.getExpertId());
                    if (userVo != null) {
                        zjkExpertItem.setUserId(experId.getUserId());
                        zjkExpertItem.setDeptId(userVo.getDeptId());
                    }
                    zjkExpertItems.add(zjkExpertItem);
                }
                break;
            // 随机加指定
            case "appointRandom":
                //黑名单和抽取记录得指定校验
                List<Long> expertsId = zjkProjectExpertItemBo.getExpertIds();
                blacklistCheck(zjkProjectExpertItemBo.getExpertsId());
                if (parenId != null) {
                    // 抽过的不能再抽
                    leaveDenialCheck(zjkProjectExpertItemBo.getExpertsId(), parenId);
                }
//                //校验指定专家是否在同一天有评审项目
//                List<ZjkExpertItem> expertItems = baseMapper.selectList(new LambdaQueryWrapper<ZjkExpertItem>()
//                    .in(ZjkExpertItem::getExpertId,zjkProjectExpertItemBo.getExpertsId())
//                    .eq(ZjkExpertItem::getItemId,zjkProjectExpertItemBo.getItemid()));
//
//                if (expertItems != null && expertItems.size() > 0) {
//                    List<Long> collect = expertItems.stream()
//                        .filter(item -> item.getIsSure().equals(1))
//                        .map(ZjkExpertItem::getExpertId)
//                        .collect(Collectors.toList());
//                    if (collect != null && collect.size() > 0) {
//                        List<ZjkExpert> zjkExperts = zjkExpertMapper.selectByIds(collect);
//                        List<String> collect1 = zjkExperts.stream().map(ZjkExpert::getExpertName).collect(Collectors.toList());
//                        throw new ServiceException(collect1 + "： 存在未评审完成项目不可指定");
//                    }
//                }

                if (zjkProjectExpertItemBo.getId() == null || zjkProjectExpertItemBo.getRedraw()) {
                    //获取抽取过的专家
                    redrawExpertId = zjkReviewPhase.getId();
                    LambdaQueryWrapper<ZjkReviewPhase> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(ZjkReviewPhase::getParentId, 0)
                        .eq(ZjkReviewPhase::getItemId, zjkReviewPhase.getItemId())
                        .eq(ZjkReviewPhase::getReviewSn, zjkReviewPhase.getReviewSn());
                    // 获取第一次的抽取规则
                    List<ZjkReviewPhase> zjkReviewPhase1 = zjkReviewPhaseMapper.selectList(wrapper);
                    Set<Long> collect1 = zjkReviewPhase1.stream().map(ZjkReviewPhase::getId).collect(Collectors.toSet());
                    LambdaQueryWrapper<ZjkExpertItem> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
                    if (collect1 != null && collect1.size() > 0) {
                        lambdaQueryWrapper1.in(ZjkExpertItem::getReviewId, collect1);
                        lambdaQueryWrapper1.eq(ZjkExpertItem::getLeaveStatus, 1);
                        List<ZjkExpertItem> zjkExpertItems2 = baseMapper.selectList(lambdaQueryWrapper1);
                        List<Long> collect = zjkExpertItems2.stream().map(ZjkExpertItem::getExpertId).collect(Collectors.toList());
                        zjkProjectExpertItemBo.setExpertIds(collect);
                        for (Long l : collect) {
                            if (zjkProjectExpertItemBo.getExpertsId().contains(l)) {
                                ZjkExpert zjkExpert = zjkExpertMapper.selectById(l);
                                throw new ServiceException(zjkExpert.getExpertName() + "专家已请假");
                            }
                        }
                    }
                }
                if (expertsId == null) {
                    expertsId = new ArrayList<>();
                }
                Integer count = zjkProjectExpertItemBo.getCount();
//                if (zjkProjectExpertItemBo.getId() != null) {
                zjkProjectExpertItemBo.setCount(zjkProjectExpertItemBo.getCount() - zjkProjectExpertItemBo.getExpertsId().size());
//                } else {
//                    zjkProjectExpertItemBo.setCount(zjkProjectExpertItemBo.getCount() - sum);
//                }
                List<Long> nameList = new ArrayList<>();
                nameList.addAll(zjkProjectExpertItemBo.getExpertsId());
                if (expertsId != null) {
                    nameList.addAll(expertsId);
                }
                //指定专家是否在回避单位中
                if (nameList != null && nameList.size() > 0 && zjkProjectExpertItemBo.getUnit() != null && zjkProjectExpertItemBo.getUnit().size() > 0) {
                    LambdaQueryWrapper<ZjkExpert> lambd = new LambdaQueryWrapper();
                    lambd.in(ZjkExpert::getExpertId, nameList);
                    lambd.in(ZjkExpert::getWorkUnit, zjkProjectExpertItemBo.getUnit());
                    List<ZjkExpertVo> lambds = zjkExpertMapper.selectVoList(lambd);
                    Set<String> collect = lambds.stream().map(ZjkExpertVo::getExpertName).collect(Collectors.toSet());
                    if (collect != null && collect.size() > 0) {
                        throw new ServiceException(collect.toString() + "在回避单位中，无法指定");
                    }
                }
                //添加之前抽到过的专家
                Set<Long> collect = remoZjkExpertItems.stream().map(ZjkExpertItem::getExpertId).collect(Collectors.toSet());
                if (collect != null && collect.size() > 0) {
                    nameList.addAll(collect);
                }
                zjkProjectExpertItemBo.setExpertIds(nameList);
                List<Long> specifiedExpertList = zjkProjectExpertItemBo.getExpertsId();
                List<Long> random = random(zjkProjectExpertItemBo, remoZjkExpertItems,specifiedExpertList);
                if (random == null) {
                    //抽取失败
                    throw new ServiceException("抽取失败");
                }
                List<Long> expertsId1 = zjkProjectExpertItemBo.getExpertsId();
                expertsId1.addAll(random);
                //获取专家id
                LambdaQueryWrapper<ZjkExpert> lambd = new LambdaQueryWrapper();
                lambd.in(ZjkExpert::getExpertId, expertsId1);
                lambd.eq(ZjkExpert::getStatus, ZjkExpertTypeEnum.NORMAL.getCode());
                if (zjkProjectExpertItemBo.getUnit() != null && zjkProjectExpertItemBo.getUnit().size() > 0) {
                    lambd.notIn(ZjkExpert::getWorkUnit, zjkProjectExpertItemBo.getUnit());
                }
                List<ZjkExpertVo> lambds = zjkExpertMapper.selectVoList(lambd);
                for (ZjkExpertVo experId : lambds) {
                    zjkExpertItem = new ZjkExpertItem();
                    zjkExpertItem.setExpertId(experId.getExpertId());
                    zjkExpertItem.setItemId(zjkProjectExpertItemBo.getItemid());
                    if (reviewId == null) {
                        zjkExpertItem.setReviewId(zjkReviewPhase.getId());
                        reviewId = zjkReviewPhase.getId();
                    } else {
                        zjkExpertItem.setReviewId(reviewId);
                    }
                    //部门id
                    UserVo userVo = baseMapper.selectUser(experId.getExpertId());
                    if (userVo != null) {
                        zjkExpertItem.setUserId(experId.getUserId());
                        zjkExpertItem.setDeptId(userVo.getDeptId());
                    }
                    zjkExpertItems.add(zjkExpertItem);
                    zjkProjectExpertItemBo.setCount(count);
                }
                zjkExpertItem.setItemId(zjkProjectExpertItemBo.getItemid());
                break;
            default:
                throw new IllegalArgumentException("抽取失败");
        }
        //修改抽取时间，抽取次数，抽取人数，生成抽取流水号，抽取状态，抽取人
        LambdaQueryWrapper<ZjkItemExtreation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(zjkProjectExpertItemBo.getItemid() != null, ZjkItemExtreation::getItemId, zjkProjectExpertItemBo.getItemid());
        //已抽取人数
        zjkItemExtreation.setExtractedSum(sum);
        // 抽取人
        zjkItemExtreation.setExtractionUser(LoginHelper.getUsername());
        //根据项目获取关联id
        LambdaQueryWrapper<ZjkExpertItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(zjkProjectExpertItemBo.getItemid() != null, ZjkExpertItem::getItemId, zjkProjectExpertItemBo.getItemid());
        //补抽把之前得记录得专家拿出来放入新规则
        if (zjkProjectExpertItemBo.getRedraw() && parenId != null) {
            //设置补抽数据来源
            zjkExpertItems.forEach(item -> {
                item.setIsSource(ExpertItemTypeEnum.EXPERTITEM_REDRAW_TYPE.getCode());
                item.setAcceptStatus(String.valueOf(ExpertItemTypeEnum.EXPERTITEM_CANCEL_TYPE.getCode()));
                //2024/12/4 add操作 重抽时改变zjkExpertItem 记录的接受状态为重抽(2)  借用枚举内的2
                item.setExtractionStatus(ExpertItemTypeEnum.EXPERTITEM_DOWN_TYPE.getCode());
            });
            Long reviewId1 = reviewId;
            remoZjkExpertItems.forEach(item -> item.setId(null));
            remoZjkExpertItems.forEach(item -> item.setReviewId(reviewId1));
            zjkExpertItems.addAll(remoZjkExpertItems);
        } else {
            // todo 专家抽取抽取后默认状态为 预抽取
            zjkExpertItems.forEach(item -> {
                item.setAcceptStatus(String.valueOf(ExpertItemTypeEnum.EXPERTITEM_CANCEL_TYPE.getCode()));
                //2024/12/3 add操作 重抽时改变zjkExpertItem 记录的接受状态为重抽(2)  借用枚举内的2
                item.setExtractionStatus(ExtractionStautsEnum.DRAW_AGAIN.getCode());
            });
        }
        //将指定的专家和项目进行绑定
        sum = zjkExpertItems.size();
        baseMapper.insertBatch(zjkExpertItems);

        int status = 0;
        if (zjkProjectExpertItemBo.getCount() <= sum) {
            status = ItemExpertTypeEnum.EXTRACTION_SUCCESS_TYPE.getCode();
//            zjkItemExtreation.setExtractionStatus(ItemExpertTypeEnum.EXTRACTION_SUCCESS_TYPE.getCode());
        } else {
            status = ItemExpertTypeEnum.EXTRACTION_PARTIAL_TYPE.getCode();
//            zjkItemExtreation.setExtractionStatus(ItemExpertTypeEnum.EXTRACTION_PARTIAL_TYPE.getCode());
        }
        ZjkItemExtreation zjkItemExtreationVo1 = new ZjkItemExtreation();
        if (zjkProjectExpertItemBo.getItemExtreationId() != null) {
            zjkItemExtreationVo1 = zjkItemExtreationMapper.selectOne(new LambdaQueryWrapper<ZjkItemExtreation>().eq(ZjkItemExtreation::getId, zjkProjectExpertItemBo.getItemExtreationId()));

        } else {
            zjkItemExtreationVo1 = zjkItemExtreationMapper.selectById(zjkProjectExpertItemBo.getId());
        }
        if (zjkItemExtreationVo1 != null) {
            zjkItemExtreation.setId(zjkItemExtreationVo1.getId());
        }
        //重抽 补抽
        if (zjkItemExtreationVo1 != null || zjkProjectExpertItemBo.getRedraw()) {
            //修改抽取条件表
            LambdaQueryWrapper<ZjkReviewPhase> zjkReviewPhaseAllQueryWrapper = new LambdaQueryWrapper();
            zjkReviewPhaseAllQueryWrapper.eq(ZjkReviewPhase::getItemId, zjkProjectExpertItemBo.getItemid());
            zjkReviewPhaseAllQueryWrapper.eq(ZjkReviewPhase::getReviewSn, zjkProjectExpertItemBo.getReviewSn());
            Long finalParenId = parenId;
            zjkReviewPhaseAllQueryWrapper.eq(parenId != null, ZjkReviewPhase::getId, parenId)
                .or(i -> i.eq(ZjkReviewPhase::getParentId, finalParenId));
            //修改父id和谷子额为有效的数据为失效
            ZjkReviewPhase zjkReviewPhase1 = new ZjkReviewPhase();
            zjkReviewPhaseAllQueryWrapper.eq(ZjkReviewPhase::getEffective, ReviewTypeEnum.REVIEW_LOSE_TYPE.getCode());
            zjkReviewPhase1.setEffective(ReviewTypeEnum.REVIEW_NOT_TYPE.getCode());
            //修改父id和谷子额为有效的数据为失效
            zjkReviewPhaseMapper.update(zjkReviewPhase1, zjkReviewPhaseAllQueryWrapper);
            ZjkItemExtreation ItemExtreation = zjkItemExtreationMapper.selectById(zjkProjectExpertItemBo.getId());
            if (ItemExtreation == null) {
                LambdaQueryWrapper<ZjkItemExtreation> zjkItemExtreationLambdaQueryWrapper = new LambdaQueryWrapper<>();
                zjkItemExtreationLambdaQueryWrapper.eq(ZjkItemExtreation::getReviewId, parenId);
                ItemExtreation = zjkItemExtreationMapper.selectOne(zjkItemExtreationLambdaQueryWrapper);
            }

            ZjkReviewPhase zjkReview = new ZjkReviewPhase();
            zjkReview.setId(reviewId);
            zjkReview.setEffective(ReviewTypeEnum.REVIEW_NOT_TYPE.getCode());
            zjkReview.setCauseRepum(zjkProjectExpertItemBo.getCauseRepum());
            //修改之前的规则
            zjkReviewPhaseMapper.updateById(zjkReview);
            if (status == 2) {
                LambdaQueryWrapper<ZjkReviewPhase> wrapper1 = new LambdaQueryWrapper();
                wrapper1.eq(ZjkReviewPhase::getId, reviewId);
                zjkReviewPhase1.setEffective(ReviewTypeEnum.REVIEW_LOSE_TYPE.getCode());
                zjkReviewPhase1.setId(null);
                zjkReviewPhaseMapper.update(zjkReviewPhase1, wrapper1);
            }
//            zjkReviewPhaseVos = zjkReviewPhaseMapper.selectUpdateZjkItemExpert(zjkProjectExpertItemBo.getItemid(), zjkProjectExpertItemBo.getReviewSn());
//            list = zjkReviewPhaseVos.stream().map(ZjkReviewPhaseVo::getId).collect(Collectors.toSet());
            // 抽取次数修改
            zjkItemExtreation.setExtractionCount(zjkItemExtreationVo1.getExtractionCount() + 1);
//            zjkItemExtreation.setExtractionStatus(status);
            //修改抽取时间
            zjkItemExtreation.setExtractionTime(new Date());
            zjkItemExtreation.setItemId(zjkReviewPhase.getItemId());
            zjkItemExtreation.setExpertSum(zjkProjectExpertItemBo.getCount());
            zjkItemExtreation.setExtractedSum(sum);
            //生成抽取流水号
//            zjkItemExtreation.setExtractionSn("LSH" + System.currentTimeMillis());
//            zjkItemExtreation.setExtractionCount(expertCount + 1);
            zjkItemExtreation.setExtractionStatus(ItemExpertTypeEnum.EXTRACTION_SUCCESS_TYPE.getCode());
            zjkItemExtreationMapper.updateById(zjkItemExtreation);
            zjkReviewPhase.setItemExtreationId(zjkItemExtreationVo1.getId());
            zjkReviewPhaseMapper.updateById(zjkReviewPhase);
            return zjkItemExtreation.getId();
        } else {
            //生成抽取流水号
            zjkItemExtreation.setExtractionSn("LSH" + System.currentTimeMillis());
            zjkItemExtreation.setItemId(zjkProjectExpertItemBo.getItemid());
            zjkItemExtreation.setExpertSum(zjkProjectExpertItemBo.getCount());
            zjkItemExtreation.setExtractionCount(1);
//            zjkItemExtreation.setReviewId(zjkReviewPhase.getId());
            //修改抽取时间
            zjkItemExtreation.setExtractionTime(new Date());
            zjkItemExtreation.setExtractedSum(sum);
            zjkItemExtreation.setExtractionStatus(ItemExpertTypeEnum.EXTRACTION_SUCCESS_TYPE.getCode());
            zjkItemExtreationMapper.insert(zjkItemExtreation);
            zjkReviewPhase.setItemExtreationId(zjkItemExtreation.getId());
            zjkReviewPhaseMapper.updateById(zjkReviewPhase);
            return zjkItemExtreation.getId();
        }
    }

    @Override
    public List<ZjkExpertVo> concatenated(String name) {

        //获取字典中的所有领域名称
        LambdaQueryWrapper<ZjkExpert> lambdaQueryWrapper = new LambdaQueryWrapper();
        if (name != null) {
            lambdaQueryWrapper.like(ZjkExpert::getExpertName, name);
        }
        lambdaQueryWrapper.eq(ZjkExpert::getStatus, 2);
        List<ZjkExpertVo> zjkExpertVos = zjkExpertMapper.selectVoList(lambdaQueryWrapper);
        return zjkExpertVos;
    }


    @Override
    public List<ZjkExpertItemVo> getExpertByReviewId(Long reviewId) {
        LambdaQueryWrapper<ZjkExpertItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ZjkExpertItem::getReviewId, reviewId);
        return baseMapper.selectVoList(queryWrapper);
    }


    //获取所有单位列表
    @Override
    public Set<String> unitList(String name) {
        LambdaQueryWrapper<ZjkExpert> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StringUtils.isNotEmpty(name), ZjkExpert::getWorkUnit, name);
        List<ZjkExpertVo> zjkExpertVos = zjkExpertMapper.selectVoList(lambdaQueryWrapper);
        Set<String> collect = zjkExpertVos.stream().map(ZjkExpertVo::getWorkUnit).collect(Collectors.toSet());
        return collect;
    }

    //取消
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int cancel(ZjkProjectExpertItemBo bo) {
        //获取规则id
        ZjkItemExtreation zjkItemExtreation = zjkItemExtreationMapper.selectById(bo.getId());
        ZjkReviewPhase zjkReviewPhase = new ZjkReviewPhase();
        zjkReviewPhase.setId(zjkItemExtreation.getReviewId());
        zjkReviewPhase.setEffective(0);
        zjkReviewPhase.setCauseRepum(bo.getCauseRepum());
        ZjkReviewPhase zjkReviewPhase1 = zjkReviewPhaseMapper.selectById(bo.getReviewId());
        if (zjkReviewPhase1.getParentId() != 0) {
            //修改记录表状态
            zjkItemExtreation.setExtractionStatus(ItemExpertTypeEnum.EXTRACTION_PARTIAL_TYPE.getCode());
            Integer extractedSum = zjkItemExtreation.getExpertSum();
            Integer extractionCount = zjkReviewPhase1.getPlannedIntake();
            Integer i = extractedSum - extractionCount;
            zjkItemExtreation.setExtractedSum(i);
            zjkItemExtreationMapper.updateById(zjkItemExtreation);
        } else {
            //修改记录表状态
            zjkItemExtreation.setExtractionStatus(ItemExpertTypeEnum.EXTRACTION_PARTIAL_TYPE.getCode());
            Integer extractedSum = zjkItemExtreation.getExpertSum();
            Integer extractionCount = zjkReviewPhase1.getPlannedIntake();
            Integer i = extractedSum - extractionCount;
            zjkItemExtreation.setExtractedSum(i);
            zjkItemExtreationMapper.updateById(zjkItemExtreation);
        }
        // 获取规则下的专家信息
        List<ZjkExpertItem> zjkExpertItemList = baseMapper.selectList(new LambdaQueryWrapper<ZjkExpertItem>()
            .eq(ZjkExpertItem::getReviewId, bo.getReviewId()));
        // 遍历专家信息列表
        for (ZjkExpertItem item : zjkExpertItemList) {
            if (item.getIsSure() == 1) {
                continue;
            }
            item.setAcceptStatus(String.valueOf(ExpertItemTypeEnum.EXPERTITEM_CANCEL_TYPE.getCode()));
            //2024/12/3 add操作  取消时改变zjkExpertItem 记录的接受状态为取消(0)  借用枚举内的0
            item.setExtractionStatus(ExtractionStautsEnum.CANCEL.getCode());
            baseMapper.updateById(item);
        }

        return zjkReviewPhaseMapper.updateById(zjkReviewPhase);
    }

    @Override
    public List<ZjkExpertItemVo> expertTop5() {
        List<ZjkExpertItemVo> zjkExpertItemVos = baseMapper.expertTop5();
        if (CollectionUtil.isEmpty(zjkExpertItemVos)) {
            return new ArrayList<>();
        }
        List<Long> userIdList = zjkExpertItemVos.stream().map(ZjkExpertItemVo::getUserId).toList();
        List<ZjkExpertVo> zjkExpertVos = zjkExpertMapper.selectByUserIds(userIdList);
        if (CollectionUtil.isEmpty(zjkExpertVos)) {
            return new ArrayList<>();
        }
        Map<Long, ZjkExpertVo> userMap = zjkExpertVos.stream().collect(Collectors.toMap(ZjkExpertVo::getUserId, v -> v));
        for (ZjkExpertItemVo zjkExpertItemVo : zjkExpertItemVos) {
            Long userId = zjkExpertItemVo.getUserId();
            if (!userMap.containsKey(userId)) {
                continue;
            }
            ZjkExpertVo zjkExpertVo = userMap.get(userId);
            zjkExpertItemVo.setExpertName(zjkExpertVo.getExpertName());
        }
        return zjkExpertItemVos;
    }

    @Override
    public List<ZjkExpertItemVo> getByReviewId(Long reviewId) {
        // 查询专家项目信息
        LambdaQueryWrapper<ZjkExpertItem> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ZjkExpertItem::getReviewId, reviewId);
        List<ZjkExpertItemVo> zjkExpertItemList = baseMapper.selectVoList(wrapper);
        // 如果查询结果为空，直接返回空集合
        if (CollectionUtil.isEmpty(zjkExpertItemList)) {
            return List.of();
        }

        // 提取用户 ID 集合
        Set<Long> userIdSet = zjkExpertItemList.stream().map(ZjkExpertItemVo::getUserId).filter(Objects::nonNull).collect(Collectors.toSet());

        // 查询专家信息并构建映射
        Map<Long, ZjkExpertVo> userMap = zjkExpertMapper.selectByUserIds(userIdSet)
            .stream().collect(Collectors.toMap(ZjkExpertVo::getUserId, Function.identity(), (k1, k2) -> k1));

        // 提取专家 ID 集合
        Set<Long> expertSet = zjkExpertItemList.stream().map(ZjkExpertItemVo::getExpertId).filter(Objects::nonNull).collect(Collectors.toSet());

        // 查询专家专业信息并按 userId 分组
        Map<Long, List<ZjkExpertMajor>> zjkExpertMajorMap = zjkExpertMajorMapper.selectMajorList(expertSet)
            .stream().collect(Collectors.groupingBy(ZjkExpertMajor::getUserId));

        // 如果专家信息为空，直接返回原列表
        if (userMap.isEmpty()) {
            return zjkExpertItemList;
        }

        // 合并数据到 zjkExpertItemList
        zjkExpertItemList.forEach(vo -> {
            if (vo.getLeaveStatus().equals("1")) {
                vo.setAcceptStatus("3");
            }
            Long userId = vo.getUserId();
            // 设置专家基本信息
            ZjkExpertVo zjkExpertVo = userMap.get(userId);
            if (zjkExpertVo != null) {
                vo.setExpertName(zjkExpertVo.getExpertName());
                vo.setConcat(zjkExpertVo.getContact());
                vo.setWorkUnit(zjkExpertVo.getWorkUnit());
                vo.setDuty(zjkExpertVo.getDuty());
                vo.setPerformWorkName(zjkExpertVo.getPerformWorkId());
            }
            vo.setZjkExpertMajorList(zjkExpertMajorMap.getOrDefault(userId, List.of()));
        });
        return zjkExpertItemList;
    }

    //随机抽取
    public List<Long> random(ZjkProjectExpertItemBo zjkProjectExpertItemBo, Set<ZjkExpertItem> remoZjkExpertItems,List<Long> specifiedExpertList) {
        int count = 0;
        // 补抽人数逻辑
        if (zjkProjectExpertItemBo.getRedraw() && zjkProjectExpertItemBo.getSupplementNum() != null) {
            count = zjkProjectExpertItemBo.getCount();
            long expertsCout = 0;
            if (zjkProjectExpertItemBo.getExpertsId() == null) {
                expertsCout = 0;
            } else {
                expertsCout = zjkProjectExpertItemBo.getExpertsId().size();
            }
            zjkProjectExpertItemBo.setCount((int) (zjkProjectExpertItemBo.getSupplementNum() - expertsCout));
        }
        // 随机抽取专家的逻辑
        List<ZjkExpertVo> zjkExpertVos = zjkExpertService.queryByExpertltemList(zjkProjectExpertItemBo, zjkProjectExpertItemBo.getExtractioRestrictio(), zjkProjectExpertItemBo,remoZjkExpertItems,specifiedExpertList);
        log.info("排除条件后 查询专家结果集{}", zjkExpertVos);
        if (CollectionUtil.isEmpty(zjkExpertVos)) {
            log.info("不存在符合抽取条件的专家");
            throw new ServiceException("不存在符合抽取条件的专家");
        }
        // 打乱
        Collections.shuffle(zjkExpertVos);
        //符合领域得所有专家
        //List<ZjkExpertVo> zjkExpertVos1 = selectRandomly(zjkExpertVos, zjkProjectExpertItemBo.getExtractioRestrictio(), zjkProjectExpertItemBo,remoZjkExpertItems);
        //抽取限制 1.屏蔽个人信息中的所属单位，2.屏蔽同一天评审的专家 ，3.同一单位只抽取一个专家
        List<ZjkExpertVo> extractedExperts = extractExperts(zjkExpertVos, zjkProjectExpertItemBo.getExtractioRestrictio(), zjkProjectExpertItemBo);
        //if (extractedExperts == null && extractedExperts.size() > 0) {
        //    throw new ServiceException("暂无专家可用");
        //}
        List<Long> idSet = extractedExperts.stream()
            .map(ZjkExpertVo::getExpertId)
            .collect(Collectors.toList());
        if (zjkProjectExpertItemBo.getSupplementNum() != null) {
            zjkProjectExpertItemBo.setCount(count);
        }
        return idSet;
    }

    public List<ZjkExpertVo> selectRandomly(List<ZjkExpertVo> zjkExpertVos, List<Long> extractioRestrictio, ZjkProjectExpertItemBo zjkProjectExpertItemBo, Set<ZjkExpertItem> remoZjkExpertItems) {
        ArrayList<ZjkExpertVo> zjkExpertVos1 = new ArrayList<>();
        Map<String, Boolean> unitMap = new HashMap<>();//指定专家的单位
        List<String> expertCollect = new ArrayList<>();

        List<Long> experts = new ArrayList<>();
        if (extractioRestrictio.contains(1L)) {
            //获取同一天的评审的专家
            LambdaQueryWrapper<ZjkReviewPhase> queryWrapper = new LambdaQueryWrapper<>();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String format = simpleDateFormat.format(zjkProjectExpertItemBo.getReviewTime());
            queryWrapper.like(ZjkReviewPhase::getReviewTime, format);
//            queryWrapper.eq(ZjkReviewPhase::getEffective, 1);
            List<ZjkReviewPhaseVo> zjkProjectVos = zjkReviewPhaseMapper.selectVoList(queryWrapper);
            List<Long> idList = zjkProjectVos.stream()
                .map(ZjkReviewPhaseVo::getId)
                .collect(Collectors.toList());
            //获取对应被抽取到的专家
            if (idList != null && idList.size() > 0) {
                LambdaQueryWrapper<ZjkExpertItem> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.in(ZjkExpertItem::getReviewId, idList);
                lambdaQueryWrapper.eq(ZjkExpertItem::getIsSure, 1);
//                lambdaQueryWrapper.eq(ZjkExpertItem::getAcceptStatus, 1);
                List<ZjkExpertItem> zjkExpertItems1 = baseMapper.selectList(lambdaQueryWrapper);
                idList = zjkExpertItems1.stream()
                    .map(ZjkExpertItem::getExpertId)
                    .collect(Collectors.toList());
                if (idList != null && idList.size() > 0) {
                    experts.addAll(idList);
                }
            }
        }

        if (extractioRestrictio.contains(2L)) {
            //补抽是一筹专家的单位
            if (remoZjkExpertItems != null && remoZjkExpertItems.size() > 0) {
                Set<Long> collect1 = remoZjkExpertItems.stream().map(ZjkExpertItem::getExpertId).collect(Collectors.toSet());
                List<ZjkExpert> zjkExperts1 = zjkExpertMapper.selectByIds(collect1);
                Set<String> collect2 = zjkExperts1.stream().map(ZjkExpert::getWorkUnit).collect(Collectors.toSet());
                for (String s : collect2) {
                    unitMap.put(s, true);
                }
            }
            if (zjkProjectExpertItemBo.getExpertsId() != null && zjkProjectExpertItemBo.getExpertsId().size() > 0) {
                List<Long> boExpertsId = zjkProjectExpertItemBo.getExpertsId();
                List<ZjkExpert> zjkExperts = zjkExpertMapper.selectByIds(boExpertsId);
                Set<String> collect = zjkExperts.stream().map(ZjkExpert::getWorkUnit).collect(Collectors.toSet());
                for (String s : collect) {
                    unitMap.put(s, true);
                }
            }
        }
        Set<Long> collect = new HashSet<>();
        if (remoZjkExpertItems != null && remoZjkExpertItems.size() > 0) {
            Set<Long> collect1 = remoZjkExpertItems.stream().map(ZjkExpertItem::getExpertId).collect(Collectors.toSet());
            collect.addAll(collect1);
        }
        if (zjkExpertVos1 != null && zjkExpertVos1.size() > 0) {
            Set<Long> collect1 = zjkExpertVos1.stream().map(ZjkExpertVo::getExpertId).collect(Collectors.toSet());
            collect.addAll(collect1);
        }
        //抽取领域
        if (zjkProjectExpertItemBo.getAreaList() != null) {
            // 需要抽取的领域
            Map<Long, Long> area = zjkProjectExpertItemBo.getAreaList();
            // 循环符合条件的专家集合
            for (ZjkExpertVo allExpert : zjkExpertVos) {
                // 补抽屏蔽已抽专家
                if (collect != null && collect.size() > 0 && collect.contains(allExpert.getExpertId())) {
                    continue;
                }
                String performWorkId = allExpert.getPerformWorkId();
                if (performWorkId != null) {
                    Long[] parts = Arrays.stream(performWorkId.split(","))
                        .map(Long::valueOf) // 将每个字符串转换为 Long
                        .toArray(Long[]::new); // 转换为 Long 数组
                    // 当前专家的领域
                    List<Long> list = new ArrayList<>(Arrays.asList(parts));
                    // 循环规则中的领域 查看当前专家的领域中是否包含
                    for (Long performWork : area.keySet()) {
                        // 如果包含需要抽取的领域
                        if (list.contains(performWork)) {
                            // 是否满足条件
                            boolean canAdd = true;
                            if (extractioRestrictio.contains(3L)) {
                                ZjkProductVo zjkProductVo = zjkProductMapper.selectVoById(zjkProjectExpertItemBo.getItemid());
                                // 非本单位的专家
                                if (zjkProductVo != null && allExpert.getWorkUnit().equals(zjkProductVo.getProductUnit())) {
                                    canAdd = false;
                                }
                            }
                            // 同一单位只能抽取一位专家
                            if (extractioRestrictio.contains(2L)) {
                                if (expertCollect != null && expertCollect.size() > 0 && expertCollect.contains(allExpert.getWorkUnit())) {
                                    canAdd = false;
                                }
                                if (unitMap.containsKey(allExpert.getWorkUnit())) {
                                    canAdd = false;
                                } else {
                                    unitMap.put(allExpert.getWorkUnit(), true);
                                }
                            }
                            // 缺失项目开始时间也就是同一天评审的专家信息
                            if (extractioRestrictio.contains(1L)) {
                                // 屏蔽所有在这个时间参加项目的专家
                                if (experts.contains(allExpert.getExpertId())) {
                                    // 不满足条件
                                    canAdd = false;
                                }
                            }
                            // 专家存在需要抽取的规则 则获取规则中的人数是否大于 0
                            if (canAdd && area.get(performWork) > 0) {
                                // 添加满足条件的专家信息
                                zjkExpertVos1.add(allExpert);
                                // 领域内专家人数-1
                                long l = area.get(performWork) - 1;
                                area.put(performWork, l);
                                // 当前专家满图条件 跳出
                                break; // 跳出内层循环
                            }
                        }

                    }
                }
            }
            for (Map.Entry<Long, Long> entry : area.entrySet()) {
                if (entry.getValue() > 0) {
                    //获取领域信息
                    String name = zjkExpertMapper.selectDataWorkId(String.valueOf(entry.getKey()), LoginHelper.getTenantId());
                    throw new ServiceException(name + "领域下专家人数不满足抽取条件，请重新选择!");
                }
            }
        }
        return zjkExpertVos1;
    }

    //抽取限制 1.屏蔽个人信息中的所属单位，2.屏蔽同一天评审的专家 ，3.同一单位只抽取一个专家
    public List<ZjkExpertVo> extractExperts1(List<ZjkExpertVo> allExperts, List<Long> extractioRestrictio, ZjkProjectExpertItemBo bo, Set<ZjkExpertItem> remoZjkExpertItems) {
        //各阶段所需人数
        Map<Long, Long> areaMap = bo.getAreaList();
        Map<Long, List<ZjkExpertVo>> areaZjkExpertMap = new HashMap<>();
        for (Long area : areaMap.keySet()) {
            List<ZjkExpertVo> areaExpertList = allExperts.stream().filter(s -> null != s.getPerformWorkId() && s.getPerformWorkId().contains(area + "")).toList();
            areaZjkExpertMap.put(area, areaExpertList);
        }

        Map<Long, List<ZjkExpertVo>> sortedMap = areaZjkExpertMap.entrySet()
            .stream()
            .sorted(Comparator.comparingInt(entry -> entry.getValue().size()))
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (oldValue, newValue) -> oldValue,
                LinkedHashMap::new // 使用 LinkedHashMap 保持顺序
            ));
        log.info("按照阶段分组后的 专家集合{}", sortedMap);
        //最终返回的 专家
        List<ZjkExpertVo> resultExpertList = new ArrayList<>();

        //排除单位
        List<String> workUnitList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(remoZjkExpertItems)) {
            List<Long> redrawExpertIds = remoZjkExpertItems.stream().map(ZjkExpertItem::getExpertId).toList();
            List<ZjkExpert> redrawExpertIdLiat = zjkExpertMapper.selectByIds(redrawExpertIds);
            workUnitList.addAll(redrawExpertIdLiat.stream().map(ZjkExpert::getWorkUnit).toList());
            log.info("排除工作单位{}", redrawExpertIdLiat);
        }
        // 是否屏蔽同一单位
        boolean concurrence = extractioRestrictio.contains(2L);

        List<Long> expertList = new ArrayList<>();

        //循环  符合条件 最少的一组
        for (Long sorted : sortedMap.keySet()) {
            //排除重复专家

            //数据库查询 专家人数
            List<ZjkExpertVo> sortedList = sortedMap.get(sorted);

            //获取每个领域返回的 专家集合
            List<ZjkExpertVo> zjkExpertVoList = new ArrayList<>();
            List<ZjkExpertVo> remainderExperList = new ArrayList<>(sortedList);
            if (concurrence) {
                remainderExperList = sortedList.stream().filter(s -> !workUnitList.contains(s.getWorkUnit())).toList();
                log.info("屏蔽同单位条件，排除工作单位{}", remainderExperList);
            }
            remainderExperList = remainderExperList.stream().filter(s -> !expertList.contains(s.getExpertId())).toList();
            remainderExperList = new ArrayList<>(remainderExperList);
            //获取 此领域所需专家人数
            Long expertCount = areaMap.get(sorted);
            remainderExperList.sort(Comparator.comparingInt(expert -> getConflictCount(expert, sortedMap)));
            for (ZjkExpertVo zjkExpertVo : remainderExperList) {
                Long expertId = zjkExpertVo.getExpertId();
                if (expertList.contains(expertId)) {
                    continue;
                }
                if (expertCount <= remainderExperList.size()) {
                    //屏蔽同意单位
                    if (concurrence) {
                        //特殊情况  某一领域专家
                        boolean contains = workUnitList.contains(zjkExpertVo.getWorkUnit());
                        if (contains) {
                            continue;
                        }
                        workUnitList.add(zjkExpertVo.getWorkUnit());
                    }
                    expertList.add(expertId);
                    zjkExpertVoList.add(zjkExpertVo);
                }
                if (expertCount <= zjkExpertVoList.size()) {
                    break;
                }
            }

            //人数不足 移除
            if (expertCount > zjkExpertVoList.size()) {
                String name = zjkExpertMapper.selectDataWorkId(String.valueOf(sorted), LoginHelper.getTenantId());
                //// i 是当前 需要补全的专家
                //for (int j = i -1; j >= 0; j--) {
                //    //本次缺少人数 的领域
                //    Long sortedI = areaList.get(i);
                //    //获取 本次 缺少人数
                //    List<ZjkExpertVo> zjkExpertListI = resultMap.get(sorted);
                //    //获取上一次 的专家集
                //    Long sortedJ = areaList.get(j);
                //    //上一个领域的专家集合
                //    List<ZjkExpertVo> sortedListJ = sortedMap.get(sortedJ);
                //    //上个符合的专家集合
                //    List<ZjkExpertVo> previousList = sortedListJ.stream().filter(s -> s.getPerformWorkId().contains(sortedI + "")).toList();
                //    if (previousList.isEmpty()) {
                //        continue;
                //    }
                //    //上一个领域 包含 当前领域的专家，给上一个领域的 移出去，新增到 本领域中，  新增上一个领域的 专家，上一个领域专家为空，在获取上一个领域专家
                //    for (ZjkExpertVo zjkExpertVo : previousList) {
                //        zjkExpertVoList.add(zjkExpertVo);
                //        if (expertCount <= zjkExpertVoList.size()) {
                //            break;
                //        }
                //    }
                //    for (int k = j - 1; k >= 0; k--) {
                //
                //    }
                //    resultMap.put(sorted, zjkExpertVoList);
                //}
                throw new ServiceException(name + "领域下专家人数不满足抽取条件，请重新选择!");
            }
            //人数够了
            resultExpertList.addAll(zjkExpertVoList);
            log.info("按照条件抽取的专家{}", resultExpertList);
        }
        Collections.shuffle(allExperts, new Random());
        allExperts.removeAll(resultExpertList);
        log.info("剩余专家列表{}", allExperts);
        allExperts = allExperts.stream().filter(s -> !workUnitList.contains(s.getWorkUnit())).toList();
        Integer planCount = bo.getCount();
        log.info("需要专家数量{}", planCount);
        int count = planCount - resultExpertList.size();
        log.info("随机填充专家数量{}", count);
        if (allExperts.size() < count) {
            throw new ServiceException("专家人数不足！！！");
        }
        //抽完后 看人数，够了 不用随机增加
        if (count == 0) {
            return resultExpertList;
        }
        for (ZjkExpertVo allExpert : allExperts) {
            if (workUnitList.contains(allExpert.getWorkUnit())) {
                continue;
            }
            resultExpertList.add(allExpert);
            log.info("随机填充专家{}", planCount);
            if (concurrence) {
                workUnitList.add(allExpert.getWorkUnit());
                log.info("随机填充专家，新增排除单位{}", allExpert.getWorkUnit());
            }
            if (resultExpertList.size() >= planCount) {
                break;
            }
        }
        if (resultExpertList.size() < planCount) {
            throw new ServiceException("专家人数不足");
        }
        return resultExpertList;
    }

    private int getConflictCount(ZjkExpertVo expert, Map<Long, List<ZjkExpertVo>> areaToExperts) {
        return (int) areaToExperts.entrySet().stream()
            .filter(entry -> entry.getValue().contains(expert))
            .count();
    }

    //黑名单校验
    public void blacklistCheck(List<Long> zjkExpertVos) {
        LambdaQueryWrapper<ZjkCreditUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.ge(ZjkCreditUser::getRewardId, 4);
        lambdaQueryWrapper.in(ZjkCreditUser::getExpertId, zjkExpertVos);
        List<ZjkCreditUser> list = zjkCreditUserMapper.selectList(lambdaQueryWrapper);
        if (list != null && list.size() > 0) {
            List<Long> collect = list.stream().map(ZjkCreditUser::getExpertId).collect(Collectors.toList());
            List<ZjkExpert> zjkExperts = zjkExpertMapper.selectByIds(collect);
            List<String> collect1 = zjkExperts.stream().map(ZjkExpert::getExpertName).collect(Collectors.toList());
            throw new ServiceException(collect1.toString() + "已被拉入黑名单，无法指定抽取");
        }
    }

    //请假拒绝校验
    public void leaveDenialCheck(List<Long> zjkExpertVos, Long parentId) {
        //是否存在fuid
        LambdaQueryWrapper<ZjkReviewPhase> zjkReviewPhaseLambdaQueryWrapper = new LambdaQueryWrapper<>();
        zjkReviewPhaseLambdaQueryWrapper.eq(ZjkReviewPhase::getParentId, parentId)
            .or(i -> i.eq(ZjkReviewPhase::getId, parentId));
        List<ZjkReviewPhase> zjkReviewPhases = zjkReviewPhaseMapper.selectList(zjkReviewPhaseLambdaQueryWrapper);
        List<Long> collect2 = zjkReviewPhases.stream().map(ZjkReviewPhase::getId).collect(Collectors.toList());
        if (collect2 != null && collect2.size() > 0) {
            LambdaQueryWrapper<ZjkExpertItem> zjkExpertItemLambdaQueryWrapper = new LambdaQueryWrapper<>();
            zjkExpertItemLambdaQueryWrapper.in(ZjkExpertItem::getReviewId, collect2);
            zjkExpertItemLambdaQueryWrapper.in(ZjkExpertItem::getExpertId, zjkExpertVos);
            zjkExpertItemLambdaQueryWrapper.in(ZjkExpertItem::getIsSure, 1);
            List<ZjkExpertItem> zjkExpertItems = baseMapper.selectList(zjkExpertItemLambdaQueryWrapper);
            if (zjkExpertItems != null && zjkExpertItems.size() > 0) {
                List<Long> collect = zjkExpertItems.stream().map(ZjkExpertItem::getExpertId).collect(Collectors.toList());
                List<ZjkExpert> zjkExperts = zjkExpertMapper.selectByIds(collect);
                List<String> collect1 = zjkExperts.stream().map(ZjkExpert::getExpertName).collect(Collectors.toList());
                throw new ServiceException(collect1.toString() + "已被抽取无法重复抽取");
            }
        }
    }
    private Long lastUnfulfilledArea = null; // 保存最后一个不满足条件的领域

    private boolean assignExperts(
        Map<Long, Long> requiredExperts,
        Map<Long, List<ZjkExpertVo>> areaToExperts,
        Set<ZjkExpertVo> assignedExperts,
        Set<String> assignedUnits,
        Map<Long, List<ZjkExpertVo>> result,
        int areaIndex,
        boolean concurrence
    ) {
        List<Long> areas = new ArrayList<>(requiredExperts.keySet());

        // 所有领域分配完成
        if (areaIndex >= areas.size()) {
            return true;
        }

        Long currentArea = areas.get(areaIndex);
        Long requiredCount = requiredExperts.get(currentArea);

        // 当前领域可用专家
        List<ZjkExpertVo> availableExperts = areaToExperts.getOrDefault(currentArea, new ArrayList<>())
            .stream()
            .filter(expert -> {
                // 未分配的专家
                boolean isNotAssigned = !assignedExperts.contains(expert);
                // 单位校验：根据 concurrence 动态控制
                boolean isUnitValid = !concurrence || !assignedUnits.contains(expert.getWorkUnit());
                return isNotAssigned && isUnitValid;
            })
            .collect(Collectors.toList());

        // 调试日志：输出当前状态
        System.out.println("当前领域：" + currentArea + "，需求人数：" + requiredCount + "，可用专家：" + availableExperts.size());

        // 如果当前领域无法满足需求
        if (availableExperts.size() < requiredCount) {
            lastUnfulfilledArea = currentArea; // 覆盖保存当前领域
            System.out.println("领域 " + currentArea + " 无法满足需求，当前状态：" + assignedExperts);
            return false;
        }

        // 动态生成组合
        List<ZjkExpertVo> combination = new ArrayList<>();
        return backtrackCombination(
            availableExperts, combination, 0, requiredCount, expert -> {
                assignedExperts.add(expert);
                if(concurrence){
                    assignedUnits.add(expert.getWorkUnit());

                }
                result.computeIfAbsent(currentArea, k -> new ArrayList<>()).add(expert);
            },
            expert -> {
                assignedExperts.remove(expert);
                if(concurrence){
                    assignedUnits.remove(expert.getWorkUnit());
                }
                result.get(currentArea).remove(expert);
            },
            currentCombination -> {
                // 检查是否违反单位约束
                if (concurrence) {
                    Set<String> unitSet = new HashSet<>();
                    for (ZjkExpertVo expert : currentCombination) {
                        if (!unitSet.add(expert.getWorkUnit())) {
                            return false; // 同单位重复，回溯
                        }
                    }
                }

                // 尝试分配下一个领域
                return assignExperts(requiredExperts, areaToExperts, assignedExperts, assignedUnits, result, areaIndex + 1, concurrence);
            }
        );
    }

    private boolean backtrackCombination(
        List<ZjkExpertVo> availableExperts,
        List<ZjkExpertVo> currentCombination,
        int startIndex,
        long requiredCount,
        Consumer<ZjkExpertVo> assignAction,
        Consumer<ZjkExpertVo> rollbackAction,
        Function<List<ZjkExpertVo>, Boolean> nextStep
    ) {
        if (currentCombination.size() == requiredCount) {
            // 当前组合已满足要求，执行下一步
            return nextStep.apply(currentCombination);
        }

        for (int i = startIndex; i < availableExperts.size(); i++) {
            ZjkExpertVo expert = availableExperts.get(i);

            // 分配当前专家
            currentCombination.add(expert);
            assignAction.accept(expert);

            // 调试日志：记录当前分配状态
            System.out.println("尝试分配专家：" + expert + "，当前组合：" + currentCombination);

            // 递归尝试下一步
            if (backtrackCombination(availableExperts, currentCombination, i + 1, requiredCount, assignAction, rollbackAction, nextStep)) {
                return true;
            }

            // 回溯撤销当前专家
            currentCombination.remove(currentCombination.size() - 1);
            rollbackAction.accept(expert);

            // 调试日志：记录回溯状态
            System.out.println("回溯撤销专家：" + expert + "，当前组合：" + currentCombination);
        }

        return false; // 无法满足组合要求
    }



    private static void generateCombinations(List<ZjkExpertVo> experts, Long n, int start, List<ZjkExpertVo> current, List<List<ZjkExpertVo>> result) {
        if (current.size() == n) {
            result.add(new ArrayList<>(current));
            return;
        }
        for (int i = start; i < experts.size(); i++) {
            current.add(experts.get(i));
            generateCombinations(experts, n, i + 1, current, result);
            current.remove(current.size() - 1);
        }
    }

    // 构建领域到专家的映射
    private static Map<Long, List<ZjkExpertVo>> getAreaToExpertsMap(List<ZjkExpertVo> experts) {
        Map<Long, List<ZjkExpertVo>> areaToExpertsMap = new HashMap<>();
        for (ZjkExpertVo expert : experts) {
            if(StringUtils.isNotBlank(expert.getPerformWorkId())){
                for (String area : expert.getAreaList()) {
                    areaToExpertsMap.computeIfAbsent(Long.parseLong(area), k -> new ArrayList<>()).add(expert);
                }
            }
        }
        return areaToExpertsMap;
    }

    // 专家类
    public List<ZjkExpertVo> extractExperts(List<ZjkExpertVo> allExperts, List<Long> extractioRestrictio, ZjkProjectExpertItemBo bo) {
        // 领域需求
        Map<Long, Long> areaList = bo.getAreaList();

        // 构建领域到专家的映射
        Map<Long, List<ZjkExpertVo>> areaToExperts = getAreaToExpertsMap(allExperts);
        log.info("全部专家集合=====================================================");
        for (Long area1 : areaToExperts.keySet()) {
            log.info("领域： {}" , area1);
            List<ZjkExpertVo> zjkExpertVos = areaToExperts.get(area1);
            for (ZjkExpertVo expert : zjkExpertVos) {
                log.info("专家姓名：{}——专家单位：{}",expert.getExpertName() , expert.getWorkUnit());
            }
        }
        log.info("全部专家集合结束=====================================================");

        // 初始化结果
        Map<Long, List<ZjkExpertVo>> result = new HashMap<>();
        for (Long area : areaList.keySet()) {
            result.put(area, new ArrayList<>());
        }
        boolean concurrence = extractioRestrictio.contains(2L);
        // 记录已分配的单位
        Set<String> assignedUnits = new HashSet<>();
        // 回溯分配
        boolean success = assignExperts(areaList, areaToExperts, new HashSet<>(), assignedUnits, result, 0, concurrence);

        if (success) {
            log.info("领域： {}","领域分配成功");
            Set<Long> areaMap = result.keySet();
            for (Long area : areaMap) {
                log.info("领域： {}",area);
                List<ZjkExpertVo> zjkExpertVos = result.get(area);
                for (ZjkExpertVo expert : zjkExpertVos) {
                        log.info("专家姓名：{}，专家单位{}",expert.getExpertName(),expert.getWorkUnit());
                }
            }
        } else {
            String name = zjkExpertMapper.selectDataWorkId(String.valueOf(lastUnfulfilledArea), LoginHelper.getTenantId());
            throw new ServiceException(name + "领域下专家人数不满足抽取条件，请重新选择!");
        }
        List<ZjkExpertVo> expertList = result.values().stream()
            .flatMap(List::stream)
            .collect(Collectors.toList());
        Collections.shuffle(allExperts, new Random());
        allExperts.removeAll(expertList);
        log.info("剩余专家列表{}", allExperts);
        if(concurrence){
            allExperts = allExperts.stream().filter(s -> !assignedUnits.contains(s.getWorkUnit())).toList();
        }
        Integer planCount = bo.getCount();
        log.info("需要专家数量{}", planCount);
        int count = planCount - expertList.size();
        log.info("随机填充专家数量{}", count);
        if (allExperts.size() < count) {
            throw new ServiceException("专家人数不足！！！");
        }
        //抽完后 看人数，够了 不用随机增加
        if (count == 0) {
            return expertList;
        }
        for (ZjkExpertVo allExpert : allExperts) {
            if (assignedUnits.contains(allExpert.getWorkUnit())) {
                continue;
            }
            log.info("随机填充专家==>{}", allExpert);
            expertList.add(allExpert);
            if (concurrence) {
                assignedUnits.add(allExpert.getWorkUnit());
                log.info("随机填充专家，新增排除单位{}", allExpert.getWorkUnit());
            }
            if (expertList.size() >= planCount) {
                break;
            }
        }
        if (expertList.size() < planCount) {
            throw new ServiceException("专家人数不足");
        }
        return expertList;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleSmsReply(SmsUpEventDto smsUpEventDto) {
        // 获取专家信息
        // 假设 encryptClient.encrypt() 是可重复加密，返回固定密文
        String encryptField = stringCryptoUtil.encryptField(smsUpEventDto.getMobile());

        ZjkExpert zjkExpert  = baseMapper.selectExpertByCodeAndPhone(smsUpEventDto.getContent(),encryptField);
       /* ZjkExpert  zjkExpert = zjkExpertMapper.selectOne(new LambdaQueryWrapper<ZjkExpert>()
            .eq(ZjkExpert::getExpertId, item.getExpertId())
            .eq(ZjkExpert::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL));*/
        if (zjkExpert == null) {
            throw new IllegalArgumentException("未找到对应的专家信息");
        }

        String lastContent = smsUpEventDto.getContent().substring(smsUpEventDto.getContent().length() - 1);
        int smsIsSuer;
        try {
            smsIsSuer = Integer.parseInt(lastContent);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("短信内容最后一位不是有效数字: " + lastContent, e);
        }

        // 构建专家记录
        ZjkExpertItemBo zjkExpertItemBo = new ZjkExpertItemBo();
        zjkExpertItemBo.setExpertId(zjkExpert.getExpertId());
        zjkExpertItemBo.setUserId(zjkExpert.getUserId());
        zjkExpertItemBo.setSmsIsSuer(smsIsSuer);

        if (smsIsSuer == 1) {
            zjkExpertItemBo.setConfirmCode(smsUpEventDto.getContent());
        } else {
            zjkExpertItemBo.setRefuseCode(smsUpEventDto.getContent());
        }

        ZjkExpertItem zjkExpertItem = baseMapper.getExpertItemInfoByUserIdAndCode(zjkExpertItemBo);
        if (zjkExpertItem == null) {
            throw new IllegalArgumentException("未找到对应的专家项目记录");
        }

        // 更新接收状态
        zjkExpertItem.setAcceptStatus(smsIsSuer == 1 ? "1" : "2");

        if (smsIsSuer != 1) {
            // 获取抽取规则并更新抽取人数
            updateExtractionStatus(zjkExpertItem);
        }

        baseMapper.updateById(zjkExpertItem);
    }

    @Override
    public void cancelExpert() {

        String cancelExpert = remoteConfigService.selectConfigByKey("cancel_expert");
        if(StringUtils.isBlank(cancelExpert)){
            return;
        }
        List<ZjkExpertItemVo> zjkExpertItemVos = baseMapper.selectCancle(cancelExpert);
        if(CollectionUtil.isEmpty(zjkExpertItemVos)){
            return;
        }

        Map<Long, List<ZjkExpertItemVo>> listMap = zjkExpertItemVos.stream().collect(Collectors.groupingBy(ZjkExpertItemVo::getItemExtreationId));

        List<ZjkExpertItem> zjkExpertItems = BeanUtil.copyToList(zjkExpertItemVos, ZjkExpertItem.class);


        zjkExpertItems.forEach(s->s.setAcceptStatus("2"));
        baseMapper.updateBatchById(zjkExpertItems);

        List<ZjkItemExtreation> zjkItemExtreations = zjkItemExtreationMapper.selectBatchIds(listMap.keySet());

        zjkItemExtreations.forEach(s->{
            if(listMap.get(s.getId())!=null){
                List<ZjkExpertItemVo> cancleExpertList = listMap.get(s.getId());
                s.setExtractedSum(s.getExtractedSum()-cancleExpertList.size());
            }
        });
        zjkItemExtreationMapper.updateBatchById(zjkItemExtreations);
    }

    /**
     * 更新抽取规则的抽取人数及状态
     */
    private void updateExtractionStatus(ZjkExpertItem zjkExpertItem) {
        ZjkReviewPhase zjkReviewPhase = zjkReviewPhaseMapper.selectById(zjkExpertItem.getReviewId());
        if (zjkReviewPhase != null) {
            ZjkItemExtreation zjkItemExtreation = zjkItemExtreationMapper.selectOne(new LambdaQueryWrapper<ZjkItemExtreation>()
                .eq(ZjkItemExtreation::getId, zjkReviewPhase.getItemExtreationId()));
            if (zjkItemExtreation != null) {
                zjkItemExtreation.setExtractedSum(zjkItemExtreation.getExtractedSum() - 1);
                zjkItemExtreation.setExtractionStatus(1);
                zjkItemExtreationMapper.updateById(zjkItemExtreation);
            }
        }
    }

}


