package com.ningdatech.pmapi.filemanage.manage;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.file.entity.File;
import com.ningdatech.file.service.FileService;
import com.ningdatech.file.utils.StrPool;
import com.ningdatech.pmapi.common.constant.BizConst;
import com.ningdatech.pmapi.common.constant.CommonConst;
import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.common.util.ExcelDownUtil;
import com.ningdatech.pmapi.expert.manage.ExpertReviewManage;
import com.ningdatech.pmapi.expert.model.vo.ExpertReviewDetailVO;
import com.ningdatech.pmapi.expert.model.vo.ProjectReviewDetailVO;
import com.ningdatech.pmapi.filemanage.model.entity.ProjectApplyBorrow;
import com.ningdatech.pmapi.filemanage.model.param.ProjectFileListParam;
import com.ningdatech.pmapi.filemanage.model.vo.ProjectApplyBorrowVO;
import com.ningdatech.pmapi.filemanage.model.vo.ProjectFileListVO;
import com.ningdatech.pmapi.filemanage.model.vo.ProjectFileVO;
import com.ningdatech.pmapi.filemanage.service.INdProjectApplyBorrowService;
import com.ningdatech.pmapi.organization.model.entity.DingOrganization;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.pmapi.projectdeclared.manage.ConstructionManage;
import com.ningdatech.pmapi.projectdeclared.manage.DefaultDeclaredProjectManage;
import com.ningdatech.pmapi.projectdeclared.manage.FinalAcceptanceManage;
import com.ningdatech.pmapi.projectdeclared.manage.PurchaseManage;
import com.ningdatech.pmapi.projectdeclared.model.entity.Contract;
import com.ningdatech.pmapi.projectdeclared.model.entity.Purchase;
import com.ningdatech.pmapi.projectdeclared.model.vo.ContractVO;
import com.ningdatech.pmapi.projectdeclared.model.vo.FinalAcceptanceVO;
import com.ningdatech.pmapi.projectdeclared.model.vo.PreInsVO;
import com.ningdatech.pmapi.projectdeclared.model.vo.PurchaseVO;
import com.ningdatech.pmapi.projectdeclared.service.IContractService;
import com.ningdatech.pmapi.projectdeclared.service.IPurchaseService;
import com.ningdatech.pmapi.projectlib.enumeration.InstTypeEnum;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.manage.ProjectLibManage;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectApplication;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectDetailVO;
import com.ningdatech.pmapi.projectlib.service.IProjectApplicationService;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.staging.enums.MsgTypeEnum;
import com.ningdatech.pmapi.sys.manage.NoticeManage;
import com.ningdatech.pmapi.todocenter.constant.WorkNoticeConstant;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import com.wflow.bean.entity.WflowModels;
import com.wflow.contants.HisProInsEndActId;
import com.wflow.exception.BusinessException;
import com.wflow.workflow.bean.dto.OrgInfoDTO;
import com.wflow.workflow.bean.process.FileBasicInfo;
import com.wflow.workflow.bean.process.ProcessComment;
import com.wflow.workflow.bean.vo.ProcessDetailVO;
import com.wflow.workflow.bean.vo.ProcessStartParamsVo;
import com.wflow.workflow.service.ProcessInstanceService;
import com.wflow.workflow.service.ProcessModelService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.task.Comment;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @Classname ProjectFileManage
 * @Description
 * @Date 2023/6/6 16:04
 * @Author PoffyZhang
 */
@Component
@AllArgsConstructor
@Slf4j
public class ProjectFileManage {

    private final IProjectService projectService;
    private final ProjectLibManage projectLibManage;
    private final UserInfoHelper userInfoHelper;
    private final ProcessModelService processModelService;
    private final DefaultDeclaredProjectManage defaultDeclaredProjectManage;
    private final ProcessInstanceService processInstanceService;
    private final NoticeManage noticeManage;
    private final IProjectInstService projectInstService;
    private final HistoryService historyService;
    private final INdProjectApplyBorrowService projectApplyBorrowService;
    private final IDingOrganizationService dingOrganizationService;
    private final IProjectApplicationService projectApplicationService;
    private final TaskService taskService;
    private final IPurchaseService purchaseService;
    private final IContractService contractService;
    private final ExpertReviewManage expertReviewManage;
    private final FileService fileService;
    private final PurchaseManage purchaseManage;
    private final ConstructionManage constructionManage;
    private final FinalAcceptanceManage finalAcceptanceManage;

    public PageVo<ProjectFileListVO> list(ProjectFileListParam param) {

        UserFullInfoDTO userFullInfo = userInfoHelper.getUserFullInfo(LoginUserUtil.getUserId());
        String employeeCode = userFullInfo.getEmployeeCode();
        String empPosUnitCode = userFullInfo.getEmpPosUnitCode();

        Page<Project> page = param.page();
        projectService.page(page, Wrappers.lambdaQuery(Project.class)
                .like(StringUtils.isNotBlank(param.getProjectName()), Project::getProjectName, param.getProjectName())
                .like(StringUtils.isNotBlank(param.getBuildOrgName()), Project::getBuildOrgName, param.getBuildOrgName())
                .eq(Project::getStatus, ProjectStatusEnum.ACCEPTED.getCode())
                .orderByDesc(Project::getUpdateOn));

        if (0L == page.getTotal()) {
            return PageVo.empty();
        }

        // 获取本单位及下属单位的单位code
        Set<String> subOrgSet = getSubOrgList(empPosUnitCode);

        List<ProjectFileListVO> vos = page.getRecords().stream().map(p -> {
            ProjectFileListVO vo = new ProjectFileListVO();
            vo.setId(p.getId());
            // 用户只可查阅自己及下属单位的项目档案和已经申请借阅通过的项目档案
            if (subOrgSet.contains(p.getBuildOrgCode()) || checkCanRead(subOrgSet, p)) {
                vo.setCanRead(Boolean.TRUE);
            }
            vo.setBuildOrgName(p.getBuildOrgName());
            vo.setPojectCode(p.getProjectCode());
            vo.setProjectName(p.getProjectName());
            // 判断当前项目,当前登录用户是否已经开启了申请借阅并且没有审批完成
            ProjectApplyBorrow projectApplyBorrow = projectApplyBorrowService.getOne(Wrappers.lambdaQuery(ProjectApplyBorrow.class)
                    .eq(ProjectApplyBorrow::getApplyBorrowEmployeeCode, employeeCode)
                    .eq(ProjectApplyBorrow::getProjectId, p.getId())
                    .orderByDesc(ProjectApplyBorrow::getCreateOn)
                    .last("limit 1"));
            if (Objects.nonNull(projectApplyBorrow)) {
                String instCode = projectApplyBorrow.getInstanceId();
                // 获取流程实例
                HistoricProcessInstance newInstance =
                        historyService.createHistoricProcessInstanceQuery().processInstanceId(instCode).singleResult();
                ProjectInst projectInst = projectInstService
                        .getOne(Wrappers.lambdaQuery(ProjectInst.class).eq(ProjectInst::getInstCode, instCode));
                // 推送省局联审的项目流程实例为EMPTY
                if (Objects.nonNull(projectInst)) {
                    Integer instType = projectInst.getInstType();
                    // 从申请借阅信息表中查询当前项目是否有当前登录用户发起的申请借阅审批流程
                    ProjectApplyBorrow applyBorrow = projectApplyBorrowService.getOne(Wrappers
                            .lambdaQuery(ProjectApplyBorrow.class).eq(ProjectApplyBorrow::getApplyBorrowEmployeeCode, employeeCode)
                            .eq(ProjectApplyBorrow::getProjectId, p.getId()).eq(ProjectApplyBorrow::getInstanceId, instCode));
                    // 延期申请流程还未审核结束
                    if (Objects.nonNull(applyBorrow) && InstTypeEnum.APPLY_BORROW.getCode().equals(instType)
                            && Objects.isNull(newInstance.getEndActivityId())) {
                        vo.setCanApplyBorrow(Boolean.FALSE);
                    }
                    // 如果是延期申请审核被驳回,设置项目可以申请延期申报
                    else if (InstTypeEnum.APPLY_BORROW.getCode().equals(instType) &&
                            HisProInsEndActId.REJECT.equals(newInstance.getEndActivityId())) {
                        vo.setCanApplyBorrow(Boolean.TRUE);
                    }
                }
            }
            return vo;
        }).collect(Collectors.toList());

        return PageVo.of(vos, page.getTotal());
    }

    private boolean checkCanRead(Set<String> subOrgSet, Project project) {
        // 从申请借阅信息表中查出本单位及下属单位审批通过的项目
        HashSet<Long> borrowProjectIdSet = new HashSet<>();
        List<Long> applyBorrowProjectIdList = projectApplyBorrowService
                .list(Wrappers.lambdaQuery(ProjectApplyBorrow.class)
                        .in(ProjectApplyBorrow::getApplyBorrowEmpPosUnitCode, subOrgSet)
                        .eq(ProjectApplyBorrow::getIsSuccess, Boolean.TRUE))
                .stream().map(ProjectApplyBorrow::getProjectId).filter(borrowProjectIdSet::add).collect(Collectors.toList());
        return applyBorrowProjectIdList.contains(project.getId());
    }

    private Set<String> getSubOrgList(String empPosUnitCode) {
        HashSet<String> orgSet = new HashSet<>();
        // 先将自己加入子集
        orgSet.add(empPosUnitCode);
        Set<String> subOrgList = dingOrganizationService
                .list(Wrappers.lambdaQuery(DingOrganization.class).eq(DingOrganization::getParentCode, empPosUnitCode))
                .stream().map(DingOrganization::getOrganizationCode).collect(Collectors.toSet());
        // 遍历子集
        for (String orgCode : subOrgList) {
            orgSet.addAll(getSubOrgList(orgCode));
        }
        return orgSet;
    }

    public ProjectFileVO file(Long projectId) {

        UserFullInfoDTO userFullInfo = userInfoHelper.getUserFullInfo(LoginUserUtil.getUserId());
        String empPosUnitCode = userFullInfo.getEmpPosUnitCode();

        // 判断该项目是否为本单位或下属单位的项目或者已经申请借阅成功的项目
        Project project = projectService.getById(projectId);
        Set<String> subOrgList = getSubOrgList(empPosUnitCode);

        if (!checkCanRead(subOrgList, project)) {
            throw new BizException("您没有权限查看此项目档案!");
        }
        ProjectFileVO projectFileVo = new ProjectFileVO();
        String projectCode = project.getProjectCode();
        ProjectDetailVO projectDetailVo = projectLibManage.getProjectDetail(projectId);
        List<ProcessDetailVO> processDetailVos = projectLibManage.processScheduleDetail(projectId);
        ProjectReviewDetailVO projectReviewDetailVo = expertReviewManage.projectExpertReviewDetail(projectCode);
        List<PurchaseVO> purchaseVos = purchaseManage.detailByProjectId(projectId);
        ContractVO contractVo = constructionManage.detailContractByProjectId(projectId);
        PreInsVO preInsVo = constructionManage.detailPreInsByProjectId(projectId);
        FinalAcceptanceVO finalAcceptanceVo = finalAcceptanceManage.detailByProjectId(projectId);

        projectFileVo.setProjectDetailVo(projectDetailVo);
        projectFileVo.setProcessDetailVos(processDetailVos);
        projectFileVo.setProjectReviewDetailVo(projectReviewDetailVo);
        projectFileVo.setPurchaseVos(purchaseVos);
        projectFileVo.setContractVo(contractVo);
        projectFileVo.setPreInsVo(preInsVo);
        projectFileVo.setFinalAcceptanceVo(finalAcceptanceVo);

        return projectFileVo;
    }

    public String wantRead(Long projectId) {
        return "申请成功";
    }

    public String startApplyBorrowProcess(Long projectId) {
        UserFullInfoDTO user = userInfoHelper.getUserFullInfo(LoginUserUtil.getUserId());
        String employeeCode = user.getEmployeeCode();
        VUtils.isTrue(StringUtils.isBlank(employeeCode)).throwMessage("获取登录用户 员工号 失败!");

        Project project = projectService.getNewProject(projectId);
        VUtils.isTrue(Objects.isNull(project)).throwMessage("提交失败 此项目不存在!");

        // 首先要判断 项目当前状态 是不是 已归档
        VUtils.isTrue(!ProjectStatusEnum.ACCEPTED.getCode().equals(project.getStatus())).throwMessage("提交失败 该项目不是 已归档");

        String regionCode = user.getRegionCode();

        WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class)
                .eq(WflowModels::getRegionCode, regionCode)
                .eq(WflowModels::getProcessType, ProjectProcessStageEnum.APPLY_BORROW.getCode()).last(BizConst.LIMIT_1));

        if (Objects.isNull(model)) {
            log.error("此 【{}】区域找不到申请借阅流程配置", regionCode);
            throw new BusinessException(String.format("此 【%s】区域找不到申请借阅流程配置", regionCode));
        }

        ProcessStartParamsVo params = new ProcessStartParamsVo();
        params.setUser(defaultDeclaredProjectManage.buildUser(employeeCode));
        params.setProcessUsers(Collections.emptyMap());
        // 放入条件判断的项目字段
        // 把条件值给放入工作流
        defaultDeclaredProjectManage.buildCondition(params, project);
        // 获取发起单位、发起单位主管单位、发起单位上级条线主管单位信息
        Map<String, OrgInfoDTO> orgModelMap = defaultDeclaredProjectManage.buildOrgModelMapUserOrgCode(project);
        String instanceId =
                processInstanceService.newStartProcess(model.getProcessDefId(), model.getFormId(), params, orgModelMap);
        log.info("申请借阅申报成功 【{}】", instanceId);

        // 保存项目借阅实例相关
        projectLibManage.saveProjectByApplyBorrow(project, user, instanceId);

        // 发送给第一个审批人消息
        noticeManage.sendFirtUser(project, model.getFormName(), instanceId, WorkNoticeConstant.PASS_MSG_TEMPLATE,
                MsgTypeEnum.PROJECT_REVIEW);

        return instanceId;
    }

    public void downloadFile(Long projectId, HttpServletResponse response) {
        Project project = projectService.getById(projectId);
        // 获取项目各阶段上传文件ID
        List<Long> fileIdList = Lists.newArrayList();
        getProjectAppendix(project, fileIdList);
        if (fileIdList.isEmpty()) {
            throw BizException.wrap("暂无档案可供下载");
        }
        List<File> files = fileService.listByIds(fileIdList);
        if (files.isEmpty()) {
            throw BizException.wrap("暂无档案可供下载");
        }
        String zipFileName = "项目档案";
        // 设置response的header
        response.setContentType("application/zip");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + ExcelDownUtil.encodeName(zipFileName) + ".zip");

        try {
            // 创建ZipOutputStream
            ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
            // 获取文件输入流
            for (File file : files) {
                String originalFileName = file.getOriginalFileName();
                String name = originalFileName.substring(0, originalFileName.indexOf(StrPool.DOT));
                String fileName = name + StrPool.UNDERSCORE + file.getId()
                        + originalFileName.substring(originalFileName.indexOf(StrPool.DOT));
                InputStream fileInputStream = fileService.getFileInputStream(file);
                // 文件
                ZipEntry zipEntry = new ZipEntry(fileName);
                zos.putNextEntry(zipEntry);
                byte[] bytes = new byte[1024];
                int length;
                while ((length = fileInputStream.read(bytes)) >= 0) {
                    zos.write(bytes, 0, length);
                }
                fileInputStream.close();
                zos.closeEntry();
            }
            zos.close();
        } catch (IOException e) {
            log.error("项目档案下载失败：", e);
            throw BizException.wrap("项目档案下载失败");
        }
    }

    private void getProjectAppendix(Project project, List<Long> fileIdList) {
        Long projectId = project.getId();
        // 项目申报阶段
        // 获取立项依据
        String buildBasis = project.getBuildBasis();
        List<JSONObject> buildBasisFileArray = JSON.parseArray(buildBasis, JSONObject.class);
        for (JSONObject jsonObject : buildBasisFileArray) {
            String fileInfo = jsonObject.getString(CommonConst.FILE_LIST);
            List<Long> buildBasisFileIdList = getFileIdList(fileInfo);
            fileIdList.addAll(buildBasisFileIdList);
        }
        // 获取附件-初步方案
        String preliminaryPlanFile = project.getPreliminaryPlanFile();
        List<Long> prePlanFileIdList = getFileIdList(preliminaryPlanFile);
        fileIdList.addAll(prePlanFileIdList);
        // 获取附件-佐证材料
        String supMaterialsFile = project.getSupportingMaterialsFile();
        List<Long> supMaterialFileIdList = getFileIdList(supMaterialsFile);
        fileIdList.addAll(supMaterialFileIdList);
        // 获取附件-项目总投资测算明细
        String calTotalInvestFile = project.getCalculationTotalInvestmentFile();
        List<Long> calTotalInvestFileIdList = getFileIdList(calTotalInvestFile);
        fileIdList.addAll(calTotalInvestFileIdList);
        // 获取附件-申报单位主要职责(单位三定方案)
        String mainResAppFile = project.getMainResponsibilitiesApplicantFile();
        List<Long> mainResAppFileIdList = getFileIdList(mainResAppFile);
        fileIdList.addAll(mainResAppFileIdList);
        // 获取附件-项目申报书
        String projectApplicationForm = project.getProjectApplicationForm();
        List<Long> projectAppFormFileIdList = getFileIdList(projectApplicationForm);
        fileIdList.addAll(projectAppFormFileIdList);
        // 获取项目应用信息中的文件
        List<ProjectApplication> applicationList = projectApplicationService
                .list(Wrappers.lambdaQuery(ProjectApplication.class).eq(ProjectApplication::getProjectId, projectId));
        for (ProjectApplication projectApplication : applicationList) {
            // 获取试点文件
            String experimentsFile = projectApplication.getExperimentsFile();
            List<Long> experimentsFileIdList = getFileIdList(experimentsFile);
            fileIdList.addAll(experimentsFileIdList);
            // 获取应用总投资测算明细
            String appEstimateFile = projectApplication.getApplicationEstimateFile();
            List<Long> appEstimateFileIdList = getFileIdList(appEstimateFile);
            fileIdList.addAll(appEstimateFileIdList);
        }
        // 流程审核意见文件
        // 获取项目关联的流程实例
        List<ProjectInst> projectInstList =
                projectInstService.list(Wrappers.lambdaQuery(ProjectInst.class).eq(ProjectInst::getProjectId, projectId));
        // 从历史评论表中获取对应流程实例的评论附件信息
        for (ProjectInst projectInst : projectInstList) {
            String instanceId = projectInst.getInstCode();
            List<Comment> commentList = taskService.getProcessInstanceComments(instanceId);
            for (Comment comment : commentList) {
                ProcessComment processComment = JSONObject.parseObject(comment.getFullMessage(), ProcessComment.class);
                List<FileBasicInfo> attachments = processComment.getAttachments();
                if (CollUtil.isNotEmpty(attachments)) {
                    List<Long> idList = attachments.stream().map(FileBasicInfo::getFileId).collect(Collectors.toList());
                    fileIdList.addAll(idList);
                }
            }
        }

        // 预审申报阶段
        // 预审申报上级条线主管单位审核意见
        String higherLineSuperOrgReviewComments = project.getHigherLineSuperOrgReviewComments();
        if (StringUtils.isNotBlank(higherLineSuperOrgReviewComments)) {
            List<Long> highSuperOrgFileIdList = getFileIdList(higherLineSuperOrgReviewComments);
            fileIdList.addAll(highSuperOrgFileIdList);
        }

        // 方案申报阶段
        // 获取建设方案文件
        String constructionPlanFile = project.getConstructionPlanFile();
        String str = StrPool.LEFT_SQ_BRACKET + StrPool.RIGHT_SQ_BRACKET;
        if (!str.equals(constructionPlanFile)) {
            JSONObject jsonObject = JSON.parseObject(constructionPlanFile, JSONObject.class);
            Long constructFileId = jsonObject.getLong(CommonConst.FILE_ID_STR);
            fileIdList.add(constructFileId);
        }

        // 立项批复阶段
        // 获取批复文件
        String approvedFile = project.getApprovedFile();
        if (Objects.nonNull(approvedFile)) {
            fileIdList.add(Long.valueOf(approvedFile));
        }
        // 获取建设方案文件
        String approvedConstructionPlanFile = project.getApprovedConstructionPlanFile();
        if (Objects.nonNull(approvedConstructionPlanFile)) {
            fileIdList.add(Long.valueOf(approvedConstructionPlanFile));
        }

        // 采购结果备案阶段
        Purchase purchase = purchaseService
                .getOne(Wrappers.lambdaQuery(Purchase.class).eq(Purchase::getProjectId, projectId).last(BizConst.LIMIT_1));
        // 获取投标文件
        if (Objects.nonNull(purchase)) {
            String biddingDoc = purchase.getBiddingDoc();
            List<Long> biddingFileIdList = getFileIdList(biddingDoc);
            fileIdList.addAll(biddingFileIdList);
            // 获取招标文件
            String bidDoc = purchase.getBidDoc();
            List<Long> bidFileIdList = getFileIdList(bidDoc);
            fileIdList.addAll(bidFileIdList);
            // 获取中标通知书
            String acceptanceLetter = purchase.getAcceptanceLetter();
            List<Long> acceptFileIdList = getFileIdList(acceptanceLetter);
            fileIdList.addAll(acceptFileIdList);
        }

        // 合同备案阶段
        Contract contract = contractService
                .getOne(Wrappers.lambdaQuery(Contract.class).eq(Contract::getProjectId, projectId).last(BizConst.LIMIT_1));
        // 获取合同附件
        if (Objects.nonNull(contract)) {
            String attachment = contract.getAttachment();
            List<Long> contractFileIdList = getFileIdList(attachment);
            fileIdList.addAll(contractFileIdList);
        }
        // 初验备案阶段
        // 获取初验材料
        String preliminaryInspectionMaterials = project.getPreliminaryInspectionMaterials();
        getInspectionMaterials(fileIdList, preliminaryInspectionMaterials);

        // 终验申报阶段
        // 获取终验材料
        String finalAcceptanceMaterials = project.getFinalAcceptanceMaterials();
        getInspectionMaterials(fileIdList, finalAcceptanceMaterials);

        // 专家评审记录-如果有初步方案评审会议、部门联审评审会议、建设方案评审会议、验收评审会议对应的附件
        // 获取项目的所有评审意见
        String projectCode = project.getProjectCode();
        ProjectReviewDetailVO projectReviewDetailVO = expertReviewManage.projectExpertReviewDetail(projectCode);
        Collection<ProjectReviewDetailVO.ReviewDetailByTypeVO> reviews = projectReviewDetailVO.getReviews();
        // 获取最终评审意见附件
        if (CollUtil.isNotEmpty(reviews)) {
            List<Long> finalReviewFileIdList = reviews.stream().map(r -> {
                ExpertReviewDetailVO finalReview = r.getFinalReview();
                return finalReview.getAttachFileId();
            }).collect(Collectors.toList());
            fileIdList.addAll(finalReviewFileIdList);
            // 获取组员评审意见
            for (ProjectReviewDetailVO.ReviewDetailByTypeVO review : reviews) {
                List<ExpertReviewDetailVO> teamMemberReviews = review.getTeamMemberReviews();
                for (ExpertReviewDetailVO teamMemberReview : teamMemberReviews) {
                    Long attachFileId = teamMemberReview.getAttachFileId();
                    fileIdList.add(attachFileId);
                }
            }
        }
    }

    private void getInspectionMaterials(List<Long> fileIdList, String preliminaryInspectionMaterials) {
        List<String> fileStrList = JSON.parseArray(preliminaryInspectionMaterials, String.class);
        if (CollUtil.isNotEmpty(fileStrList)) {
            for (String fileStr : fileStrList) {
                JSONObject object = JSON.parseObject(fileStr, JSONObject.class);
                String dataStr = object.getString("data");
                List<String> array = JSON.parseArray(dataStr, String.class);
                for (String file : array) {
                    JSONObject fileObject = JSON.parseObject(file, JSONObject.class);
                    String filesStr = fileObject.getString("files");
                    List<JSONObject> jsonObjects = JSON.parseArray(filesStr, JSONObject.class);
                    if (CollUtil.isEmpty(jsonObjects)) {
                        // 如果没有上传附件,跳过
                        continue;
                    }
                    for (JSONObject json : jsonObjects) {
                        String response = json.getString("response");
                        JSONObject responseJson = JSON.parseObject(response, JSONObject.class);
                        String fileData = responseJson.getString("data");
                        JSONObject fileInfoObject = JSON.parseObject(fileData, JSONObject.class);
                        Long fileId = fileInfoObject.getLong("id");
                        fileIdList.add(fileId);
                    }
                }
            }
        }
    }

    private List<Long> getFileIdList(String buildBasis) {
        List<JSONObject> prePlanFileArray = JSON.parseArray(buildBasis, JSONObject.class);
        List<Long> prePlanFileIdList = CollUtils.fieldList(prePlanFileArray, w -> w.getLong(CommonConst.ID_STR));
        return prePlanFileIdList;
    }

    /**
     * 查看 借阅的详情
     *
     * @param instanceId
     * @return
     */
    public ProjectApplyBorrowVO wantReadDetail(String instanceId) {
        ProjectApplyBorrow apply = projectApplyBorrowService.getOne(Wrappers.lambdaQuery(ProjectApplyBorrow.class)
                .eq(ProjectApplyBorrow::getInstanceId, instanceId)
                .last(BizConst.LIMIT_1));

        if (Objects.isNull(apply)) {
            return null;
        }

        ProjectApplyBorrowVO vo = BeanUtil.copyProperties(apply, ProjectApplyBorrowVO.class);
        if (StringUtils.isNotBlank(vo.getApplyBorrowEmployeeCode())) {
            UserFullInfoDTO user = userInfoHelper.getUserFullInfoByEmployeeCode(vo.getApplyBorrowEmployeeCode());
            if (Objects.nonNull(user)) {
                vo.setApplyBorrowEmployeeName(user.getUsername());
            }
        }
        if (StringUtils.isNotBlank(vo.getApplyBorrowEmpPosUnitCode())) {
            DingOrganization organization = dingOrganizationService.getOne(Wrappers.lambdaQuery(DingOrganization.class)
                    .eq(DingOrganization::getOrganizationCode, vo.getApplyBorrowEmpPosUnitCode())
                    .last(BizConst.LIMIT_1));
            if (Objects.nonNull(organization)) {
                vo.setApplyBorrowEmpPosUnitName(organization.getOrganizationName());
            }
        }
        if (Objects.nonNull(vo.getProjectId())) {
            Project project = projectService.getById(vo.getProjectId());
            if (Objects.nonNull(project)) {
                vo.setProjectName(project.getProjectName());
            }
        }
        return vo;
    }
}
