package org.dromara.zjk.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.domain.DateRange;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.excel.utils.ExcelUtil;
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.RemoteFileService;
import org.dromara.resource.api.RemoteMessageService;
import org.dromara.system.api.RemoteConfigService;
import org.dromara.system.api.RemoteDeptService;
import org.dromara.system.api.RemoteUserService;
import org.dromara.system.api.domain.bo.RemoteDeptBo;
import org.dromara.system.api.domain.bo.RemoteUserBo;
import org.dromara.system.api.domain.vo.RemoteUserVo;
import org.dromara.system.api.model.LoginUser;
import org.dromara.workflow.api.domain.RemoteWorkflowService;
import org.dromara.workflow.api.domain.event.ProcessEvent;
import org.dromara.workflow.api.domain.event.ProcessTaskEvent;
import org.dromara.zjk.annualInspection.annualInspectionAudit.domain.ZjkAnnualInspection;
import org.dromara.zjk.annualInspection.annualInspectionAudit.mapper.ZjkAnnualInspectionMapper;
import org.dromara.zjk.domain.*;
import org.dromara.zjk.domain.bo.ZjkCreditUserBo;
import org.dromara.zjk.domain.bo.ZjkExpertBo;
import org.dromara.zjk.domain.bo.ZjkProjectExpertItemBo;
import org.dromara.zjk.domain.dto.ProfessorsDto;
import org.dromara.zjk.domain.vo.*;
import org.dromara.zjk.enums.*;
import org.dromara.zjk.expert.expertAwards.domain.ZjkExpertAwards;
import org.dromara.zjk.expert.expertAwards.service.IZjkExpertAwardsService;
import org.dromara.zjk.expert.expertPaper.domain.ZjkExpertPaper;
import org.dromara.zjk.expert.expertPaper.service.IZjkExpertPaperService;
import org.dromara.zjk.expert.expertPatent.domain.ZjkExpertPatent;
import org.dromara.zjk.expert.expertPatent.service.IZjkExpertPatentService;
import org.dromara.zjk.mapper.*;
import org.dromara.zjk.service.*;
import org.dromara.zjk.utils.AesUtils;
import org.dromara.zjk.utils.FieldChangeRecorderUtils;
import org.dromara.zjk.utils.IdCardValidator;
import org.dromara.zjk.zwy.annotation.EncryptOperation;
import org.dromara.zjk.zwy.client.HmacClient;
import org.dromara.zjk.zwy.utils.ObjectHashGenerator;
import org.dromara.zjk.zwy.utils.StringCryptoUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
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.Supplier;
import java.util.stream.Collectors;

/**
 * expertService业务层处理
 *
 * @author wangtong
 * @date 2024-10-24
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class ZjkExpertServiceImpl implements IZjkExpertService {

    private final ZjkExpertMapper baseMapper;

    private final ZjkExpertLogMapper zjkExpertLogMapper;

    private final IZjkExpertMajorService zjkExpertMajorService;

    private final IZjkExpertProfessionalService zjkExpertProfessionalService;

    private final ZjkExpertHistoryMapper zjkExpertHistoryMapper;

    private final ZjkLeaveMapper zjkLeaveMapper;

    private final IZjkApprovalProcessLogsService zjkApprovalProcessLogsService;

    private final ZjkDataChangesLogsServiceImpl zjkDataChangesLogsService;

    private final ScheduledExecutorService scheduledExecutorService;

    private final IZjkExpertAwardsService zjkExpertAwardsService;

    private final IZjkExpertPaperService zjkExpertPaperService;

    private final IZjkCreditUserService zjkCreditUserService;

    private final ZjkCreditUserMapper zjkCreditUserMapper;

    private final IZjkExpertPatentService zjkExpertPatentService;

    private final ZjkAnnualInspectionMapper zjkAnnualInspectionMapper;

    private final IZjkReviewPhaseService zjkReviewPhaseService;

    private final ZjkEvaluateMapper zjkEvaluateMapper;

    @Resource
    private final ZjkProductSummarizeLogMapper zjkProductSummarizeLogMapper;

    private final ZjkExpertItemMapper zjkExpertItemMapper;

    private final ZjkCreditMapper zjkCreditMapper;

    // 用户服务 远程调用
    @DubboReference(timeout=5000)
    private RemoteUserService remoteUserService;

    @DubboReference(timeout=5000)
    private RemoteDeptService remoteDeptService;

    @DubboReference(timeout=5000)
    private RemoteConfigService remoteConfigService;

    @DubboReference(timeout=5000)
    private RemoteFileService remoteFileService;

    @DubboReference(timeout=20000)
    private RemoteWorkflowService remoteWorkflowService;

    @DubboReference(stub = "true")
    private final RemoteMessageService remoteMessageService;

    private final ZjkReviewPhaseMapper zjkReviewPhaseMapper;

    private final ZjkProductMapper zjkProductMapper;

    private final HmacClient hmacClient;


    @Autowired
    private StringCryptoUtil stringCryptoUtil;

//    @Value("${api.type.sxzwfw.online-third-professorList}")
    private String professorList;


    /**
     * 查询expert
     *
     * @param id 主键
     * @return expert
     */
    @Override
    public ZjkExpertVo queryById(Long id) {
        ZjkExpertVo zjkExpertVo = baseMapper.selectZjkExpertVo(ZjkExpert.builder().expertId(id).build());
        // 获取专家信息的其他附件 查询 oss 文件
        if (StringUtils.isNotBlank(zjkExpertVo.getOtherPath())) {
            zjkExpertVo.setOtherPathList(remoteFileService.selectByIds(zjkExpertVo.getOtherPath()));
        }
        zjkExpertVo.setMajorList(zjkExpertMajorService.populateExpertMajorList(zjkExpertVo.getUserId(), zjkExpertVo.getExpertId()));
        zjkExpertVo.setProfessionalList(zjkExpertProfessionalService.populateExpertProfessionalList(zjkExpertVo.getUserId(), zjkExpertVo.getExpertId()));
        zjkExpertVo.setZjkExpertAwardsList(zjkExpertAwardsService.selectByExpertId(zjkExpertVo.getExpertId()));
        zjkExpertVo.setZjkExpertPaperList(zjkExpertPaperService.selectByExpertId(zjkExpertVo.getExpertId()));
        zjkExpertVo.setZjkExpertPatentList(zjkExpertPatentService.selectByExpertId(zjkExpertVo.getExpertId()));
        ZjkExpertHistory zjkExpertHistory = zjkExpertHistoryMapper.selectOne(new LambdaQueryWrapper<ZjkExpertHistory>()
            .eq(ZjkExpertHistory::getExpectId, zjkExpertVo.getExpertId()).eq(ZjkExpertHistory::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL));
        if (zjkExpertHistory != null && zjkExpertVo.getApprovalType() == ApprovalTypeEnum.CHANGESTO_INFORMATION.getCode()) {
            zjkExpertVo.setModifiedFields(zjkExpertHistory.getModifiedFields());
        }
        return zjkExpertVo;
    }

    /**
     * 分页查询expert列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return expert分页列表
     */
    @Override
    public TableDataInfo<ZjkExpertVo> queryPageList(ZjkExpertBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ZjkExpert> lqw = buildQueryWrapper(bo);
        if (bo.getStatus() == null) {
            lqw.notIn(ZjkExpert::getStatus, 0, 4, 5);
        } else {
            lqw.eq(ZjkExpert::getStatus, bo.getStatus());
        }
        lqw.orderBy(true, true, ZjkExpert::getStatus);
        lqw.orderBy(true, false, ZjkExpert::getUpdateTime);
        Page<ZjkExpertVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }


    /**
     * 查询专家库列表信息
     */
    @Override
    public TableDataInfo<ZjkExpertVo> expertList(ZjkExpertBo bo, PageQuery pageQuery) {
        Page<ZjkExpertVo> result = baseMapper.expertList(pageQuery.build(), bo);
        return TableDataInfo.build(result);
    }

    @Override
    public TableDataInfo<ZjkExpertVo> expertInquiry(ZjkExpertBo bo, PageQuery pageQuery) {
        Page<ZjkExpertVo> result = baseMapper.expertInquiry(pageQuery.build(), bo);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的专家信息列表
     *
     * @param bo 查询条件
     * @return expert列表
     */
    @Override
    public List<ZjkExpertVo> queryList(ZjkExpertBo bo) {
        LambdaQueryWrapper<ZjkExpert> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }


    /**
     * 导出数据查询
     *
     * @param bo 查询条件
     * @return
     */
    @Override
    public List<ZjkExpertVo> exportList(ZjkExpertBo bo) {
        LambdaQueryWrapper<ZjkExpert> lqw = buildQueryWrapper(bo);
        if (StringUtils.isNotBlank(bo.getExpertIds())) {
           List<String> expertIds= List.of(bo.getExpertIds().split(","));
           if (CollectionUtils.isNotEmpty(expertIds)) {
               lqw.in(ZjkExpert::getExpertId, expertIds);
           }
        }
        lqw.eq(ZjkExpert::getStatus, ZjkExpertTypeEnum.NORMAL.getCode());
        lqw.orderBy(true, true, ZjkExpert::getStatus);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ZjkExpert> buildQueryWrapper(ZjkExpertBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ZjkExpert> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getExpertName()), ZjkExpert::getExpertName, bo.getExpertName());
        lqw.eq(StringUtils.isNotBlank(bo.getContact()), ZjkExpert::getContact, bo.getContact());
        lqw.eq(StringUtils.isNotBlank(bo.getWorkUnit()), ZjkExpert::getWorkUnit, bo.getWorkUnit());
        lqw.eq(StringUtils.isNotBlank(bo.getDuty()), ZjkExpert::getDuty, bo.getDuty());
        lqw.eq(StringUtils.isNotBlank(bo.getPolitics()), ZjkExpert::getPolitics, bo.getPolitics());
        lqw.eq(ZjkExpert::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL);
        return lqw;
    }

    /**
     * 暂存，专家申请
     *
     * @param bo expert
     * @return 是否新增成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(ZjkExpertBo bo) {
        try{
            // 状态不为空且是暂存的时候
            if (bo.getStatus() != null && bo.getStatus() == ZjkExpertTypeEnum.STAGING.getCode()) {
                bo.setStatus(ZjkExpertTypeEnum.STAGING.getCode());
            } else {
                bo.setStatus(ZjkExpertTypeEnum.APPROVAL.getCode());
            }
            // 获取当前用户ID和初始化专家状态
            Long userId = LoginHelper.getUserId();
            bo.setUserId(userId);
            // 检查是否存在当前用户的专家信息
            ZjkExpert existingExpert = baseMapper.selectOne(
                new LambdaQueryWrapper<ZjkExpert>()
                    .eq(ZjkExpert::getUserId, userId)
                    .eq(ZjkExpert::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL)
            );
            if(existingExpert!=null){
                //解密
                decryptIfNotBlank(existingExpert::getContact, existingExpert::setContact);
                decryptIfNotBlank(existingExpert::getIdCard, existingExpert::setIdCard);
                decryptIfNotBlank(existingExpert::getEmail, existingExpert::setEmail);
            }
            // 新增对象
            ZjkExpert addExpert = MapstructUtils.convert(bo, ZjkExpert.class);

            if (existingExpert != null) {
                // 专家信息存在 身份证校验时需要排除掉自己
                ZjkExpert idCard = baseMapper.selectOne(
                    new LambdaQueryWrapper<ZjkExpert>()
                        .eq(ZjkExpert::getIdCard, bo.getIdCard())
                        .ne(ZjkExpert::getExpertId, existingExpert.getExpertId())
                        .eq(ZjkExpert::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL)
                );
                if (idCard != null) {
                    throw new ServiceException("当前身份证在专家库已存在");
                }
                RemoteUserVo remoteUserVo = remoteUserService.selectUserVoByIdCard(bo.getIdCard(), userId);
                if (remoteUserVo != null) {
                    throw new ServiceException("当前身份证号已被注册");
                }
                addExpert.setExpertId(existingExpert.getExpertId());
            } else {
                // 专家信息不存在
                ZjkExpert idCard = baseMapper.selectOne(
                    new LambdaQueryWrapper<ZjkExpert>()
                        .eq(ZjkExpert::getIdCard, bo.getIdCard())
                        .eq(ZjkExpert::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL)
                );
                if (idCard != null) {
                    throw new ServiceException("当前身份证在专家库已存在");
                }
                RemoteUserVo remoteUserVo = remoteUserService.selectUserVoByIdCard(bo.getIdCard(), userId);
                if (remoteUserVo != null) {
                    throw new ServiceException("当前身份证号已被注册");
                }
            }

            if (existingExpert != null && existingExpert.getApprovalType() == ApprovalTypeEnum.EXPERTSAPPLY.getCode() && existingExpert.getStatus() == ZjkExpertTypeEnum.NORMAL.getCode()) {
                bo.setApprovalType(ApprovalTypeEnum.CHANGESTO_INFORMATION.getCode());
            }
            // 审批流程记录发起
            zjkApprovalProcessLogsService.saveCommonApprovalRecord(ApprovalProcessTypeEnum.APPROVAL_INITIATED.getCode(),
                bo.getApprovalType() == ApprovalTypeEnum.EXPERTSAPPLY.getCode() ? ApprovalProcessBusinessTypeEnum.Expert_warehousing.getCode() : ApprovalProcessBusinessTypeEnum.CHANGES_EXPERT_INFORMATION.getCode(),
                null);
            // 转换实体并进行属性拷贝
            // 数据变更记录  只记录变更的字段
            if (existingExpert == null) {
                bo.setApprovalType(ApprovalTypeEnum.EXPERTSAPPLY.getCode());
                // 直接全部记录
                ZjkDataChangesLogs zjkDataChangesLogs = new ZjkDataChangesLogs();
                zjkDataChangesLogs.setBusinessType(BusinessTypeEnum.EXPERT_INFO_CHANGE.getCode());
                zjkDataChangesLogs.setChangeType(ChangeTypeEnum.ADD.getCode());
                zjkDataChangesLogs.setAfterOper(FieldChangeRecorderUtils.recordNewData(addExpert));
                zjkDataChangesLogsService.insertDataChangesLogs(zjkDataChangesLogs);
            }
            // 如果状态为暂存 不进行这一步操作
            if (existingExpert != null && bo.getStatus() != null && bo.getStatus() != ZjkExpertTypeEnum.STAGING.getCode() && bo.getApprovalType() == ApprovalTypeEnum.CHANGESTO_INFORMATION.getCode()) {
                // 获取专家旧的 专业学历 专业技术资格数据
                existingExpert.setMajorList(zjkExpertMajorService.populateExpertMajorList(existingExpert.getUserId(), existingExpert.getExpertId()));
                existingExpert.setProfessionalList(zjkExpertProfessionalService.populateExpertProfessionalList(existingExpert.getUserId(), existingExpert.getExpertId()));
                existingExpert.setZjkExpertAwardsList(zjkExpertAwardsService.populateExpertAwardsList(existingExpert.getExpertId()));
                existingExpert.setZjkExpertPaperList(zjkExpertPaperService.populateExpertPapersList(existingExpert.getExpertId()));
                existingExpert.setZjkExpertPatentList(zjkExpertPatentService.populateExpertPatentsList(existingExpert.getExpertId()));
                // 历史数据表 插入数据
                ZjkExpertHistory zjkExpertHistory = new ZjkExpertHistory();
                zjkExpertHistory.setExpectId(existingExpert.getExpertId());
                zjkExpertHistory.setOldData(JSON.toJSONString(existingExpert));
                zjkExpertHistory.setNewData(JSON.toJSONString(addExpert));
                zjkExpertHistory.setModifiedFields(JSON.toJSONString(FieldChangeRecorderUtils.compareAndRecordChanges(existingExpert, addExpert)));
                zjkExpertHistoryMapper.insert(zjkExpertHistory);
                // 数据变更记录
                ZjkDataChangesLogs zjkDataChangesLogs = new ZjkDataChangesLogs();
                zjkDataChangesLogs.setBusinessType(BusinessTypeEnum.EXPERT_INFO_CHANGE.getCode());
                zjkDataChangesLogs.setChangeType(ChangeTypeEnum.UPDATE.getCode());
                Map<String, Map<String, Object>> compareAndRecordChanges = FieldChangeRecorderUtils.compareAndRecordChanges(existingExpert, addExpert);
                zjkDataChangesLogs.setBeforeOper(compareAndRecordChanges.get("beforeOper").isEmpty() ? null : JSON.toJSONString(compareAndRecordChanges.get("beforeOper")));
                zjkDataChangesLogs.setAfterOper(compareAndRecordChanges.get("afterOper").isEmpty() ? null : JSON.toJSONString(compareAndRecordChanges.get("afterOper")));
                zjkDataChangesLogsService.insertDataChangesLogs(zjkDataChangesLogs);
            }

            // 校验和保存专家申请信息
            validEntityBeforeSave(addExpert);
            boolean flag = baseMapper.insertOrUpdate(addExpert);
            if (flag) {
                bo.setExpertId(addExpert.getExpertId());
            }
            // 专业学历信息处理
            zjkExpertMajorService.handleExpertMajors(bo.getMajorList(), bo.getExpertId(), userId);
            // 专业技术资格信息处理
            zjkExpertProfessionalService.handleExpertProfessionals(bo.getProfessionalList(), bo.getExpertId(), userId);

            zjkExpertAwardsService.handleExpertAwards(bo.getZjkExpertAwardsList(), bo.getExpertId());

            zjkExpertPaperService.handleExpertPapers(bo.getZjkExpertPaperList(), bo.getExpertId());

            zjkExpertPatentService.handleExpertPatents(bo.getZjkExpertPatentList(), bo.getExpertId());

//        // 调用远程服务 发起审批流程
            // 暂存情况下 不发起审批流
            if (bo.getStatus() != null && bo.getStatus() != ZjkExpertTypeEnum.STAGING.getCode()){
                Map<String, Object> variables = Map.of(
                    "entity", Map.of(
                        "approvalType",bo.getApprovalType()
                    )
                );
                Map<String, Object> startedWorkFlowMap = remoteWorkflowService.startWorkFlow(String.valueOf(addExpert.getExpertId()), "zjk_expert", variables);
                log.info("ID:{}姓名:{}手机号:{}身份证号:{}专家工作流相关数据taskInfoMap:{}",addExpert.getExpertId(),addExpert.getExpertName(),addExpert.getContact(),addExpert.getIdCard(),JSON.toJSONString(startedWorkFlowMap));
                remoteWorkflowService.completeTask(startedWorkFlowMap.get("taskId").toString(), new ArrayList<>(List.of("1")),null, String.valueOf(addExpert.getExpertId()));
            }
            refreshHmac(addExpert.getExpertId());
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
        return true;
    }
    private void decryptIfNotBlank(Supplier<String> getter, Consumer<String> setter) {
        String value = getter.get();
        if (value != null && !value.isBlank()) {
            setter.accept(stringCryptoUtil.decryptField(value));
        }
    }

    /**
     * 校验专家以及专家附属信息的hmac
     * @param expertId
     */
    @Override
    public void refreshHmac(Long expertId) {
        try {
            // 查询完整的专家视图对象（含附属信息）
            ZjkExpertVo zjkExpertVo = baseMapper.selectZjkExpertVo(ZjkExpert.builder().expertId(expertId).build());
            if (zjkExpertVo == null) {
                log.warn("未找到专家信息，expertId: {}", expertId);
                return;
            }

            // 查询 OSS 附件（非必须用于 HMAC，但保留结构一致性）
            if (StringUtils.isNotBlank(zjkExpertVo.getOtherPath())) {
                zjkExpertVo.setOtherPathList(remoteFileService.selectByIds(zjkExpertVo.getOtherPath()));
            }

            // 查询附属信息并设置到 VO 中
            zjkExpertVo.setMajorList(zjkExpertMajorService.populateExpertMajorList(zjkExpertVo.getUserId(), zjkExpertVo.getExpertId()));
            zjkExpertVo.setProfessionalList(zjkExpertProfessionalService.populateExpertProfessionalList(zjkExpertVo.getUserId(), zjkExpertVo.getExpertId()));
            zjkExpertVo.setZjkExpertAwardsList(zjkExpertAwardsService.selectByExpertId(zjkExpertVo.getExpertId()));
            zjkExpertVo.setZjkExpertPaperList(zjkExpertPaperService.selectByExpertId(zjkExpertVo.getExpertId()));
            zjkExpertVo.setZjkExpertPatentList(zjkExpertPatentService.selectByExpertId(zjkExpertVo.getExpertId()));

            // 构造参与哈希的组合对象
            Map<String, Object> composite = new HashMap<>();
            composite.put("expert", zjkExpertVo);
            composite.put("majorList", zjkExpertVo.getMajorList());
            composite.put("professionalList", zjkExpertVo.getProfessionalList());
            composite.put("awardsList", zjkExpertVo.getZjkExpertAwardsList());
            composite.put("paperList", zjkExpertVo.getZjkExpertPaperList());
            composite.put("patentList", zjkExpertVo.getZjkExpertPatentList());

            // 生成哈希与 HMAC 值（如需加密服务调用，请替换此行）
            String hash = ObjectHashGenerator.generateHash(composite);
            String base64 = Base64.getEncoder().encodeToString(hash.getBytes(StandardCharsets.UTF_8));
             String hmac = hmacClient.calculateHmac(base64);
//            String hmac = base64;

            // 更新专家主表的 HMAC 字段
            ZjkExpert update = new ZjkExpert();
            update.setExpertId(expertId);
            update.setHmac(hmac);
            baseMapper.updateHmac(update);

            log.info("专家 HMAC 生成成功，专家ID: {}, HMAC: {}", expertId, hmac);
        } catch (Exception e) {
            log.error("生成专家 HMAC 失败，专家ID: {}", expertId, e);
        }
    }
    @Override
    public Map<String, Object> getExpertObjectById(Long expertId) {
        try {
            // 查询完整的专家视图对象（含附属信息）
            ZjkExpertVo zjkExpertVo = baseMapper.selectZjkExpertVo(ZjkExpert.builder().expertId(expertId).build());
            if (zjkExpertVo == null) {
                log.warn("未找到专家信息，expertId: {}", expertId);
                return Collections.emptyMap();
            }

            // 附件路径（非必要）
            if (StringUtils.isNotBlank(zjkExpertVo.getOtherPath())) {
                zjkExpertVo.setOtherPathList(remoteFileService.selectByIds(zjkExpertVo.getOtherPath()));
            }

            // 附属信息
            zjkExpertVo.setMajorList(zjkExpertMajorService.populateExpertMajorList(zjkExpertVo.getUserId(), zjkExpertVo.getExpertId()));
            zjkExpertVo.setProfessionalList(zjkExpertProfessionalService.populateExpertProfessionalList(zjkExpertVo.getUserId(), zjkExpertVo.getExpertId()));
            zjkExpertVo.setZjkExpertAwardsList(zjkExpertAwardsService.selectByExpertId(zjkExpertVo.getExpertId()));
            zjkExpertVo.setZjkExpertPaperList(zjkExpertPaperService.selectByExpertId(zjkExpertVo.getExpertId()));
            zjkExpertVo.setZjkExpertPatentList(zjkExpertPatentService.selectByExpertId(zjkExpertVo.getExpertId()));

            // 组合结构
            Map<String, Object> composite = new HashMap<>();
            composite.put("expert", zjkExpertVo);
            composite.put("majorList", zjkExpertVo.getMajorList());
            composite.put("professionalList", zjkExpertVo.getProfessionalList());
            composite.put("awardsList", zjkExpertVo.getZjkExpertAwardsList());
            composite.put("paperList", zjkExpertVo.getZjkExpertPaperList());
            composite.put("patentList", zjkExpertVo.getZjkExpertPatentList());

            return composite;
        } catch (Exception e) {
            log.error("生成专家 HMAC 对象失败，专家ID: {}", expertId, e);
            return Collections.emptyMap();
        }
    }

    /**
     * 批量新增
     *
     * @param list
     * @return 是否新增成功
     */
    @EncryptOperation
    @Override
    public Boolean insertList(List<ZjkExpertBo> list) {
        if (CollectionUtils.isEmpty(list)) {
            return true;
        }
        List<ZjkExpert> zjkExpertList = new ArrayList<>();
        list.forEach(a -> {
            ZjkExpert add = MapstructUtils.convert(a, ZjkExpert.class);
            add.setApprovalType(ApprovalTypeEnum.EXPERTSAPPLY.getCode());
            add.setStatus(ZjkExpertTypeEnum.NORMAL.getCode());
            zjkExpertList.add(add);
        });
        baseMapper.insertBatch(zjkExpertList);
        List<ZjkCreditUser> zjkCreditUserList = new ArrayList<>();
        List<ZjkCredit> zjkCreditList = new ArrayList<>();
        for (ZjkExpert zjkExpert : zjkExpertList) {
            ZjkCreditUser zjkCreditUser = new ZjkCreditUser();
            zjkCreditUser.setExpertId(zjkExpert.getExpertId());
            zjkCreditUser.setUserId(zjkExpert.getUserId());
            zjkCreditUser.setChangeTime(new Date());
            zjkCreditUserList.add(zjkCreditUser);
            //新增一条信用记录
            ZjkCredit zjkCredit = new ZjkCredit();
            zjkCredit.setExpertId(zjkExpert.getExpertId());
            zjkCredit.setCreditCount(100L);
            zjkCredit.setUserId(zjkExpert.getUserId());
            zjkCredit.setCredit(+100L);
            zjkCreditList.add(zjkCredit);
        }
        zjkCreditUserMapper.insertBatch(zjkCreditUserList);
        zjkCreditMapper.insertBatch(zjkCreditList);
       return true;
    }

    /**
     * 执行审批操作 然后进行操作日志记录
     *
     * @param bo expert
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(ZjkExpertBo bo) {
        ZjkExpert add = MapstructUtils.convert(bo, ZjkExpert.class);
        ZjkExpert zjkExpertInfo = baseMapper.selectById(bo.getExpertId());
        // 如果只是审批则不进行，修改则进行
        if (!bo.getMajorList().isEmpty()) {
            // 专业学历信息处理
            zjkExpertMajorService.handleExpertMajors(bo.getMajorList(), zjkExpertInfo.getExpertId(), zjkExpertInfo.getUserId());
        }
        if (!bo.getProfessionalList().isEmpty()) {
            // 专业技术资格信息处理
            zjkExpertProfessionalService.handleExpertProfessionals(bo.getProfessionalList(), zjkExpertInfo.getExpertId(), zjkExpertInfo.getUserId());
        }
        if (!bo.getZjkExpertAwardsList().isEmpty()) {
            zjkExpertAwardsService.handleExpertAwards(bo.getZjkExpertAwardsList(), zjkExpertInfo.getExpertId());
        }

        if (!bo.getZjkExpertPaperList().isEmpty()) {
            zjkExpertPaperService.handleExpertPapers(bo.getZjkExpertPaperList(), zjkExpertInfo.getExpertId());
        }

        if (!bo.getZjkExpertPatentList().isEmpty()) {
            zjkExpertPatentService.handleExpertPatents(bo.getZjkExpertPatentList(), zjkExpertInfo.getExpertId());
        }

        boolean b = baseMapper.updateById(add) > 0;
        refreshHmac(zjkExpertInfo.getExpertId());
        return b;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean approval(ZjkExpertBo bo) {

        ZjkExpert add = MapstructUtils.convert(bo, ZjkExpert.class);
        try {
        ZjkExpert zjkExpertInfo = baseMapper.selectById(bo.getExpertId());
        // 如果状态为通过并且 为专家申请 设置审批时间
        if (add.getStatus() == ZjkExpertTypeEnum.NORMAL.getCode() && zjkExpertInfo.getApprovalType() == ApprovalTypeEnum.EXPERTSAPPLY.getCode()) {
            //同步信用用户  查询当前专家是否存在数据 存在不进行处理
            ZjkCreditUser zjkCreditUser = zjkCreditUserMapper.selectOne(new LambdaQueryWrapper<ZjkCreditUser>()
                .eq(ZjkCreditUser::getUserId, zjkExpertInfo.getUserId())
                .eq(ZjkCreditUser::getExpertId, zjkExpertInfo.getExpertId()));
            if (zjkCreditUser == null) {
                ZjkCreditUserBo zjkCreditUserBo = new ZjkCreditUserBo();
                zjkCreditUserBo.setExpertId(zjkExpertInfo.getExpertId());
                zjkCreditUserBo.setUserId(zjkExpertInfo.getUserId());
                zjkCreditUserBo.setChangeTime(new Date());
                zjkCreditUserService.insertByBo(zjkCreditUserBo);
                //新增一条信用记录
                ZjkCredit zjkCredit = new ZjkCredit();
                zjkCredit.setExpertId(zjkExpertInfo.getExpertId());
                zjkCredit.setCreditCount(100L);
                zjkCredit.setUserId(zjkExpertInfo.getUserId());
                zjkCredit.setCredit(+100L);
                zjkCreditMapper.insert(zjkCredit);
                add.setApprovalTime(new Date());
            }
        }
        // 入库记录
        ZjkExpertLog expertLog = new ZjkExpertLog();
        expertLog.setExpertId(zjkExpertInfo.getExpertId());
        expertLog.setName(zjkExpertInfo.getExpertName());
        expertLog.setContactInfo(zjkExpertInfo.getContact());
        expertLog.setOrganization(zjkExpertInfo.getWorkUnit());
        expertLog.setPosition(zjkExpertInfo.getDuty());
        expertLog.setEntryResult(bo.getStatus() == 2 ? ResultTypeEnum.SUCCESS.getCode() : ResultTypeEnum.ERROR.getCode());
        expertLog.setApplicationTime(zjkExpertInfo.getUpdateTime());
        expertLog.setRejectionReason(bo.getRemark());
        zjkExpertLogMapper.insert(expertLog);
        // 审批流程记录
        zjkApprovalProcessLogsService.saveCommonApprovalRecord(bo.getStatus() == ZjkExpertTypeEnum.NORMAL.getCode() ? ApprovalProcessTypeEnum.APPROVAL_PASSED.getCode() : ApprovalProcessTypeEnum.APPROVAL_REFUSED.getCode(),
            zjkExpertInfo.getApprovalType() == ApprovalTypeEnum.EXPERTSAPPLY.getCode() ? ApprovalProcessBusinessTypeEnum.Expert_warehousing.getCode() : ApprovalProcessBusinessTypeEnum.CHANGES_EXPERT_INFORMATION.getCode(),
            bo.getRemark());
        scheduledExecutorService.schedule(() -> {
            remoteMessageService.publishMessage(zjkExpertInfo.getUserId(), bo.getStatus() == ZjkExpertTypeEnum.NORMAL.getCode() ? "您的专家信息审核通已通过" : "您的专家信息审核被驳回");
        }, 3, TimeUnit.SECONDS);
        ZjkExpertHistory zjkExpertHistory = zjkExpertHistoryMapper.selectOne(new LambdaQueryWrapper<ZjkExpertHistory>().eq(ZjkExpertHistory::getExpectId, zjkExpertInfo.getExpertId()).eq(ZjkExpertHistory::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL));
        if (zjkExpertHistory != null) {
            zjkExpertHistoryMapper.deleteById(zjkExpertHistory.getId());
        }
        // 根据审核状态走不同的工作流 1. 根据业务 id 获取相关信息

            Map<String, Object> taskInfoMap = remoteWorkflowService.getTaskInfoByBusinessKey(String.valueOf(zjkExpertInfo.getExpertId()));
            log.info("姓名:{}手机号:{}身份证号:{}专家工作流相关数据taskInfoMap:{}",zjkExpertInfo.getExpertName(),zjkExpertInfo.getContact(),zjkExpertInfo.getIdCard(),JSON.toJSONString(taskInfoMap));
            // 审批通过时 进行工作流通过 否则驳回
            if (bo.getStatus() == ZjkExpertTypeEnum.NORMAL.getCode()){
                log.info("姓名:{}手机号:{}身份证号:{}审批通过",zjkExpertInfo.getExpertName(),zjkExpertInfo.getContact(),zjkExpertInfo.getIdCard());
                // 创建嵌套 Map
                Map<String, Object> result = Map.of(
                    "entity", Map.of(
                        "status",bo.getStatus(),
                        "approvalType",zjkExpertInfo.getApprovalType()
                    )
                );
                remoteWorkflowService.completeTask(taskInfoMap.get("taskId").toString(), new ArrayList<>(List.of("1")),result, String.valueOf(zjkExpertInfo.getExpertId()));
            } else {
                log.info("姓名:{}手机号:{}身份证号:{}审批驳回",zjkExpertInfo.getExpertName(),zjkExpertInfo.getContact(),zjkExpertInfo.getIdCard());
                // 获取可驳回的流程 id
                String targetActivityId = remoteWorkflowService.getNodeList(taskInfoMap.get("processInstanceId").toString());
                log.info("可驳回的流程:{}",targetActivityId);
                // 进行驳回操作
                String backResult = remoteWorkflowService.backProcess(taskInfoMap.get("taskId").toString(), new ArrayList<>(List.of("1")),targetActivityId,bo.getRemark());
                log.info("姓名:{} 手机号:{}   身份证号:{}   驳回状态:{}",zjkExpertInfo.getExpertName(),zjkExpertInfo.getContact(),zjkExpertInfo.getIdCard(),backResult);
            }

            boolean b = baseMapper.updateStatusById(add) > 0;
            refreshHmac(zjkExpertInfo.getExpertId());
            return b;
        } catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("系统异常，请联系管理员处理");
        }
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ZjkExpert entity) {
        //TODO 做一些数据校验,如唯一约束
//        String expertName = entity.getExpertName();
//        if (StringUtils.isEmpty(expertName)) {
//            throw new ServiceException("姓名不能为空!");
//        }
    }

    /**
     * 校验并批量删除expert信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 根据用户 id 获取当前用户的专家信息
     *
     * @param userId 登录用户id
     * @return
     */
    @Override
    public ZjkExpertVo queryByUserId(Long userId, Long expertId) {
        ZjkExpert query = new ZjkExpert();
        query.setUserId(userId);
        if (expertId != null) {
            query.setExpertId(expertId);
        }
        ZjkExpertVo zjkExpertVo = baseMapper.selectZjkExpertVo(query);
        // 专家信息为空时查询基本数据返回
        if (zjkExpertVo == null) {
            LoginUser loginUser = LoginHelper.getLoginUser();
            if (loginUser == null) {
                throw new ServiceException("数据异常");
            }
            zjkExpertVo = new ZjkExpertVo();
            zjkExpertVo.setIdCard(loginUser.getIdCard());
            zjkExpertVo.setContact(loginUser.getPhone());
            zjkExpertVo.setExpertName(loginUser.getNickname());
            zjkExpertVo.setApprovalType(ApprovalTypeEnum.EXPERTSAPPLY.getCode());
            return zjkExpertVo;
        }
        // 获取专家信息的其他附件 查询 oss 文件
        if (StringUtils.isNotBlank(zjkExpertVo.getOtherPath())) {
            zjkExpertVo.setOtherPathList(remoteFileService.selectByIds(zjkExpertVo.getOtherPath()));
        }
        zjkExpertVo.setMajorList(zjkExpertMajorService.populateExpertMajorList(userId, zjkExpertVo.getExpertId()));
        zjkExpertVo.setProfessionalList(zjkExpertProfessionalService.populateExpertProfessionalList(userId, zjkExpertVo.getExpertId()));
        zjkExpertVo.setZjkExpertAwardsList(zjkExpertAwardsService.selectByExpertId(zjkExpertVo.getExpertId()));
        zjkExpertVo.setZjkExpertPaperList(zjkExpertPaperService.selectByExpertId(zjkExpertVo.getExpertId()));
        zjkExpertVo.setZjkExpertPatentList(zjkExpertPatentService.selectByExpertId(zjkExpertVo.getExpertId()));
        // 获取当前专家年检信息
        ZjkAnnualInspection zjkAnnualInspection = zjkAnnualInspectionMapper.selectOne(new LambdaQueryWrapper<ZjkAnnualInspection>()
            .eq(ZjkAnnualInspection::getUserId, userId)
            .eq(expertId != null, ZjkAnnualInspection::getExpertId, expertId)
            .eq(ZjkAnnualInspection::getDelFlag, UserConstants.DEL_FLAG_NORMAL)
            .orderByDesc(ZjkAnnualInspection::getCreateTime) // 按创建时间倒序
            .last("limit 1"));
        if (zjkAnnualInspection != null) {
            zjkExpertVo.setZjkAnnualInspection(zjkAnnualInspection);
        }
        return zjkExpertVo;
    }

    /**
     * 根据身份证号查询是否存在专家
     *
     * @param idCards
     * @return
     */
    @Override
    public List<String> selectExistingIdCards(List<String> idCards) {
        return baseMapper.selectExistingIdCards(idCards);
    }

    @Override
    public List<ZjkExpertVo> queryByExpertltemList(ZjkProjectExpertItemBo zjkProjectExpertItemBo, List<Long> extractioRestrictio, ZjkProjectExpertItemBo bo, Set<ZjkExpertItem> remoZjkExpertItems, List<Long> specifiedExpertList) {
        Set<Long> expertIds = new HashSet<>();
        //屏蔽黑名单专家
        LambdaQueryWrapper<ZjkCreditUser> userWrapper = new LambdaQueryWrapper();
        userWrapper.ge(ZjkCreditUser::getRewardId, 4);
        List<ZjkCreditUser> zjkCreditUsers = zjkCreditUserMapper.selectList(userWrapper);
        List<Long> collect2 = zjkCreditUsers.stream().map(ZjkCreditUser::getExpertId).collect(Collectors.toList());
        log.info("黑名单专家结果集{}",collect2);
        if (collect2 != null && collect2.size() > 0) {
            expertIds.addAll(collect2);
        }
        //获取项目总结未评价完的专家
//        LambdaQueryWrapper<ZjkProductSummarizeLog> lambdaQueryWrapper1 = new LambdaQueryWrapper();
//        lambdaQueryWrapper1.eq(ZjkProductSummarizeLog::getIsEvaluate, 0);
//        List<ZjkProductSummarizeLog> zjkProductSummarizeLogs = zjkProductSummarizeLogMapper.selectList(lambdaQueryWrapper1);
//        List<String> coll = zjkProductSummarizeLogs.stream().map(ZjkProductSummarizeLog::getExpertIds).collect(Collectors.toList());
//        if (coll != null) {
//            for (String s : coll) {
//                if (s != null && s.length() > 0) {
//                    String[] split = s.split(",");
//                    for (String numStr : split) {
//                        expertIds.add(Long.parseLong(numStr));
//                    }
//                }
//            }
//        }

        LambdaQueryWrapper<ZjkExpert> lqw = Wrappers.lambdaQuery();
        //回避专家
        if(CollectionUtils.isNotEmpty(zjkProjectExpertItemBo.getExpertIds())){
            expertIds.addAll(zjkProjectExpertItemBo.getExpertIds());
            log.info("回避专家结果集{}",collect2);
        }
        //请假过滤，获取在开标时间段内请假的专家并过滤
        LambdaQueryWrapper<ZjkLeave> queryWrapper = new LambdaQueryWrapper<>();
        Date reviewTime = zjkProjectExpertItemBo.getReviewTime();
        queryWrapper.le(ZjkLeave::getStartDate, reviewTime);
        queryWrapper.ge(ZjkLeave::getEndDate, reviewTime);
        // 长期请假的专家
        List<ZjkLeaveVo> zjkLeaveVos = zjkLeaveMapper.selectVoList(queryWrapper);
        Set<String> set = zjkLeaveVos.stream().filter(s -> s.getCreateBy() != null).map(ZjkLeaveVo::getCreateBy).collect(Collectors.toSet());
        if (CollectionUtil.isNotEmpty(set)) {
            lqw.notIn(ZjkExpert::getUserId, set);
            log.info("长期请假用户集合{}",set);
        }
        if (CollectionUtil.isNotEmpty(zjkProjectExpertItemBo.getExtractArea())) {
            if (zjkProjectExpertItemBo.getExtractArea().size() == 1) {
                lqw.eq(ZjkExpert::getProvince, zjkProjectExpertItemBo.getProvinces());
                log.info("抽取回避 省市区 --省{}",zjkProjectExpertItemBo.getProvinces());
            }
            if (zjkProjectExpertItemBo.getExtractArea().size() == 2) {
                lqw.eq(ZjkExpert::getCity, zjkProjectExpertItemBo.getProvinces());
                log.info("抽取回避 省市区 --市{}",zjkProjectExpertItemBo.getProvinces());
            }
            if (zjkProjectExpertItemBo.getExtractArea().size() == 3) {
                lqw.eq(ZjkExpert::getArea, zjkProjectExpertItemBo.getProvinces());
                log.info("抽取回避 省市区 --区{}",zjkProjectExpertItemBo.getProvinces());
            }
        }
        if (zjkProjectExpertItemBo.getZjkReviewPhase() != null && zjkProjectExpertItemBo.getZjkReviewPhase().getParentId() != null) {
            //获取项目已经请假的专家
            LambdaQueryWrapper<ZjkReviewPhase> wrapper = new LambdaQueryWrapper<>();
            ZjkReviewPhase zjkReviewPhase = zjkProjectExpertItemBo.getZjkReviewPhase();
            List<Long> collect1 = new ArrayList<>();
            wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ZjkReviewPhase::getParentId, zjkReviewPhase.getParentId())
                .or(i -> i.eq(ZjkReviewPhase::getId, zjkReviewPhase.getParentId()))
                .eq(ZjkReviewPhase::getItemId, zjkReviewPhase.getItemId())
                .eq(ZjkReviewPhase::getReviewSn, zjkReviewPhase.getReviewSn());
            List<ZjkReviewPhase> zjkReviewPhases = zjkReviewPhaseMapper.selectList(wrapper);
            if (CollectionUtil.isNotEmpty(zjkReviewPhases)) {
                List<Long> collect = zjkReviewPhases.stream().map(ZjkReviewPhase::getId).collect(Collectors.toList());
                collect1.addAll(collect);
                log.info("项目请假专家集合{}",collect);

            }
            LambdaQueryWrapper<ZjkExpertItem> lambdasQuery = new LambdaQueryWrapper<>();
            if (CollectionUtil.isNotEmpty(collect1)) {
                lambdasQuery.in(ZjkExpertItem::getReviewId, collect1);
                lambdasQuery.eq(ZjkExpertItem::getIsSure, 1);
//                lambdasQuery.notIn(ZjkExpertItem::getAcceptStatus, 4);
                List<ZjkExpertItem> zjkExpertItems2 = zjkExpertItemMapper.selectList(lambdasQuery);
                List<Long> collect = zjkExpertItems2.stream()
                    .map(ZjkExpertItem::getExpertId)
                    .distinct() // 去重
                    .collect(Collectors.toList());
                zjkProjectExpertItemBo.setExpertIds(collect);
                expertIds.addAll(collect);
                log.info("发送通知结果集{}",collect);
            }
        }

        if (extractioRestrictio.contains(1L)) {
            //屏蔽同天评审专家
            LambdaQueryWrapper<ZjkReviewPhase> reivewMapper = new LambdaQueryWrapper<>();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String format = simpleDateFormat.format(bo.getReviewTime());
            reivewMapper.like(ZjkReviewPhase::getReviewTime, format);
            reivewMapper.eq(ZjkReviewPhase::getEffective, 1);
            List<ZjkReviewPhaseVo> zjkProjectVos = zjkReviewPhaseMapper.selectVoList(reivewMapper);
            List<Long> idList = zjkProjectVos.stream()
                .map(ZjkReviewPhaseVo::getId)
                .collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(idList)) {
                List<ZjkExpertItemVo> zjkExpertItemVos = zjkExpertItemMapper.selectBatchByReviewIds(idList);
                if(CollectionUtil.isNotEmpty(zjkExpertItemVos)){
                    List<Long> expertIdList = zjkExpertItemVos.stream().map(ZjkExpertItemVo::getExpertId).toList();
                    expertIds.addAll(expertIdList);
                    log.info("屏蔽同天评审专家集{}",expertIdList);
                }
            }
        }
        List<String> unit = CollectionUtil.isNotEmpty(zjkProjectExpertItemBo.getUnit()) ? new ArrayList<>(zjkProjectExpertItemBo.getUnit()) : new ArrayList<>();
        // 补抽，指定抽取  用户 同一单位
        List<Long> specifiedExpertIds = new ArrayList<>();
        if (extractioRestrictio.contains(2L)) {
            //指定专家 同一单位
            if (CollectionUtil.isNotEmpty(specifiedExpertList)) {
                specifiedExpertIds.addAll(specifiedExpertList);
            }
            //补抽 同意单位 排除
            if (CollectionUtil.isNotEmpty(remoZjkExpertItems)) {
                List<Long> redrawExpertIds = remoZjkExpertItems.stream().map(ZjkExpertItem::getExpertId).toList();
                specifiedExpertIds.addAll(redrawExpertIds);
            }
            if (CollectionUtil.isNotEmpty(specifiedExpertIds)) {
                List<ZjkExpert> redrawExpertIdLiat = baseMapper.selectByIds(specifiedExpertIds);
                if (CollectionUtil.isNotEmpty(redrawExpertIdLiat)) {
                    unit.addAll(redrawExpertIdLiat.stream().map(ZjkExpert::getWorkUnit).toList());
                    log.info("排除工作单位{}", redrawExpertIdLiat);
                }
            }
        }
        //todo 屏蔽本单位专家
        if (extractioRestrictio.contains(3L)) {
            Long itemId = bo.getItemid();
            ZjkProductVo zjkProductVo = zjkProductMapper.selectVoById(itemId);
            unit.add(zjkProductVo.getProductUnit());
        }
        if (CollectionUtil.isNotEmpty(unit)) {
            lqw.notIn(ZjkExpert::getWorkUnit, unit);
            log.info("屏蔽本单位 {}",unit);

        }
        lqw.eq(ZjkExpert::getStatus, 2);
        lqw.eq(ZjkExpert::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL);
        lqw.and(wrapper ->
            wrapper.eq(ZjkExpert::getAnnualInspectionStatus, AnnualInspectionStatus.PASSED.getCode())
                .or()
                .isNull(ZjkExpert::getAnnualInspectionStatus)
        );
        if (CollectionUtil.isNotEmpty(expertIds)) {
            lqw.notIn(ZjkExpert::getExpertId, expertIds);
            log.info("排除全部专家集合{}",expertIds);
        }
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public TableDataInfo<ZjkExpertVo> querylist() {
        LambdaQueryWrapper<ZjkExpert> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ZjkExpert::getStatus, 2);
        List<ZjkExpertVo> zjkExpertVos = baseMapper.selectVoList(lambdaQueryWrapper);
        return TableDataInfo.build(zjkExpertVos);
    }

    /**
     * 专家申请撤销
     *
     * @param type 1 专家个人信息页面撤销申请  2 专家我的任务进行撤销逻辑
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean expertQuash(Integer type, String businessKey) {
        // 根据当前登录用户获取专家 id
        LambdaQueryWrapper<ZjkExpert> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ZjkExpert::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL);
        if (type == 1) {
            lambdaQueryWrapper.eq(ZjkExpert::getUserId, LoginHelper.getUserId());
        } else {
            lambdaQueryWrapper.eq(ZjkExpert::getExpertId, businessKey);
        }
        ZjkExpert existingExpert = baseMapper.selectOne(lambdaQueryWrapper);
        if (existingExpert == null) {
            return false;
        }
        // type==1 专家个人信息页面撤销 同步撤销工作流
        if (type == 1) {
            remoteWorkflowService.cancelProcessApply(String.valueOf(existingExpert.getExpertId()));
        }
        ZjkExpertHistory zjkExpertHistory = zjkExpertHistoryMapper.selectOne(new LambdaQueryWrapper<ZjkExpertHistory>().eq(ZjkExpertHistory::getExpectId, existingExpert.getExpertId()).eq(ZjkExpertHistory::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL));
        if (zjkExpertHistory != null) {
            ZjkExpert zjkExpert = JSON.parseObject(zjkExpertHistory.getOldData(), ZjkExpert.class);
            // 专业学历信息处理
            zjkExpertMajorService.handleExpertMajors(zjkExpert.getMajorList(), zjkExpert.getExpertId(), zjkExpert.getUserId());
            // 专业技术资格信息处理
            zjkExpertProfessionalService.handleExpertProfessionals(zjkExpert.getProfessionalList(), zjkExpert.getExpertId(), zjkExpert.getUserId());

            zjkExpertAwardsService.handleExpertAwards(zjkExpert.getZjkExpertAwardsList(), zjkExpert.getExpertId());

            zjkExpertPaperService.handleExpertPapers(zjkExpert.getZjkExpertPaperList(), zjkExpert.getExpertId());

            zjkExpertPatentService.handleExpertPatents(zjkExpert.getZjkExpertPatentList(), zjkExpert.getExpertId());

            baseMapper.updateById(zjkExpert);

            refreshHmac(zjkExpert.getExpertId());

            zjkExpertHistoryMapper.deleteById(zjkExpertHistory.getId());
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> imports(MultipartFile file) {
        try {
            InputStream inputStream = file.getInputStream();
            // 文件转化
            List<ZjkExpertBo> zjkExpertVos = ExcelUtil.importExcel(inputStream, ZjkExpertBo.class);
            // 提取所有的身份证号
            List<String> idCards = zjkExpertVos.stream()
                .map(ZjkExpertBo::getIdCard)
                .collect(Collectors.toList());
            // 使用 Map 进行分组统计
            Map<String, Long> idCardCounts = idCards.stream()
                .collect(Collectors.groupingBy(idCard -> idCard, Collectors.counting()));

            // 打印重复的身份证号
            idCardCounts.forEach((idCard, count) -> {
                if (count > 1) {
                    throw new ServiceException("当前导入的数据中该身份证号存在多个" + idCard);
                }
            });
            // 根据提取的 idCards 列表查询数据库中已存在的 idCards
            List<String> existingIdCards = baseMapper.selectExistingIdCards(idCards);
            // 如果存在重复的身份证号则提示，剔除之后再次导入
            if (!CollUtil.isEmpty(existingIdCards)) {
                // 将身份证号列表转换为用逗号分隔的字符串
                return existingIdCards;
            }
            // 注册用户信息
            List<RemoteUserBo> remoteUserBoList = new ArrayList<>();
            // 剔除重复的身份证号记录
/*            List<ZjkExpertBo> filteredZjkExpertVos = zjkExpertVos.stream()
                .filter(expert -> !existingIdCards.contains(expert.getIdCard()))
                .peek(expert -> expert.setApprovalTime(new Date())) // 设置 approvalTime 为当前时间
                .collect(Collectors.toList());*/
            // 剔除重复的身份证号记录 & 校验身份证格式
            List<ZjkExpertBo> filteredZjkExpertVos = zjkExpertVos.stream()
                .filter(expert -> !existingIdCards.contains(expert.getIdCard()))
                .filter(expert -> {
                    String idCard = expert.getIdCard();
                    if (!IdCardValidator.isValid(idCard)) {
                        throw new ServiceException("身份证号格式不合法或出生日期错误：" + idCard);
                    }
                    return true;
                })
                .peek(expert -> expert.setApprovalTime(new Date())) // 设置 approvalTime 为当前时间
                .collect(Collectors.toList());

            // 获取当前用户部门
            List<RemoteDeptBo> remoteDeptBos = remoteDeptService.selectDeptInfoByTenantId(LoginHelper.getTenantId());
            String tenantId = LoginHelper.getTenantId();
            String password = remoteConfigService.selectConfigByKey("expert.import.password");
            if (StringUtils.isEmpty(password)) {
                password = "k6psy7kafT%U";
            }
            // 用户信息生成
            for (ZjkExpertBo expert : filteredZjkExpertVos) {
                RemoteUserBo remoteUserBo = new RemoteUserBo();
                remoteUserBo.setUserName(expert.getIdCard());
                remoteUserBo.setNickName(expert.getExpertName());
                remoteUserBo.setIdCard(expert.getIdCard());
                remoteUserBo.setPhonenumber(expert.getContact());
                remoteUserBo.setPassword(BCrypt.hashpw(password));
                remoteUserBo.setTenantId(tenantId);
                remoteUserBo.setSource("30");
                remoteUserBo.setSourceTenant(2);
                remoteUserBo.setDeptId(remoteDeptBos.get(0).getDeptId());
                remoteUserBoList.add(remoteUserBo);
            }
            // 用户注册
            remoteUserService.expertRegisterUserInfo(remoteUserBoList, tenantId);
            // 手机号转 list
            List<String> phoneNumbers = filteredZjkExpertVos.stream()
                .map(ZjkExpertBo::getIdCard)
                .collect(Collectors.toList());
            // 根据手机号列表获取用户对象
            List<RemoteUserVo> fetchedUsers = remoteUserService.selectListByUserName(phoneNumbers);
            // 将 fetchedUsers 转换为 Map，键为手机号，值为用户 ID
            Map<String, Long> userNameToUserIdMap = fetchedUsers.stream()
                .collect(Collectors.toMap(RemoteUserVo::getUserName, RemoteUserVo::getUserId));
            // 遍历 filteredZjkExpertVos，匹配 userName 并赋值 userId
            filteredZjkExpertVos.forEach(expert -> {
                Long userId = userNameToUserIdMap.get(expert.getIdCard());
                if (userId != null) {
                    expert.setUserId(userId);
                }
            });
            insertList(filteredZjkExpertVos);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("导入失败请联系管理员");
        }

        return new ArrayList<>();
    }

    @Override
    public Long getExpertCount() {
        LambdaQueryWrapper<ZjkExpert> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ZjkExpert::getStatus, ZjkExpertTypeEnum.NORMAL.getCode());
        return baseMapper.selectCount(wrapper);
    }

    @Override
    public ExpertBaseInfo getExpertBaseInfo() {
        Long userId = LoginHelper.getUserId();
        ExpertBaseInfo expertBaseInfo = baseMapper.getExpertBaseInfo(userId);
        if (expertBaseInfo == null) {
            expertBaseInfo = new ExpertBaseInfo();
        }
        ZjkExpert zjkExpert = baseMapper.selectOne(
            new LambdaQueryWrapper<ZjkExpert>()
                .eq(ZjkExpert::getUserId, userId)
                .eq(ZjkExpert::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL)
        );
        if (zjkExpert == null) {
            throw new ServiceException("当前用户不存在专家信息");
        }
        if (StringUtils.isNotEmpty(zjkExpert.getPhotograph())) {
            expertBaseInfo.setPhotograph(
                (zjkExpert.getPhotograph() != null && !zjkExpert.getPhotograph().isEmpty())
                    ? zjkExpert.getPhotograph()
                    : null
            );
        }
        // 获取评审项目次数
        expertBaseInfo.setReviewProjectCount(zjkReviewPhaseService.getReviewProductCountByExpertId(zjkExpert.getExpertId()));
        // 获取请假总次数
        expertBaseInfo.setLeaveCount(zjkLeaveMapper.selectCount(new LambdaQueryWrapper<ZjkLeave>().eq(ZjkLeave::getCreateBy, userId).eq(ZjkLeave::getStatus, 1)));
        // 获取专家互评人数
        expertBaseInfo.setEvaluateCount(zjkEvaluateMapper.selectCount(new LambdaQueryWrapper<ZjkEvaluate>().eq(ZjkEvaluate::getCreateBy, userId)));
        // 获取当前专家的请假时间
        ZjkLeave zjkLeave = zjkLeaveMapper.selectOne(new LambdaQueryWrapper<ZjkLeave>().eq(ZjkLeave::getStatus, 1).eq(ZjkLeave::getCreateBy, userId).last("limit 1"));
        if (zjkLeave != null) {
            if (DateUtils.isWithinLeavePeriod(new Date(), zjkLeave.getStartDate(), zjkLeave.getEndDate())) {
                expertBaseInfo.setStartDate(zjkLeave.getStartDate());
                expertBaseInfo.setEndDate(zjkLeave.getEndDate());
            }
        }
        return expertBaseInfo;
    }

    @Override
    public List<ExpertPerformWorkCountVO> getExpertPerformWorkCount(Integer days) {
        if (days != null) {
            DateRange dateRange = DateUtils.getDateRange(days);
            return baseMapper.getExpertPerformWorkCount(dateRange);
        } else {
            return baseMapper.getExpertPerformWorkCount(null);
        }
    }


    /**
     * 总体流程监听(例如: 提交 退回 撤销 终止 作废等)
     * 正常使用只需#processEvent.key=='leave1'
     * 示例为了方便则使用startsWith匹配了全部示例key
     *
     * @param processEvent 参数
     */
    @EventListener(condition = "#processEvent.key.startsWith('zjsq')")
    public void processHandler(ProcessEvent processEvent) {
        // 专家申请撤销
        if (BusinessStatusEnum.CANCEL.getStatus().equals(processEvent.getStatus())) {
            // 监听工作流撤销操作进行撤销
            this.expertQuash(2, processEvent.getBusinessKey());
        }
        log.info("当前任务执行了{}", processEvent.toString());
    }


    /**
     * 总体流程监听(例如: 提交 退回 撤销 终止 作废等)
     * 正常使用只需#processEvent.key=='leave1'
     * 示例为了方便则使用startsWith匹配了全部示例key
     *
     * @param processTaskEvent 参数
     */
    @EventListener(condition = "#processTaskEvent.key=='zjsq' && #processTaskEvent.taskDefinitionKey=='Activity_19je674'")
    public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
        log.info("当前任务执行了{}", processTaskEvent.toString());
    }


    @Override
    public List<ExpertPerformWorkCountVO> getUnitCount() {
        return baseMapper.getUnitCount();
    }

    @Override
    public List<ExpertPerformWorkCountVO> getPoliticsCount() {
        return baseMapper.getPoliticsCount();
    }

    @Override
    public List<Map<String, Integer>> getAgeRangeStatistics() {
        return baseMapper.getAgeRangeStatistics();
    }

    @Override
    public List<Map<String, Integer>> workProfessialYear() {
        return baseMapper.workProfessialYear();
    }

    @Override
    public List<Map<String, Integer>> getApprovalTimeAnalysis(String startTime, String endTime) {
        if (StringUtils.isBlank(startTime) || StringUtils.isBlank(endTime)) {
            String[] times = DateUtils.getCurrentMonthDateRange();
            return baseMapper.getApprovalTimeAnalysis(times[0], times[1]);
        } else {
            return baseMapper.getApprovalTimeAnalysis(startTime, endTime);
        }
    }

    @Override
    public Long getApprovalTimeCountThisYear() {
        return baseMapper.getApprovalTimeCountThisYear();
    }

    @Override
    public List<ZjkExpert> getPhonesById(List<Long> receiveUserIds) {
        return baseMapper.getPhonesById(receiveUserIds);
    }

    @Override
    public Long getUserIdByPhone(String tel) {
        return baseMapper.getUserIdByPhone(tel);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void fetchRemoteProfessors() {
        // 初始页面参数
        int currentPage = 1;
        int pageSize = 10; // 每页10条数据
        ProfessorsDto allProfessorsDto = new ProfessorsDto(); // 用于存储所有请求到的数据
        int totalPage = 1; // 默认总页数为1

        try {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

            // 使用循环动态获取每一页数据
            while (currentPage <= totalPage) {
                String url = professorList + "?pageNumber=" + currentPage + "&pageSize=" + pageSize;
                String response = HttpUtil.createGet(url).execute().body();
//                String response = "{\"code\":\"00000\",\"msg\":\"操作成功\",\"data\":{\"data\":\"fx/cZTfDSwcPlU9Lgkud8WIe66mxnyHwO/OKG3WKfqRk0AcMGufIdvVZB4HT7ASPbXngSbZXABXzoHhC6kiUS7jE3EgyYqgLQoLO4+1az6cqjGaFT+GH3tZ87CCMM4nsN0O3FzD6h1jydUhHirkVLmqT76SO1czXEqIXxbNGl6YhzXV8k4oQXOZAnXnXwCZX5yYitsJKrxllHuCTEAsISWhWTx3BS5gDFA3Qr7rzJgJ9PFQrvzAw9G/5K3v6BSwEwhDradTJUkchzIgIGIg2PNlGN1Onajz6IAUk+WV7obgHCAy9DTXt+34Tu48xuGA4g7coNziI7GzAG3tCx2ldO2XaRDCTnRb+unRbXXU9q7iSx/Cz7z7oLvid9sOK7VHqzim8XXc6XoaVT6ShqsLK5xEum8+zc6m8CzM4CZy5WMAXIgXbLybaTZ0FmK8tqFFB2NGhrSa13RdNs7PMU5Wsl2b/Ml4g3d3uzgD1zVCeHg1GulGhxehvhYMbeVyOWCGjDw6zw8J3EjBXrQKFIeczMga4EQuXWIp3+hJZvs4YIsvRvK0u6/Bs2IK+cThyKADUMKCuGLPWrueEapZ3zcdWGRCtan6+0GM+pyQw1ko1YnfUhE5HLvSgeaMUZlCjT+D3H2ucwSRimkBGDh+M9qdudx5YZBLwj6rnNbHqVLxE9Dhs+2sVCxIJslChxD7eJkR2CrUBGejJOoXGglcjcOUSkuYclmguJSelEeGHy/AFwRFe5G+LUF/Hfr0Lt+dpA4RV9eg4smaq8yCyaYUs+sjJg6dI8MjTDPL7JWjo9ginMDMbgbj3ZNxtzFdUswq/Z5J/FJ3H1wzSyaXKo9XRN/yebTB30XTdePLWfnOron/KDW0uXHU/UMXHefc6yX970c8PbZR+rUxYl0ow53f78HS2+o8cPUNTowC9VLQvlHgpmuuT1QMBFrV22MyBgBE7pBdWhdytC0pj96P9Bb+JBeSouFAxdM9U1qs5c5e8/xn9p7cgviMrYzAVEXK4Hy4rKel0MtdqrJZaF32Qd9Ke8ZVaP2geaDhI/TRAGUiJ3HDzDwxteeBJtlcAFfOgeELqSJRLLhJCOwxl4L4e47Pv80esk6Tp41+P3CGG7j1ljPZYaE47c6FfWh4aD3BdjOv7K5qhx3ZF5sErxAgJI/YTJmi1PoSG6P4UlOkWdXSjVBod3qrUVNUksXruaCg2duoT7y0sHGZv0CpBWf0Z/zr/1RJNYg2YJQ4AqTOVeyANRJe162TkdMs1Jm814a9lvGB6z0hL3l/iZE4N+AFQGcqhyCrMMPtGa+HwAQU5Fd0GRxW4thgqHAvElGaHTBa0xTyPS71xXkm73MykIPeMHZQ6Bzma1mXaRDCTnRb+unRbXXU9q7iplJEujP5XfYRMg2yHv6upFJ3H1wzSyaXKo9XRN/yebcbr98MkDGjBVqf5ugl/paV/pTx2FimbVdKzRaFGE7G6pNcUylm2NeQGbOUl/zDYslbbpHxvP/XJKDE+Bn5OVvMLsDS3VlsBQ6Oh5J6hoRXIYtoA/7b0CjJtcvYMngn5P7kUwbmaRo+0zgOuCOVzA0gP/fKw1lSGyEJa+Nq5bEto\"}}";
                JSONObject jsonResponse = JSON.parseObject(response);

                if (!"00000".equals(jsonResponse.getString("code"))) {
                    break;
                }

                // 获取最里面的 "data" 并解密
                String innerData = AesUtils.decrypt(jsonResponse.getJSONObject("data").getString("data"), "KlzY40Xw2wywV9Me");

                // 将响应数据转化为 ProfessorsDto 对象
                ProfessorsDto dto = objectMapper.readValue(innerData, ProfessorsDto.class);

                if (currentPage == 1) {
                    // 初始化分页信息
                    allProfessorsDto.setTotalPage(dto.getTotalPage());
                    allProfessorsDto.setTotalRow(dto.getTotalRow());
                    allProfessorsDto.setPageSize(dto.getPageSize());
                }

                // 合并数据
                allProfessorsDto.getList().addAll(dto.getList());
                totalPage = dto.getTotalPage(); // 更新总页数
                currentPage++; // 获取下一页数据
            }

            // 数据拷贝转化
            List<ZjkExpertBo> zjkExpertBos = allProfessorsDto.getList().stream()
                .map(professor -> {
                    ZjkExpertBo expertBo = new ZjkExpertBo();
                    BeanUtils.copyProperties(professor, expertBo);
                    return expertBo;
                })
                .toList();

            // 提取身份证号
            List<String> idCards = zjkExpertBos.stream()
                .map(ZjkExpertBo::getIdCard)
                .filter(idCard -> idCard != null && !idCard.trim().isEmpty())
                .collect(Collectors.toList());

            // 查询已存在的身份证号
            List<String> existingIdCards = baseMapper.selectExistingIdCards(idCards);

            // 过滤重复记录并设置额外字段
            List<ZjkExpertBo> filteredZjkExpertBos = zjkExpertBos.stream()
                .filter(expert -> !existingIdCards.contains(expert.getIdCard()) && StringUtils.isNotBlank(expert.getIdCard()))
                .peek(expert -> {
                    expert.setApprovalTime(new Date()); // 设置审批时间

                    // 提取出生日期
                    String idCard = expert.getIdCard();
                    if (idCard.length() == 18) {
                        try {
                            String birthDateString = idCard.substring(6, 14);
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                            expert.setBirthDate(sdf.parse(birthDateString));
                        } catch (ParseException e) {
                            throw new RuntimeException("Invalid ID card format", e);
                        }
                    }
                })
                .toList();

            // 获取当前用户部门信息
            List<RemoteDeptBo> remoteDeptBos = remoteDeptService.selectDeptInfoByTenantId(LoginHelper.getTenantId());
            String tenantId = LoginHelper.getTenantId();
            String password = StringUtils.defaultIfEmpty(
                remoteConfigService.selectConfigByKey("expert.import.password"),
                "k6psy7kafT%U"
            );
            // 构造 RemoteUserBo 列表
            List<RemoteUserBo> remoteUserBoList = filteredZjkExpertBos.stream()
                .map(expert -> {
                    RemoteUserBo userBo = new RemoteUserBo();
                    userBo.setUserName(expert.getIdCard());
                    userBo.setNickName(expert.getExpertName());
                    userBo.setIdCard(expert.getIdCard());
                    userBo.setPhonenumber(expert.getContact());
                    userBo.setPassword(BCrypt.hashpw(password));
                    userBo.setTenantId(tenantId);
                    userBo.setSource("30");
                    userBo.setSourceTenant(2);
                    userBo.setDeptId(remoteDeptBos.get(0).getDeptId());
                    return userBo;
                })
                .toList();

            // 用户注册
            remoteUserService.expertRegisterUserInfo(remoteUserBoList, tenantId);

            // 根据手机号获取用户信息
            List<String> phoneNumbers = filteredZjkExpertBos.stream()
                .map(ZjkExpertBo::getIdCard)
                .toList();

            List<RemoteUserVo> fetchedUsers = remoteUserService.selectListByUserName(phoneNumbers);

            // 转换为 Map (手机号 -> 用户 ID)
            Map<String, Long> userNameToUserIdMap = fetchedUsers.stream()
                .collect(Collectors.toMap(RemoteUserVo::getUserName, RemoteUserVo::getUserId));

            // 匹配用户 ID 并赋值
            filteredZjkExpertBos.forEach(expert -> {
                Long userId = userNameToUserIdMap.get(expert.getIdCard());
                if (userId != null) {
                    expert.setUserId(userId);
                }
            });

            // 数据落库
            insertList(filteredZjkExpertBos);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
