package jnpf.cultivate.v2.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jnpf.base.UserInfo;
import jnpf.cultivate.mapper.CultivateIdentifyApplyDetailsMapper;
import jnpf.cultivate.mapper.CultivateIdentifyApplyMapper;
import jnpf.cultivate.service.*;
import jnpf.cultivate.service.impl.FtbCultivateFileService;
import jnpf.cultivate.utils.UserApiV2Util;
import jnpf.cultivate.v2.service.FtbCultivateLabelService;
import jnpf.cultivate.v2.service.V2CultivateCertificateService;
import jnpf.cultivate.v2.service.V2CultivateIdentifyApplyService;
import jnpf.cultivate.v2.util.CultivateIdentityUtil;
import jnpf.cultivate.v2.util.CultivateMqSendUtil;
import jnpf.entity.cultivate.*;
import jnpf.enums.cultivate.ApplyResultEnum;
import jnpf.enums.cultivate.ApplyStatusEnum;
import jnpf.enums.cultivate.IdentifyItemExceptionEnum;
import jnpf.model.cultivate.event.JnpfApplicationEvent;
import jnpf.model.cultivate.event.dto.file.FileEventDTO;
import jnpf.model.cultivate.po.FtbCultivateFile;
import jnpf.model.cultivate.po.label.FtbCultivateLabel;
import jnpf.model.cultivate.v2.apply.req.*;
import jnpf.model.cultivate.v2.apply.vo.*;
import jnpf.model.cultivate.v2.identify.vo.V2IdentifyTableScoreConfigVo;
import jnpf.model.cultivate.vo.common.InnerPowerUserVO;
import jnpf.model.cultivate.vo.identify.IdentifyApplyDetailsInfoVo;
import jnpf.model.cultivate.vo.offline.FtbCultivateOfflineFileVO;
import jnpf.model.personnels.dto.staff.roster.FtbPersonnelsStaffRosterDto;
import jnpf.model.personnels.req.roster.StaffRosterListReq;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.permission.vo.v2.user.UserPageListVO;
import jnpf.personnels.service.FtbPersonnelsStaffRosterService;
import jnpf.util.*;
import jnpf.util.context.SpringContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class V2CultivateIdentifyApplyServiceImpl implements V2CultivateIdentifyApplyService {


    @Autowired
    private UserApiV2Util userApiV2Util;

    @Autowired
    private CultivateIdentifyTableService identifyTableService;
    @Autowired
    private CultivateIdentifyItemsService identifyItemsService;
    @Autowired
    private CultivateIdentifyApplyDetailsMapper applyDetailsMapper;
    @Autowired
    private CultivateIdentifyApplyDetailsService applyDetailsService;

    @Autowired
    private CultivateIdentifyApplyTableBackupsService applyTableBackupsService;
    @Autowired
    private CultivateIdentifyApplyDetailsBackupsService applyDetailsBackupsService;

    @Autowired
    private FtbCultivateFileService ftbCultivateFileService;


    @Autowired
    private CultivateIdentifyApplyMapper baseMapper;

    @Autowired
    private CultivateMqSendUtil cultivateMqSendUtil;

    @Autowired
    private V2CultivateCertificateService v2CultivateCertificateService;

    @Autowired
    private FtbCultivateLabelService ftbCultivateLabelService;

    @Autowired
    private FtbPersonnelsStaffRosterService staffRosterService;

    /**
     * 获取Web端培养鉴定申请列表的分页数据
     *
     * @param req 查询条件请求对象，包含分页信息和筛选条件
     * @return 分页结果对象，包含申请列表数据和分页信息
     */
    @Override
    public Page<V2IdentifyApplyListVo> getWebPageApplyList(V2IdentifyApplyListReq req) {
        Page<V2IdentifyApplyListVo> page = Page.of(req.getCurrentPage(), req.getPageSize());
        InnerPowerUserVO innerPowerUserVO = userApiV2Util.getLoginManagerUserIdsForEncode();
        if (innerPowerUserVO.getCode() == 1) {
            req.setInnerPowerUserIds(innerPowerUserVO.getUserIds());
        } else if (innerPowerUserVO.getCode() == 0) {
            req.setInnerPowerUserIds(new ArrayList<>());
        } else {
            return page;
        }
        if (StringUtil.isNotEmpty(req.getOrgId())) {
            List<UserPageListVO> userListForOrgIds = userApiV2Util.getUserListForOrgIds(List.of(req.getOrgId()), null);
            if (CollUtil.isEmpty(userListForOrgIds)) {
                return page;
            }
            if (CollUtil.isNotEmpty(req.getInnerPowerUserIds())) {
                List<String> intersection = UserApiV2Util.getIntersection(req.getInnerPowerUserIds(), userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList()));
                if (CollUtil.isEmpty(intersection)) {
                    return page;
                }
                req.setInnerPowerUserIds(intersection);
            } else {
                req.setInnerPowerUserIds(userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList()));
            }
        }
        if (StrUtil.isNotBlank(req.getKeyword())){
            //查询用户信息 通过用户名称模糊搜索出用户ID集合
            StaffRosterListReq rosterListReq = new StaffRosterListReq();
            rosterListReq.setIsQueryAuth("0");
            rosterListReq.setLikeUserName(req.getKeyword());
            List<FtbPersonnelsStaffRosterDto> rosterDtos = staffRosterService.postWithSalaryNoPage(rosterListReq);
            req.setUserIdsKeyWord(rosterDtos.stream()
                    .map(FtbPersonnelsStaffRosterDto::getUserId)
                    .filter(StrUtil::isNotEmpty)
                    .collect(Collectors.toList()));
        }
        page = this.baseMapper.getPageListV2(page, req);
        if (CollUtil.isNotEmpty(page.getRecords())) {
            //查询到人员名称-服务调用
            List<String> userIdList = new ArrayList<>();
            for (V2IdentifyApplyListVo record : page.getRecords()) {
                userIdList.add(record.getBeIdentifyUserId());
                if (StringUtil.isNotEmpty(record.getIdentifyUserId())) {
                    userIdList.addAll(List.of(record.getIdentifyUserId().split(",")));
                }
            }
            Map<String, UserBoundVO> userMap = userApiV2Util.getUserPrimaryBoundBatch(userIdList, null);

            for (V2IdentifyApplyListVo item : page.getRecords()) {
                UserBoundVO beUserInfoVo = userMap.get(item.getBeIdentifyUserId());
                // 获取用户头像
                if (Objects.nonNull(beUserInfoVo) && !StringUtil.isEmpty(beUserInfoVo.getHeadIcon())) {
                    item.setBeIdentifyUserInfo(beUserInfoVo);
                }
                if (StringUtil.isNotEmpty(item.getIdentifyUserId())) {
                    List<UserBoundVO> identifyUserInfo = new ArrayList<>();
                    for (String tempId : item.getIdentifyUserId().split(",")) {
                        //鉴定用户信息
                        UserBoundVO userInfoVo = userMap.get(tempId);
                        // 获取用户头像
                        if (Objects.nonNull(userInfoVo)) {
                            identifyUserInfo.add(userInfoVo);
                        }
                    }
                    item.setIdentifyUserInfo(identifyUserInfo);
                }
            }
        }
        return page;
    }

    /**
     * 根据ID获取Web端培养鉴定申请的基本信息
     *
     * @param id 申请记录的唯一标识符
     * @return 申请的基本信息对象
     */
    @Override
    public V2IdentifyApplyBasicInfoVo getWebApplyBasicInfo(String id) {
        CultivateIdentifyApply apply = queryAndCheckApply(id);
        CultivateIdentifyApplyTableBackups table = this.applyTableBackupsService.getById(apply.getTableId());
        ServiceException.notNull(table, "未查询到实操鉴定表记录");
        V2IdentifyApplyBasicInfoVo applyBasicInfoVo = new V2IdentifyApplyBasicInfoVo();
        BeanUtils.copyProperties(apply, applyBasicInfoVo);

        applyBasicInfoVo.setId(apply.getId());
        applyBasicInfoVo.setTableId(table.getTableId());
        applyBasicInfoVo.setTableName(table.getName());
        applyBasicInfoVo.setRuleId(table.getRuleId());
        applyBasicInfoVo.setLabelId(table.getLabelId());
        if (StringUtil.isNotEmpty(table.getLabelId())) {
            FtbCultivateLabel label = ftbCultivateLabelService.getById(table.getLabelId());
            if (label != null) {
                applyBasicInfoVo.setLabelName(label.getName());
            }
        } else {
            applyBasicInfoVo.setLabelName("未设置分类");
        }
        String beIdentifyUserId = apply.getBeIdentifyUserId();

        List<String> userIds = new ArrayList<>();
        if (StringUtil.isNotEmpty(apply.getIdentifyUserId())) {
            userIds.addAll(List.of(apply.getIdentifyUserId().split(",")));
        }
        userIds.add(beIdentifyUserId);

        Map<String, UserBoundVO> userMap = userApiV2Util.getUserPrimaryBoundBatch(userIds, null);
        applyBasicInfoVo.setBeIdentifyUserInfo(userMap.get(beIdentifyUserId));


        //鉴定用户信息
        List<UserBoundVO> identifyUserInfo = new ArrayList<>();
        if (StringUtil.isNotEmpty(apply.getIdentifyUserId())) {
            for (String s : apply.getIdentifyUserId().split(",")) {
                UserBoundVO userBoundVO = userMap.get(s);
                if (userBoundVO != null) {
                    identifyUserInfo.add(userBoundVO);
                }
            }
        }

        applyBasicInfoVo.setIdentifyUserInfo(identifyUserInfo);
        return applyBasicInfoVo;
    }

    private CultivateIdentifyApply queryAndCheckApply(String id) {
        CultivateIdentifyApply apply = this.baseMapper.selectById(id);
        if (apply == null || apply.getDeleteMark().equals(1)) {
            throw new ServiceException("鉴定不存在或者已经删除");
        }
        return apply;
    }

    @Override
    public V2IdentifyApplyAppBasicInfoVo getAppApplyBasicInfo(String id) {
        CultivateIdentifyApply apply = queryAndCheckApply(id);
        CultivateIdentifyApplyTableBackups table = this.applyTableBackupsService.getById(apply.getTableId());
        ServiceException.notNull(table, "未查询到实操鉴定表记录");
        V2IdentifyApplyAppBasicInfoVo applyBasicInfoVo = new V2IdentifyApplyAppBasicInfoVo();
        BeanUtils.copyProperties(apply, applyBasicInfoVo);

        applyBasicInfoVo.setId(apply.getId());
        applyBasicInfoVo.setTableId(table.getTableId());
        applyBasicInfoVo.setTableName(table.getName());
        applyBasicInfoVo.setRuleId(table.getRuleId());
        applyBasicInfoVo.setCoverUrl(table.getCoverUrl());
        applyBasicInfoVo.setScoreType(table.getScoreType());
        applyBasicInfoVo.setRuleDesc(table.getRuleDesc());
        applyBasicInfoVo.setPassType(table.getPassType());
        applyBasicInfoVo.setPassScore(table.getPassScore());
        applyBasicInfoVo.setExcellentType(table.getExcellentType());
        applyBasicInfoVo.setExcellentScore(table.getExcellentScore());
        applyBasicInfoVo.setIdentifyTime(apply.getIdentifyTime());
        if (StringUtil.isNotEmpty(table.getScoreConfig())) {
            applyBasicInfoVo.setScoreConfig(JSON.parseArray(table.getScoreConfig(), V2IdentifyTableScoreConfigVo.class));
        }
        applyBasicInfoVo.setCertificateId(table.getCertificateId());
        String beIdentifyUserId = apply.getBeIdentifyUserId();

        List<String> userIds = new ArrayList<>();
        if (StringUtil.isNotEmpty(apply.getIdentifyUserId())) {
            userIds.addAll(List.of(apply.getIdentifyUserId().split(",")));
        }
        userIds.add(beIdentifyUserId);

        Map<String, UserBoundVO> userMap = userApiV2Util.getUserPrimaryBoundBatch(userIds, null);
        applyBasicInfoVo.setBeIdentifyUserInfo(userMap.get(beIdentifyUserId));


        //鉴定用户信息
        List<UserBoundVO> identifyUserInfo = new ArrayList<>();
        if (StringUtil.isNotEmpty(apply.getIdentifyUserId())) {
            for (String s : apply.getIdentifyUserId().split(",")) {
                UserBoundVO userBoundVO = userMap.get(s);
                if (userBoundVO != null) {
                    identifyUserInfo.add(userBoundVO);
                }
            }
        }
        applyBasicInfoVo.setIdentifyUserInfo(identifyUserInfo);

        LambdaQueryWrapper<CultivateIdentifyApplyDetailsBackups> itemsLambdaQueryWrapper = new LambdaQueryWrapper<CultivateIdentifyApplyDetailsBackups>()
                .eq(CultivateIdentifyApplyDetailsBackups::getTableId, table.getId())
                .eq(CultivateIdentifyApplyDetailsBackups::getDeleteMark, ConstantUtil.NUM_FALSE);
        List<CultivateIdentifyApplyDetailsBackups> identifyItemsList = this.applyDetailsBackupsService.list(itemsLambdaQueryWrapper);
        BigDecimal totalScore = CultivateIdentityUtil.calIdentityTotalScore(identifyItemsList);
        applyBasicInfoVo.setItemNum(identifyItemsList.size());
        applyBasicInfoVo.setShowScoreConfig(CultivateIdentityUtil.calPassAndExcellentResult(totalScore, table));

        return applyBasicInfoVo;
    }

    @Override
    public V2IdentifyApplyItemVo itemList(String id) {
        CultivateIdentifyApply apply = queryAndCheckApply(id);
        CultivateIdentifyApplyTableBackups table = this.applyTableBackupsService.getById(apply.getTableId());
        ServiceException.notNull(table, "未查询到实操鉴定表记录");
        V2IdentifyApplyItemVo applyBasicInfoVo = new V2IdentifyApplyItemVo();
        BeanUtils.copyProperties(apply, applyBasicInfoVo);

        applyBasicInfoVo.setId(apply.getId());
        applyBasicInfoVo.setTableId(table.getTableId());
        applyBasicInfoVo.setTableName(table.getName());
        applyBasicInfoVo.setRuleId(table.getRuleId());
        applyBasicInfoVo.setCoverUrl(table.getCoverUrl());
        applyBasicInfoVo.setScoreType(table.getScoreType());
        applyBasicInfoVo.setRuleDesc(table.getRuleDesc());
        applyBasicInfoVo.setPassType(table.getPassType());
        applyBasicInfoVo.setPassScore(table.getPassScore());
        applyBasicInfoVo.setExcellentType(table.getExcellentType());
        applyBasicInfoVo.setExcellentScore(table.getExcellentScore());
        if (StringUtil.isNotEmpty(table.getScoreConfig())) {
            applyBasicInfoVo.setScoreConfig(JSON.parseArray(table.getScoreConfig(), V2IdentifyTableScoreConfigVo.class));
        }
        applyBasicInfoVo.setCertificateId(table.getCertificateId());
        String beIdentifyUserId = apply.getBeIdentifyUserId();

        List<String> userIds = new ArrayList<>();
        if (StringUtil.isNotEmpty(apply.getIdentifyUserId())) {
            userIds.addAll(List.of(apply.getIdentifyUserId().split(",")));
        }
        userIds.add(beIdentifyUserId);

        Map<String, UserBoundVO> userMap = userApiV2Util.getUserPrimaryBoundBatch(userIds, null);
        applyBasicInfoVo.setBeIdentifyUserInfo(userMap.get(beIdentifyUserId));


        //鉴定用户信息
        List<UserBoundVO> identifyUserInfo = new ArrayList<>();
        if (StringUtil.isNotEmpty(apply.getIdentifyUserId())) {
            for (String s : apply.getIdentifyUserId().split(",")) {
                UserBoundVO userBoundVO = userMap.get(s);
                if (userBoundVO != null) {
                    identifyUserInfo.add(userBoundVO);
                }
            }
        }
        applyBasicInfoVo.setIdentifyUserInfo(identifyUserInfo);


        //设置鉴定项得分集合
        List<IdentifyApplyDetailsInfoVo> detailsInfoVos = this.applyDetailsMapper.getIdentifyItemList(apply.getId());
        if (CollUtil.isNotEmpty(detailsInfoVos)) {
            List<String> tempIds = new ArrayList<>();
            BigDecimal totalScore = new BigDecimal(0);
            for (IdentifyApplyDetailsInfoVo detailsInfoVo : detailsInfoVos) {
                tempIds.add(detailsInfoVo.getId());
                if (detailsInfoVo.getType().equals(0)) {
                    totalScore = totalScore.add(detailsInfoVo.getTotalScore());
                } else {
                    totalScore = totalScore.add(new BigDecimal(detailsInfoVo.getMaxScore()));
                }
            }
            applyBasicInfoVo.setIdentifyItemList(detailsInfoVos);
            List<FtbCultivateFile> fileItemLists = queryFilesLists(tempIds);
            if (CollUtil.isNotEmpty(fileItemLists)) {
                //按照businessId 分组
                Map<String, List<FtbCultivateFile>> fileItemMap = fileItemLists.stream().collect(Collectors.groupingBy(FtbCultivateFile::getBusinessId));
                for (IdentifyApplyDetailsInfoVo detailsInfoVo : detailsInfoVos) {
                    List<FtbCultivateFile> fileItemList = fileItemMap.get(detailsInfoVo.getId());
                    if (CollUtil.isNotEmpty(fileItemList)) {
                        detailsInfoVo.setFiles(fileItemList.stream().map(FtbCultivateOfflineFileVO::convertFtbCultivateOfflineFileVO).collect(Collectors.toList()));
                    }
                }
            }

            applyBasicInfoVo.setShowScoreConfig(CultivateIdentityUtil.calPassAndExcellentResult(totalScore, table));


        } else {
            applyBasicInfoVo.setIdentifyItemList(CollUtil.newArrayList());
            applyBasicInfoVo.setTotalScore(null);
            applyBasicInfoVo.setUserTime(null);
            applyBasicInfoVo.setResult(null);
        }
        List<String> applyFileIds = new ArrayList<>();
        applyFileIds.add(apply.getId());
        applyFileIds.add(apply.getId() + apply.getBeIdentifyUserId());

        List<FtbCultivateFile> applyFileList = queryFilesLists(applyFileIds);

        applyBasicInfoVo.setFiles(applyFileList.stream().map(FtbCultivateOfflineFileVO::convertFtbCultivateOfflineFileVO).collect(Collectors.toList()));


        return applyBasicInfoVo;
    }

    @Override
    @Transactional
    public void applyDataSubmit(V2IdentifyApplySubmitReq req) {

        String userId = UserProvider.getLoginUserId();
        String tenantId = UserProvider.getUser().getTenantId();
        CultivateIdentifyApply apply = this.baseMapper.selectById(req.getId());
        if (apply == null || apply.getDeleteMark().equals(1)) {
            throw new ServiceException("鉴定不存在或者已经删除");
        }
        if (userId.equals(apply.getBeIdentifyUserId())) {
            throw new ServiceException("对不起,不能够自己给自己鉴定");
        }
        if (apply.getStatus().equals(1)) {
            throw new ServiceException("该鉴定已完成");
        }

        CultivateIdentifyApplyTableBackups table = this.applyTableBackupsService.getById(apply.getTableId());
        ServiceException.notNull(table, "未查询到实操鉴定表记录");

        LambdaQueryWrapper<CultivateIdentifyApplyDetailsBackups> itemsLambdaQueryWrapper = new LambdaQueryWrapper<CultivateIdentifyApplyDetailsBackups>()
                .eq(CultivateIdentifyApplyDetailsBackups::getTableId, table.getId())
                .eq(CultivateIdentifyApplyDetailsBackups::getDeleteMark, ConstantUtil.NUM_FALSE);
        List<CultivateIdentifyApplyDetailsBackups> identifyItemsList = this.applyDetailsBackupsService.list(itemsLambdaQueryWrapper);
        ServiceException.notNull(identifyItemsList, "未查询到实操鉴定项记录");

        //计算鉴定总分
        BigDecimal totalScore = CultivateIdentityUtil.calIdentityTotalScore(identifyItemsList);
        //计算总得分
        BigDecimal userTotalScore = CultivateIdentityUtil.calUserTotalScore(req.getIdentifyItemList());
//        0-合格，1-优秀，2-不合格
        MutablePair<Integer, String> pair = CultivateIdentityUtil.calUserIdentifyResult(table, totalScore, userTotalScore);

        apply.setResult(pair.left);
        apply.setGradeName(pair.right);
        apply.setTotalScore(totalScore);
        apply.setUserTotalScore(userTotalScore);
        //变更为已鉴定
        apply.setStatus(ApplyStatusEnum.YJD.getCode());
        apply.setIdentifyTime(new Date());
        apply.setUseTime((int) DateUtil.between(new Date(), apply.getCreatorTime(), DateUnit.MINUTE));
        apply.setIdentifyUserId(userId);
        this.baseMapper.updateById(apply);

        List<CultivateIdentifyApplyDetails> applyDetailsList = new ArrayList<>();
        if (CollUtil.isNotEmpty(req.getIdentifyItemList())) {
            for (V2IdentifyApplyItemReq v2IdentifyApplyItemReq : req.getIdentifyItemList()) {
                CultivateIdentifyApplyDetails applyDetails = new CultivateIdentifyApplyDetails();
                applyDetails.setId(v2IdentifyApplyItemReq.getId());
                applyDetails.setScore(v2IdentifyApplyItemReq.getIdentifyScore());
                applyDetails.setDeleteMark(0);
                applyDetails.setRemark(v2IdentifyApplyItemReq.getRemark());
                applyDetailsList.add(applyDetails);
            }
            this.applyDetailsService.updateBatchById(applyDetailsList);
        }

        if (CollUtil.isNotEmpty(applyDetailsList)) {
            for (V2IdentifyApplyItemReq v2IdentifyApplyItemReq : req.getIdentifyItemList()) {
                if (CollUtil.isNotEmpty(v2IdentifyApplyItemReq.getFiles())) {
                    SpringContext.getApplicationContext().publishEvent(new JnpfApplicationEvent<>(FileEventDTO.builder()
                            .files(v2IdentifyApplyItemReq.getFiles())
                            .businessTypeID(v2IdentifyApplyItemReq.getId())
                            .type(FileEventDTO.FileType.PRACTICAL_APPRAISAL_ITEM).build()));
                }
            }
        }
        if (StringUtil.isNotEmpty(table.getCertificateId())) {
            if (apply.getResult().equals(0) || apply.getResult().equals(1)) {
                if (apply.getSource().equals(0) || apply.getSource().equals(1) || apply.getSource().equals(3)) {
                    v2CultivateCertificateService.triggerCertificate(apply.getBeIdentifyUserId(), table.getCertificateId(), tenantId);
                }
            }
        }
        cultivateMqSendUtil.sendIdentityCompletionMessage(apply, table.getTableId());
    }


    public List<FtbCultivateFile> queryFilesLists(List<String> businessIds) {
        LambdaQueryWrapper<FtbCultivateFile> wrapperItemFile = Wrappers.lambdaQuery();
        wrapperItemFile.in(FtbCultivateFile::getBusinessId, businessIds);
        wrapperItemFile.eq(FtbCultivateFile::getEnabledMark, 0);
        wrapperItemFile.orderByAsc(FtbCultivateFile::getCreatorTime);
        List<FtbCultivateFile> list = ftbCultivateFileService.list(wrapperItemFile);
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list;
    }

    /**
     * 根据ID获取Web端培养鉴定申请的详细信息
     *
     * @param id 申请记录的唯一标识符
     * @return 申请的详细信息对象
     */
    @Override
    public V2IdentifyApplyInfoVo getWebApplyInfo(String id) {
        CultivateIdentifyApply apply = queryAndCheckApply(id);
        CultivateIdentifyApplyTableBackups table = this.applyTableBackupsService.getById(apply.getTableId());
        ServiceException.notNull(table, "未查询到实操鉴定表记录");
        V2IdentifyApplyInfoVo applyInfoVo = new V2IdentifyApplyInfoVo();
        BeanUtils.copyProperties(apply, applyInfoVo);
        applyInfoVo.setUserTime(apply.getUseTime());
        applyInfoVo.setTableName(table.getName());
        applyInfoVo.setRuleDesc(table.getRuleDesc());

        String beIdentifyUserId = apply.getBeIdentifyUserId();
        List<String> userIds = new ArrayList<>();
        if (StringUtil.isNotEmpty(apply.getIdentifyUserId())) {
            userIds.addAll(List.of(apply.getIdentifyUserId().split(",")));
        }
        userIds.add(beIdentifyUserId);

        Map<String, UserBoundVO> userMap = userApiV2Util.getUserPrimaryBoundBatch(userIds, null);

        applyInfoVo.setBeIdentifyUserInfo(userMap.get(beIdentifyUserId));
        //鉴定用户信息
        List<UserBoundVO> identifyUserInfo = new ArrayList<>();
        if (StringUtil.isNotEmpty(apply.getIdentifyUserId())) {
            for (String s : apply.getIdentifyUserId().split(",")) {
                UserBoundVO userBoundVO = userMap.get(s);
                if (userBoundVO != null) {
                    identifyUserInfo.add(userBoundVO);
                }
            }
        }
        applyInfoVo.setIdentifyUserInfo(identifyUserInfo);

        //设置鉴定项得分集合
        BigDecimal totalScore = BigDecimal.ZERO;
        BigDecimal userTotalScore = BigDecimal.ZERO;
        List<IdentifyApplyDetailsInfoVo> detailsInfoVos = this.applyDetailsMapper.getIdentifyItemList(apply.getId());
        if (CollUtil.isNotEmpty(detailsInfoVos)) {
            List<String> tempIds = new ArrayList<>();
            for (IdentifyApplyDetailsInfoVo detailsInfoVo : detailsInfoVos) {
                if (detailsInfoVo.getTotalScore() != null) {
                    totalScore = totalScore.add(detailsInfoVo.getTotalScore());
                }
                if (detailsInfoVo.getMaxScore() != null) {
                    totalScore = totalScore.add(new BigDecimal(detailsInfoVo.getMaxScore()));
                }
                if (detailsInfoVo.getScore() != null) {
                    userTotalScore = userTotalScore.add(detailsInfoVo.getScore());
                }
                tempIds.add(detailsInfoVo.getId());
            }
            applyInfoVo.setTotalScore(totalScore);
            applyInfoVo.setUserTotalScore(userTotalScore);
            applyInfoVo.setIdentifyItemList(detailsInfoVos);
//            LambdaQueryWrapper<FtbCultivateFile> wrapperItemFile = Wrappers.lambdaQuery();
//            wrapperItemFile.in(FtbCultivateFile::getBusinessId, tempIds);
//            wrapperItemFile.orderByAsc(FtbCultivateFile::getCreatorTime);
            List<FtbCultivateFile> fileItemLists = queryFilesLists(tempIds);
            if (CollUtil.isNotEmpty(fileItemLists)) {
                //按照businessId 分组
                Map<String, List<FtbCultivateFile>> fileItemMap = fileItemLists.stream().collect(Collectors.groupingBy(FtbCultivateFile::getBusinessId));
                for (IdentifyApplyDetailsInfoVo detailsInfoVo : detailsInfoVos) {
                    List<FtbCultivateFile> fileItemList = fileItemMap.get(detailsInfoVo.getId());
                    if (CollUtil.isNotEmpty(fileItemList)) {
                        detailsInfoVo.setFiles(fileItemList.stream().map(FtbCultivateOfflineFileVO::convertFtbCultivateOfflineFileVO).collect(Collectors.toList()));
                    }
                }

            }
        } else {
            applyInfoVo.setIdentifyItemList(CollUtil.newArrayList());
            applyInfoVo.setTotalScore(null);
            applyInfoVo.setUserTime(null);
            applyInfoVo.setResult(null);
        }

        List<String> applyFileIds = new ArrayList<>();
        applyFileIds.add(apply.getId());
        applyFileIds.add(apply.getId() + apply.getBeIdentifyUserId());
        List<FtbCultivateFile> applyFileList = queryFilesLists(applyFileIds);
        applyInfoVo.setFiles(applyFileList.stream().map(FtbCultivateOfflineFileVO::convertFtbCultivateOfflineFileVO).collect(Collectors.toList()));
        return applyInfoVo;
    }


    private V2IdentifyApplySaveDto convertToIdentifyApplySaveDto(V2IdentifyApplySaveReq req) {
        V2IdentifyApplySaveDto identifyApplySaveDto = new V2IdentifyApplySaveDto();
        identifyApplySaveDto.setTableId(req.getTableId());
        identifyApplySaveDto.setAppraisalResults(req.getAppraisalResults());
        identifyApplySaveDto.setSource(req.getSource());
        if (CollUtil.isEmpty(req.getIdentifyUserIds())) {
            identifyApplySaveDto.setIdentifyUserId("");
        } else {
            identifyApplySaveDto.setIdentifyUserId(String.join(",", req.getIdentifyUserIds()));
        }
        identifyApplySaveDto.setFiles(req.getFiles());
        return identifyApplySaveDto;
    }

    private void checkBatchParam(V2IdentifyApplySaveReq req) {
        if (CollUtil.isEmpty(req.getBeIdentifyUserIds())) {
            throw new RuntimeException("被鉴定人信息不能为空");
        }
    }

    /**
     * 批量保存培养鉴定申请数据
     *
     * @param req 保存请求对象，包含待保存的申请数据列表
     */
    @Override
    @Transactional
    public void applyDataSaveBatch(V2IdentifyApplySaveReq req) {
        checkBatchParam(req);
        CultivateIdentifyTable table = this.identifyTableService.getById(req.getTableId());
        ServiceException.notNull(table, "未查询到实操鉴定表记录");
        if (!table.getIsAbnormal().equals(IdentifyItemExceptionEnum.NORMAL.getCode())) {
            throw new RuntimeException("该鉴定表存在异常,不能发起鉴定申请");
        }
        List<CultivateIdentifyApply> applyList = CollUtil.newArrayList();

        List<CultivateIdentifyItems> identifyItemsList = this.identifyItemsService.lambdaQuery().eq(CultivateIdentifyItems::getTableId, req.getTableId()).eq(CultivateIdentifyItems::getDeleteMark, ConstantUtil.NUM_FALSE).list();
        ServiceException.notNull(identifyItemsList, "未查询到鉴定项数据");

        List<String> bIdentifyUserIds = req.getBeIdentifyUserIds();
        List<String> allUserIds = new ArrayList<>(bIdentifyUserIds);
        if (CollUtil.isNotEmpty(req.getIdentifyUserIds())) {
            allUserIds.addAll(req.getIdentifyUserIds());
        }
        Map<String, UserBoundVO> userMap = userApiV2Util.getUserPrimaryBoundBatchReturnMap(allUserIds, null);
        for (String userId : bIdentifyUserIds) {
            UserBoundVO userBoundVO = userMap.get(userId);
            if (userBoundVO != null) {
                if (CollUtil.isNotEmpty(req.getIdentifyUserIds())) {
                    if (req.getIdentifyUserIds().contains(userId)) {
                        throw new RuntimeException("被鉴定人不能同时是鉴定人[" + userBoundVO.getUserName() + "]");
                    }
                }
            }
        }

        for (String userId : bIdentifyUserIds) {
            UserBoundVO userBoundVO = userMap.get(userId);
            if (userBoundVO == null) {
                continue;
            }
            V2IdentifyApplySaveDto identifyApplySaveDto = this.convertToIdentifyApplySaveDto(req);
            applyList.add(this.applyDataSaveNew(identifyApplySaveDto, table, identifyItemsList, userBoundVO));
        }
    }

    public CultivateIdentifyApply applyDataSaveNew(V2IdentifyApplySaveDto req, CultivateIdentifyTable table, List<CultivateIdentifyItems> identifyItemsList, UserBoundVO userBoundVO) throws RuntimeException {
        CultivateIdentifyApply apply = new CultivateIdentifyApply();
        apply.setId(RandomUtil.uuId());
        apply.setName(table.getName());
        BeanUtils.copyProperties(req, apply);
        apply.setStatus(ApplyStatusEnum.DJD.getCode());
        apply.setIsReIdentify(ConstantUtil.NUM_FALSE);
        apply.setBeIdentifyUserId(userBoundVO.getId());
        apply.setIdentifyUserId(req.getIdentifyUserId());
        apply.setOriginalTableId(table.getId());

        //生成鉴定表、鉴定项备份数据
        CultivateIdentifyApplyTableBackups applyTableBackups = new CultivateIdentifyApplyTableBackups();
        BeanUtils.copyProperties(table, applyTableBackups);
        applyTableBackups.setId(RandomUtil.uuId());
        applyTableBackups.setTableId(table.getId());
        apply.setTableId(applyTableBackups.getId());
        apply.setSource(req.getSource());

        //生成鉴定项数据
        List<CultivateIdentifyApplyDetailsBackups> applyDetailsBackupsList = CollUtil.newArrayList();
        if (CollUtil.isNotEmpty(identifyItemsList)) {
            applyDetailsBackupsList.addAll(identifyItemsList.stream().map(item -> {
                CultivateIdentifyApplyDetailsBackups applyDetailsBackups = new CultivateIdentifyApplyDetailsBackups();
                BeanUtils.copyProperties(item, applyDetailsBackups);
                applyDetailsBackups.setId(RandomUtil.uuId());
                applyDetailsBackups.setTableId(applyTableBackups.getId());
                applyDetailsBackups.setItemsId(item.getId());
                applyDetailsBackups.setDeleteMark(0);
                return applyDetailsBackups;
            }).collect(Collectors.toList()));
        }
        //生成鉴定项数据
        List<CultivateIdentifyApplyDetails> applyDetailsList = CollUtil.newArrayList();
        if (CollUtil.isNotEmpty(applyDetailsBackupsList)) {
            applyDetailsList.addAll(applyDetailsBackupsList.stream().map(item -> {
                CultivateIdentifyApplyDetails applyDetails = new CultivateIdentifyApplyDetails();
                applyDetails.setApplyId(apply.getId());
                applyDetails.setItemsId(item.getId());
                applyDetails.setDeleteMark(0);
                return applyDetails;
            }).collect(Collectors.toList()));
        } else {
            ServiceException.notNull(apply, "未查询到鉴定项数据");
        }
        //保存备份数据
        this.applyTableBackupsService.save(applyTableBackups);
        if (CollUtil.isNotEmpty(applyDetailsBackupsList)) {
            this.applyDetailsBackupsService.saveBatch(applyDetailsBackupsList);
        }
        //保存鉴定数据
        baseMapper.insert(apply);
        if (CollUtil.isNotEmpty(applyDetailsList)) {
            this.applyDetailsService.saveBatch(applyDetailsList);
        }

        SpringContext.getApplicationContext().publishEvent(new JnpfApplicationEvent<>(FileEventDTO.builder()
                .files(req.getFiles())
                .businessTypeID(apply.getId() + apply.getBeIdentifyUserId())
                .type(FileEventDTO.FileType.PRACTICAL_APPRAISAL).build()));
        return apply;
    }

    public IdentifyDataVo reAddIdentifyApply(CultivateIdentifyTable table) throws RuntimeException {

        //生成鉴定表、鉴定项备份数据
        CultivateIdentifyApplyTableBackups applyTableBackups = new CultivateIdentifyApplyTableBackups();
        BeanUtils.copyProperties(table, applyTableBackups);
        applyTableBackups.setId(RandomUtil.uuId());
        applyTableBackups.setTableId(table.getId());
        // 生成鉴定项数据
        List<CultivateIdentifyItems> identifyItemsList = this.identifyItemsService.lambdaQuery()
                .eq(CultivateIdentifyItems::getTableId, table.getId()).eq(CultivateIdentifyItems::getDeleteMark, ConstantUtil.NUM_FALSE).list();
        List<CultivateIdentifyApplyDetailsBackups> applyDetailsBackupsList = CollUtil.newArrayList();
        if (CollUtil.isNotEmpty(identifyItemsList)) {
            applyDetailsBackupsList.addAll(identifyItemsList.stream().map(item -> {
                CultivateIdentifyApplyDetailsBackups applyDetailsBackups = new CultivateIdentifyApplyDetailsBackups();
                BeanUtils.copyProperties(item, applyDetailsBackups);
                applyDetailsBackups.setId(RandomUtil.uuId());
                applyDetailsBackups.setTableId(applyTableBackups.getId());
                applyDetailsBackups.setItemsId(item.getId());
                applyDetailsBackups.setDeleteMark(0);
                return applyDetailsBackups;
            }).collect(Collectors.toList()));
        }
        //保存备份数据
        this.applyTableBackupsService.save(applyTableBackups);
        if (CollUtil.isNotEmpty(applyDetailsBackupsList)) {
            this.applyDetailsBackupsService.saveBatch(applyDetailsBackupsList);
        }
        return new IdentifyDataVo(applyTableBackups, applyDetailsBackupsList);
    }

    /**
     * 对指定ID的培养鉴定申请进行重新鉴定操作
     *
     * @param id 需要重新鉴定的申请记录唯一标识符
     */
    @Override
    @Transactional
    public void applyDataReIdentify(String id) {
        CultivateIdentifyApply apply = baseMapper.selectById(id);
        if (apply == null || apply.getDeleteMark().equals(1)) {
            throw new ServiceException("未查询到实操鉴定数据");
        }
        if (!apply.getResult().equals(ApplyResultEnum.BHG.getCode())) {
            throw new ServiceException("鉴定不合格的数据才能重新鉴定");
        }


        CultivateIdentifyApplyTableBackups applyTableBackupsOld = this.applyTableBackupsService.getById(apply.getTableId());
        ServiceException.notNull(applyTableBackupsOld, "未查询到实操鉴定备份表记录");
        //重新鉴定需拉取最新的鉴定表数据
        CultivateIdentifyTable table = this.identifyTableService.getById(applyTableBackupsOld.getTableId());
        ServiceException.notNull(table, "未查询到实操鉴定表记录");
        //生成鉴定申请
        CultivateIdentifyApply reIdentifyApply = JsonUtil.getJsonToBean(apply, CultivateIdentifyApply.class);
        reIdentifyApply.setOriginalTableId(table.getId());
        reIdentifyApply.setPlanIdentifyTime(null);
        reIdentifyApply.setIdentifyTime(null);
        reIdentifyApply.setUseTime(null);
        reIdentifyApply.setStatus(ApplyStatusEnum.DJD.getCode());
        reIdentifyApply.setResult(null);
        reIdentifyApply.setIsReIdentify(ConstantUtil.NUM_TRUE);


        //生成鉴定表、鉴定项备份数据
        CultivateIdentifyApplyTableBackups applyTableBackups = new CultivateIdentifyApplyTableBackups();
        BeanUtils.copyProperties(table, applyTableBackups);
        applyTableBackups.setId(RandomUtil.uuId());
        applyTableBackups.setTableId(table.getId());
        reIdentifyApply.setTableId(applyTableBackups.getId());

        List<CultivateIdentifyItems> identifyItemsList = this.identifyItemsService.lambdaQuery().eq(CultivateIdentifyItems::getTableId, table.getId()).eq(CultivateIdentifyItems::getDeleteMark, ConstantUtil.NUM_FALSE).list();

        List<CultivateIdentifyApplyDetailsBackups> applyDetailsBackupsList = CollUtil.newArrayList();
        if (CollUtil.isNotEmpty(identifyItemsList)) {
            applyDetailsBackupsList.addAll(identifyItemsList.stream().map(item -> {
                CultivateIdentifyApplyDetailsBackups applyDetailsBackups = new CultivateIdentifyApplyDetailsBackups();
                BeanUtils.copyProperties(item, applyDetailsBackups);
                applyDetailsBackups.setId(RandomUtil.uuId());
                applyDetailsBackups.setItemsId(item.getId());
                applyDetailsBackups.setTableId(applyTableBackups.getId());
                return applyDetailsBackups;
            }).collect(Collectors.toList()));
        }
        //生成鉴定项数据
        List<CultivateIdentifyApplyDetails> reIdentifyApplyDetailsList = CollUtil.newArrayList();
        reIdentifyApplyDetailsList.addAll(applyDetailsBackupsList.stream().map(item -> {
            CultivateIdentifyApplyDetails applyDetails = new CultivateIdentifyApplyDetails();
            applyDetails.setApplyId(reIdentifyApply.getId());
            applyDetails.setItemsId(item.getId());
            return applyDetails;
        }).collect(Collectors.toList()));

        //保存备份数据
        this.applyTableBackupsService.save(applyTableBackups);
        if (CollUtil.isNotEmpty(applyDetailsBackupsList)) {
            this.applyDetailsBackupsService.saveBatch(applyDetailsBackupsList);
        }
        //保存鉴定数据
        apply.setDeleteMark(ConstantUtil.NUM_TRUE);
        baseMapper.updateById(apply);
        baseMapper.insert(reIdentifyApply);
        if (CollUtil.isNotEmpty(reIdentifyApplyDetailsList)) {
            this.applyDetailsService.saveBatch(reIdentifyApplyDetailsList);
        }
    }

    /**
     * 删除指定ID的培养鉴定申请记录
     *
     * @param id 需要删除的申请记录唯一标识符
     */
    @Override
    @Transactional
    public void applyDataDelete(String id, Integer delMain) {

        CultivateIdentifyApply apply = queryAndCheckApply(id);
        // 1. 删除关联的文件（实操鉴定附件）
        LambdaUpdateWrapper<FtbCultivateFile> fileUpdateWrapper = Wrappers.lambdaUpdate();
        fileUpdateWrapper.eq(FtbCultivateFile::getBusinessId, apply.getId());
        fileUpdateWrapper.eq(FtbCultivateFile::getType, FileEventDTO.FileType.PRACTICAL_APPRAISAL.getType());
        fileUpdateWrapper.set(FtbCultivateFile::getEnabledMark, ConstantUtil.NUM_TRUE);
        ftbCultivateFileService.update(fileUpdateWrapper);

        // 2. 删除实操鉴定申请详情记录
        this.applyDetailsService.update(new LambdaUpdateWrapper<CultivateIdentifyApplyDetails>()
                .eq(CultivateIdentifyApplyDetails::getApplyId, id)
                .eq(CultivateIdentifyApplyDetails::getDeleteMark, ConstantUtil.NUM_FALSE)
                .set(CultivateIdentifyApplyDetails::getDeleteMark, ConstantUtil.NUM_TRUE));

        // 3. 删除鉴定表备份记录
        this.applyTableBackupsService.update(new LambdaUpdateWrapper<CultivateIdentifyApplyTableBackups>()
                .eq(CultivateIdentifyApplyTableBackups::getId, apply.getTableId())
                .eq(CultivateIdentifyApplyTableBackups::getDeleteMark, ConstantUtil.NUM_FALSE)
                .set(CultivateIdentifyApplyTableBackups::getDeleteMark, ConstantUtil.NUM_TRUE));

        // 4. 删除鉴定项备份记录
        this.applyDetailsBackupsService.update(new LambdaUpdateWrapper<CultivateIdentifyApplyDetailsBackups>()
                .eq(CultivateIdentifyApplyDetailsBackups::getTableId, apply.getTableId())
                .eq(CultivateIdentifyApplyDetailsBackups::getDeleteMark, ConstantUtil.NUM_FALSE)
                .set(CultivateIdentifyApplyDetailsBackups::getDeleteMark, ConstantUtil.NUM_TRUE));

        // 5. 删除鉴定申请主记录
        if (ConstantUtil.NUM_TRUE == delMain) {
            apply.setDeleteMark(ConstantUtil.NUM_TRUE);
            baseMapper.updateById(apply);
        }
    }

    /**
     * 查询当前用户的培养鉴定申请列表（移动端）
     *
     * @param req 查询条件请求对象，包含分页信息和筛选条件
     * @return 分页结果对象，包含申请列表数据和分页信息
     */
    @Override
    public Page<V2IdentifyApplyListAppVo> queryMyIdentifyApplyList(V2MyIdentifyApplyListAppReq req) {
        Page<V2IdentifyApplyListAppVo> page = Page.of(req.getCurrentPage(), req.getPageSize());
        String userId = UserProvider.getUser().getUserId();

        page = this.baseMapper.queryMyIdentifyApplyList(page, req, userId);
        if (CollUtil.isEmpty(page.getRecords())) {
            return page;
        }

        // 收集所有需要查询的用户ID(被鉴定人 + 鉴定人)
        List<String> userIdList = new ArrayList<>();
        for (V2IdentifyApplyListAppVo record : page.getRecords()) {
            userIdList.add(record.getBeIdentifyUserId());
            if (StringUtil.isNotEmpty(record.getIdentifyUserId())) {
                userIdList.addAll(List.of(record.getIdentifyUserId().split(",")));
            }
        }

        // 批量查询用户信息
        Map<String, UserBoundVO> userMap = userApiV2Util.getUserPrimaryBoundBatch(userIdList, null);

        // 填充被鉴定人和鉴定人信息
        for (V2IdentifyApplyListAppVo record : page.getRecords()) {
            // 设置被鉴定人信息
            UserBoundVO beUserInfoVo = userMap.get(record.getBeIdentifyUserId());
            if (Objects.nonNull(beUserInfoVo)) {
                record.setBeIdentifyUserInfo(beUserInfoVo);
            }

            // 设置鉴定人信息(取第一个鉴定人)
            if (StringUtil.isNotEmpty(record.getIdentifyUserId())) {
                if (record.getStatus().equals(1)) {
                    {
                        UserBoundVO identifyUserInfoVo = userMap.get(record.getIdentifyUserId());
                        if (Objects.nonNull(identifyUserInfoVo)) {
                            record.setIdentifyUserInfo(identifyUserInfoVo);
                        }
                    }
                }
            }
        }
        return page;
    }

    @Override
    public Page<V2IdentifyApplyListAppVo> queryAppIdentifyApplyList(V2IdentifyApplyListAppReq req) {
        String loginUserId = UserProvider.getUser().getUserId();
        List<String> orgUserIds = new ArrayList<>();
        List<String> myUserIds = this.baseMapper.queryMyIdentifyUserList(loginUserId);
        Page<V2IdentifyApplyListAppVo> page = Page.of(req.getCurrentPage(), req.getPageSize());
        if (CollUtil.isNotEmpty(req.getOrgIds())) {
            List<UserPageListVO> userListForOrgIds = userApiV2Util.getUserListForOrgIds(req.getOrgIds(), null);
            if (CollUtil.isEmpty(userListForOrgIds)) {
                orgUserIds = new ArrayList<>(List.of("-1"));
            } else {
                orgUserIds = userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList());
            }
        }

        if (req.getStatus().equals(0)) {
            //权限 + 鉴定人是自己的
            List<String> powerUserIds = userApiV2Util.getPermissionUserIds();
            if (CollUtil.isNotEmpty(powerUserIds)) {

                if (CollUtil.isNotEmpty(orgUserIds)) {
                    List<String> intersection = UserApiV2Util.getIntersection(powerUserIds, orgUserIds);
                    if (CollUtil.isEmpty(intersection)) {
                        powerUserIds = new ArrayList<>(List.of("-1"));
                    } else {
                        powerUserIds = intersection;
                    }
                }
            } else {
                powerUserIds = orgUserIds;
            }

            page = this.baseMapper.queryAppIdentifyApplyListWaiting(page, req, powerUserIds, myUserIds, loginUserId);
            if (CollUtil.isEmpty(page.getRecords())) {
                return page;
            }
        } else if (req.getStatus().equals(1)) {
            page = this.baseMapper.queryAppIdentifyApplyListComplete(page, req, orgUserIds, loginUserId);
            if (CollUtil.isEmpty(page.getRecords())) {
                return page;
            }
        } else {
            List<String> powerUserIds = userApiV2Util.getPermissionUserIds();
            if (CollUtil.isNotEmpty(powerUserIds)) {
                if (CollUtil.isNotEmpty(orgUserIds)) {
                    List<String> intersection = UserApiV2Util.getIntersection(powerUserIds, orgUserIds);
                    if (CollUtil.isEmpty(intersection)) {
                        powerUserIds = new ArrayList<>(List.of("-1"));
                    } else {
                        powerUserIds = intersection;
                    }
                }
            }else{
                powerUserIds = orgUserIds;
            }
            page = this.baseMapper.queryAppIdentifyApplyList(page, req,orgUserIds, powerUserIds, myUserIds, loginUserId);
            if (CollUtil.isEmpty(page.getRecords())) {
                return page;
            }
        }

        Map<String, UserBoundVO> userMap = userApiV2Util.getUserPrimaryBoundBatchReturnMap(page.getRecords().stream().map(V2IdentifyApplyListAppVo::getBeIdentifyUserId).collect(Collectors.toList()), null);
        for (V2IdentifyApplyListAppVo record : page.getRecords()) {
            record.setBeIdentifyUserInfo(userMap.get(record.getBeIdentifyUserId()));
        }
        return page;
    }

    /**
     * 根据鉴定记录ID重新发起鉴定
     *
     * @param id 需要重新发起的鉴定申请记录唯一标识符
     */
    @Override
    @Transactional
    public List<IdentifyApplyDetailsInfoVo> regenerateIdentifyApply(String id) {
        // 1. 查询原鉴定记录，获取基本信息
        CultivateIdentifyApply oldApply = queryAndCheckApply(id);
        if (oldApply.getStatus().equals(1) && (oldApply.getResult().equals(0) || oldApply.getResult().equals(1))) {
            throw new RuntimeException("鉴定已经合格,不能重新鉴定");
        }
        CultivateIdentifyTable table = getIdentifyTable(oldApply.getTableId());
        if (!table.getIsAbnormal().equals(IdentifyItemExceptionEnum.NORMAL.getCode())) {
            throw new RuntimeException("鉴定表存在异常,不能重新起鉴定申请");
        }
        List<CultivateIdentifyItems> list = this.identifyItemsService.lambdaQuery().eq(CultivateIdentifyItems::getTableId, table.getId())
                .eq(CultivateIdentifyItems::getDeleteMark, ConstantUtil.NUM_FALSE).orderByAsc(CultivateIdentifyItems::getSortCode)
                .list();
        if (CollUtil.isNotEmpty(list)) {
            return convertToIdentifyApplyDetailsInfoVo(list);
        }
        return new ArrayList<>();
    }

    /**
     * 将CultivateIdentifyItems列表转换为IdentifyApplyDetailsInfoVo列表
     *
     * @param itemsList 鉴定项列表
     * @return 转换后的VO列表
     */
    private List<IdentifyApplyDetailsInfoVo> convertToIdentifyApplyDetailsInfoVo(List<CultivateIdentifyItems> itemsList) {
        List<IdentifyApplyDetailsInfoVo> result = new ArrayList<>();
        for (CultivateIdentifyItems item : itemsList) {
            IdentifyApplyDetailsInfoVo vo = new IdentifyApplyDetailsInfoVo();
            vo.setId(item.getId());
            vo.setName(item.getName());
            // CultivateIdentifyItems中的score对应数据库的F_TotalScore字段，即鉴定项总分值
            vo.setTotalScore(item.getScore());
            vo.setType(item.getType());
            // 在重新发起鉴定时，初始得分为null或0，因为还没有进行评分
            vo.setScore(null);
            vo.setMinScore(item.getMinScore());
            vo.setMaxScore(item.getMaxScore());
            vo.setSortCode(item.getSortCode());
            // 注意：CultivateIdentifyItems中没有remark字段，所以这里设置为null
            // 如果需要从其他地方获取remark，可以在这里添加相应逻辑
            vo.setRemark(null);
            vo.setFiles(new ArrayList<>()); // 初始化附件列表为空
            result.add(vo);
        }
        return result;
    }

    private CultivateIdentifyTable getIdentifyTable(String tableId) {

        // 查询备份表，获取原始鉴定表ID
        CultivateIdentifyApplyTableBackups tableBackups = this.applyTableBackupsService.getById(tableId);
        ServiceException.notNull(tableBackups, "未查询到实操鉴定备份表记录");
        String originalTableId = tableBackups.getTableId();
        ServiceException.notNull(originalTableId, "未查询到原始鉴定表ID");
        // 校验鉴定表是否正常
        CultivateIdentifyTable table = this.identifyTableService.getById(originalTableId);
        ServiceException.notNull(table, "未查询到实操鉴定表记录");
        return table;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void reSubmit(V2IdentifyApplySubmitReq req) {

        String applyId = req.getId();
        CultivateIdentifyApply oldApply = queryAndCheckApply(applyId);
        CultivateIdentifyTable identifyTable = getIdentifyTable(oldApply.getTableId());
        // 移除旧鉴定项数据
        applyDataDelete(applyId, ConstantUtil.NUM_FALSE);
        // 生成新鉴定项数据
        IdentifyDataVo identifyData = reAddIdentifyApply(identifyTable);
        // 鉴定表重置 使用 LambdaUpdateWrapper 重置鉴定记录状态

        // 开始鉴定
        UserInfo user = UserProvider.getUser();
        if (user.getUserId().equals(oldApply.getBeIdentifyUserId())) {
            throw new ServiceException("对不起,不能够自己给自己鉴定");
        }
        CultivateIdentifyApplyTableBackups table = identifyData.getApplyTableBackups();
        List<CultivateIdentifyApplyDetailsBackups> identifyItemsList = identifyData.getApplyDetailsBackupsList();
        Map<String, String> itemMap = new HashMap<>();
        for (CultivateIdentifyApplyDetailsBackups item : identifyItemsList) {
            itemMap.put(item.getItemsId(), item.getId());
        }
        // 计算鉴定总分
        BigDecimal totalScore = CultivateIdentityUtil.calIdentityTotalScore(identifyItemsList);
        // 计算总得分
        BigDecimal userTotalScore = CultivateIdentityUtil.calUserTotalScore(req.getIdentifyItemList());
        // 0-合格，1-优秀，2-不合格
        MutablePair<Integer, String> pair = CultivateIdentityUtil.calUserIdentifyResult(table, totalScore, userTotalScore);

        LambdaUpdateWrapper<CultivateIdentifyApply> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(CultivateIdentifyApply::getId, applyId);
        updateWrapper.set(CultivateIdentifyApply::getDeleteMark, ConstantUtil.NUM_FALSE);
        updateWrapper.set(CultivateIdentifyApply::getResult, pair.left);  // 清空鉴定结果
        updateWrapper.set(CultivateIdentifyApply::getStatus, ApplyStatusEnum.YJD.getCode());  // 设置为待鉴定状态
        updateWrapper.set(CultivateIdentifyApply::getIdentifyTime, new Date());  // 清空鉴定时间
        updateWrapper.set(CultivateIdentifyApply::getUseTime, (int) DateUtil.between(new Date(), oldApply.getCreatorTime(), DateUnit.MINUTE));  // 清空用时
        updateWrapper.set(CultivateIdentifyApply::getPlanIdentifyTime, null);  // 清空计划鉴定时间
        updateWrapper.set(CultivateIdentifyApply::getUserTotalScore, userTotalScore);
        updateWrapper.set(CultivateIdentifyApply::getIsReIdentify, ConstantUtil.NUM_TRUE);
        updateWrapper.set(CultivateIdentifyApply::getTableId, identifyData.getApplyTableBackups().getId());
        updateWrapper.set(CultivateIdentifyApply::getIdentifyUserId, user.getUserId());
        updateWrapper.set(CultivateIdentifyApply::getTotalScore, totalScore);
        updateWrapper.set(CultivateIdentifyApply::getGradeName, pair.right);
        baseMapper.update(new CultivateIdentifyApply(), updateWrapper);
        List<CultivateIdentifyApplyDetails> applyDetailsList = new ArrayList<>();
        if (CollUtil.isNotEmpty(req.getIdentifyItemList())) {
            for (V2IdentifyApplyItemReq v2IdentifyApplyItemReq : req.getIdentifyItemList()) {
                CultivateIdentifyApplyDetails applyDetails = new CultivateIdentifyApplyDetails();
                applyDetails.setId(FtbUtil.getId());
                applyDetails.setApplyId(applyId);
                applyDetails.setItemsId(itemMap.get(v2IdentifyApplyItemReq.getId()));
                applyDetails.setScore(v2IdentifyApplyItemReq.getIdentifyScore());
                applyDetails.setDeleteMark(0);
                applyDetails.setRemark(v2IdentifyApplyItemReq.getRemark());
                applyDetailsList.add(applyDetails);
            }
            this.applyDetailsService.saveBatch(applyDetailsList);
        }
        if (CollUtil.isNotEmpty(applyDetailsList)) {
            for (V2IdentifyApplyItemReq v2IdentifyApplyItemReq : req.getIdentifyItemList()) {
                if (CollUtil.isNotEmpty(v2IdentifyApplyItemReq.getFiles())) {
                    SpringContext.getApplicationContext().publishEvent(new JnpfApplicationEvent<>(FileEventDTO.builder()
                            .files(v2IdentifyApplyItemReq.getFiles())
                            .businessTypeID(itemMap.get(v2IdentifyApplyItemReq.getId()))
                            .type(FileEventDTO.FileType.PRACTICAL_APPRAISAL_ITEM).build()));
                }
            }
        }
        if (StringUtil.isNotEmpty(table.getCertificateId())) {
            if (oldApply.getResult().equals(0) || oldApply.getResult().equals(1)) {
                if (oldApply.getSource().equals(0) || oldApply.getSource().equals(1) || oldApply.getSource().equals(3)) {
                    v2CultivateCertificateService.triggerCertificate(oldApply.getBeIdentifyUserId(), table.getCertificateId(), user.getTenantId());
                }
            }
        }
        cultivateMqSendUtil.sendIdentityCompletionMessage(oldApply, table.getTableId());
    }
}
