package com.hz.pm.api.performance.manage;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.hz.pm.api.common.helper.UserInfoHelper;
import com.hz.pm.api.common.model.constant.BizConst;
import com.hz.pm.api.common.model.constant.CommonConst;
import com.hz.pm.api.common.util.BizUtils;
import com.hz.pm.api.common.util.CodeUtil;
import com.hz.pm.api.performance.convert.PerformanceAppraisalConveter;
import com.hz.pm.api.performance.enumration.EvalObjectEnum;
import com.hz.pm.api.performance.model.dto.*;
import com.hz.pm.api.performance.model.entity.*;
import com.hz.pm.api.performance.model.req.PerformanceAppraisalListReq;
import com.hz.pm.api.performance.model.vo.PerformanceAppraisalApplicationVO;
import com.hz.pm.api.performance.model.vo.PerformanceAppraisalProjectGroupVO;
import com.hz.pm.api.performance.model.vo.PerformanceAppraisalProjectVO;
import com.hz.pm.api.performance.model.vo.PerformanceAppraisalVO;
import com.hz.pm.api.performance.service.*;
import com.hz.pm.api.projectlib.manage.ProjectLibManage;
import com.hz.pm.api.projectlib.model.entity.Project;
import com.hz.pm.api.projectlib.model.entity.ProjectApplication;
import com.hz.pm.api.projectlib.model.entity.ProjectInst;
import com.hz.pm.api.projectlib.model.enumeration.InstTypeEnum;
import com.hz.pm.api.projectlib.model.enumeration.ProjectStatusEnum;
import com.hz.pm.api.projectlib.model.enumeration.ProjectTypeNewEnum;
import com.hz.pm.api.projectlib.model.req.ProjectListReq;
import com.hz.pm.api.projectlib.model.vo.ProjectApplicationVO;
import com.hz.pm.api.projectlib.model.vo.ProjectLibListItemVO;
import com.hz.pm.api.projectlib.service.IProjectApplicationService;
import com.hz.pm.api.projectlib.service.IProjectInstService;
import com.hz.pm.api.projectlib.service.IProjectService;
import com.hz.pm.api.todocenter.utils.BuildUserUtils;
import com.hz.pm.api.user.security.model.UserFullInfoDTO;
import com.hz.pm.api.user.security.model.UserInfoDetails;
import com.hz.pm.api.user.util.LoginUserUtil;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.basic.util.StrPool;
import com.wflow.workflow.bean.process.ProgressNode;
import com.wflow.workflow.bean.vo.ProcessProgressVo;
import com.wflow.workflow.service.ProcessInstanceService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Classname PerformanceAppraisalManage
 * @Description
 * @Date 2023/6/19 14:18
 * @Author PoffyZhang
 */
@Component
@Slf4j
@AllArgsConstructor
public class PerformanceAppraisalPlanManage {

    private final IPerformanceAppraisalService performanceAppraisalService;
    private final IPerformanceAppraisalProjectService performanceAppraisalProjectService;
    private final IPerformanceAppraisalApplicationService performanceAppraisalApplicationService;
    private final IProjectService projectService;
    private final IProjectApplicationService applicationService;
    private final IPerformanceAppraisalProjectGroupService groupService;
    private final UserInfoHelper userInfoHelper;
    private final IProjectInstService projectInstService;
    private final ProcessInstanceService processInstanceService;
    private final BuildUserUtils buildUserUtils;
    private final IPerformanceAppraisalScoreInfoService performanceAppraisalScoreInfoService;
    private final IPerformanceAppraisalAppScoreInfoService performanceAppraisalAppScoreInfoService;
    private final ProjectLibManage projectLibManage;
    private final IProjectApplicationService projectApplicationService;

    /**
     * 绩效列表
     *
     * @param req
     * @return
     */
    public PageVo<PerformanceAppraisalVO> list(PerformanceAppraisalListReq req) {
        Page<PerformanceAppraisal> page = req.page();
        String regionCode = req.getRegionCode();
        LambdaQueryWrapper<PerformanceAppraisal> wrapper = Wrappers.lambdaQuery(PerformanceAppraisal.class)
                .like(StringUtils.isNotBlank(req.getPlanName()), PerformanceAppraisal::getName, req.getPlanName())
                .ge(Objects.nonNull(req.getStart()), PerformanceAppraisal::getCreateOn, req.getStart())
                .le(Objects.nonNull(req.getEnd()), PerformanceAppraisal::getCreateOn, req.getEnd())
                .eq(StringUtils.isNotBlank(regionCode), PerformanceAppraisal::getRegionCode, regionCode)
                .orderByDesc(PerformanceAppraisal::getUpdateOn);
        // 如果登录用户是区域管理员，能看到本区域的评价计划
        performanceAppraisalService.page(page, wrapper);
        if (CollUtil.isEmpty(page.getRecords())) {
            return PageVo.empty();
        }
        List<Long> paIds = page.getRecords().stream().map(PerformanceAppraisal::getId).collect(Collectors.toList());
        List<PerformanceAppraisalProject> paps = performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                .in(PerformanceAppraisalProject::getAppraisalId, paIds));

        Map<String, Project> projectMap = Maps.newHashMap();
        Map<Long, List<PerformanceAppraisalProject>> papsGroupMap = Maps.newHashMap();
        if (CollUtil.isNotEmpty(paps)) {
            papsGroupMap = paps.stream().collect(Collectors.groupingBy(PerformanceAppraisalProject::getAppraisalId));

            List<String> projectCodes = paps.stream().map(PerformanceAppraisalProject::getProjectCode).collect(Collectors.toList());
            List<Project> projects = projectService.list(Wrappers.lambdaQuery(Project.class)
                    .in(Project::getProjectCode, projectCodes)
                    .eq(Project::getNewest, Boolean.TRUE));
            if (CollUtil.isNotEmpty(projects)) {
                projectMap = projects.stream().collect(Collectors.toMap(Project::getProjectCode, p -> p));
            }
        }

        List<PerformanceAppraisalApplication> paas = performanceAppraisalApplicationService.list(Wrappers.lambdaQuery(PerformanceAppraisalApplication.class)
                .in(PerformanceAppraisalApplication::getAppraisalId, paIds));
        Map<Long, ProjectApplication> applicationMap = Maps.newHashMap();
        Map<Long, List<PerformanceAppraisalApplication>> paasGroupMap = Maps.newHashMap();
        if (CollUtil.isNotEmpty(paas)) {
            paasGroupMap = paas.stream().collect(Collectors.groupingBy(PerformanceAppraisalApplication::getAppraisalId));

            List<Long> applicationIds = paas.stream().map(PerformanceAppraisalApplication::getApplicationId).collect(Collectors.toList());
            List<ProjectApplication> apps = applicationService.list(Wrappers.lambdaQuery(ProjectApplication.class)
                    .in(ProjectApplication::getId, applicationIds));
            if (CollUtil.isNotEmpty(apps)) {
                applicationMap = apps.stream().collect(Collectors.toMap(ProjectApplication::getId, a -> a));
            }
        }

        Map<Long, List<PerformanceAppraisalProject>> finalPapsGroupMap = papsGroupMap;
        Map<Long, List<PerformanceAppraisalApplication>> finalPaasGroupMap = paasGroupMap;
        Map<String, Project> finalProjectMap = projectMap;
        Map<Long, ProjectApplication> finalApplicationMap = applicationMap;
        List<PerformanceAppraisalVO> res = page.getRecords().stream().map(p -> {
            PerformanceAppraisalVO vo = BeanUtil.copyProperties(p, PerformanceAppraisalVO.class);
            if (finalPapsGroupMap.containsKey(p.getId())) {
                vo.setProjects(PerformanceAppraisalConveter.convertProjects(finalPapsGroupMap.get(p.getId()), finalProjectMap));
            }
            if (finalPaasGroupMap.containsKey(p.getId())) {
                vo.setApplications(PerformanceAppraisalConveter.convertApplications(finalPaasGroupMap.get(p.getId()), finalApplicationMap));
            }
            return vo;
        }).collect(Collectors.toList());
        return PageVo.of(res, page.getTotal());
    }

    public PerformanceAppraisalVO detail(Long id) {

        PerformanceAppraisal pa = performanceAppraisalService.getById(id);
        VUtils.isTrue(Objects.isNull(pa)).throwMessage("该计划不存在");

        PerformanceAppraisalVO vo = BeanUtil.copyProperties(pa, PerformanceAppraisalVO.class);
        //绩效关联的项目
        List<PerformanceAppraisalProject> paps = performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                .eq(PerformanceAppraisalProject::getAppraisalId, id));
        Map<String, Project> projectMap = Maps.newHashMap();
        Map<Long, List<PerformanceAppraisalProject>> papsGroupMap = Maps.newHashMap();
        if (CollUtil.isNotEmpty(paps)) {
            papsGroupMap = paps.stream().collect(Collectors.groupingBy(PerformanceAppraisalProject::getAppraisalId));

            List<String> projectCodes = paps.stream().map(PerformanceAppraisalProject::getProjectCode).collect(Collectors.toList());
            List<Project> projects = projectService.list(Wrappers.lambdaQuery(Project.class)
                    .in(Project::getProjectCode, projectCodes)
                    .eq(Project::getNewest, Boolean.TRUE));
            if (CollUtil.isNotEmpty(projects)) {
                projectMap = projects.stream().collect(Collectors.toMap(Project::getProjectCode, p -> p));
            }
        }

        //绩效关联的应用
        List<PerformanceAppraisalApplication> paas = performanceAppraisalApplicationService.list(Wrappers.lambdaQuery(PerformanceAppraisalApplication.class)
                .eq(PerformanceAppraisalApplication::getAppraisalId, id));
        Map<Long, ProjectApplication> applicationMap = Maps.newHashMap();
        Map<Long, List<PerformanceAppraisalApplication>> paasGroupMap = Maps.newHashMap();
        if (CollUtil.isNotEmpty(paas)) {
            paasGroupMap = paas.stream().collect(Collectors.groupingBy(PerformanceAppraisalApplication::getAppraisalId));

            List<Long> applicationIds = paas.stream().map(PerformanceAppraisalApplication::getApplicationId).collect(Collectors.toList());
            List<ProjectApplication> apps = applicationService.list(Wrappers.lambdaQuery(ProjectApplication.class)
                    .in(ProjectApplication::getId, applicationIds));
            if (CollUtil.isNotEmpty(apps)) {
                applicationMap = apps.stream().collect(Collectors.toMap(ProjectApplication::getId, a -> a));
            }
        }

        Map<Long, List<PerformanceAppraisalProject>> finalPapsGroupMap = papsGroupMap;
        Map<Long, List<PerformanceAppraisalApplication>> finalPaasGroupMap = paasGroupMap;
        Map<String, Project> finalProjectMap = projectMap;
        Map<Long, ProjectApplication> finalApplicationMap = applicationMap;
        if (finalPapsGroupMap.containsKey(vo.getId())) {
            vo.setProjects(PerformanceAppraisalConveter.convertProjects(finalPapsGroupMap.get(vo.getId()), finalProjectMap));
        }
        if (finalPaasGroupMap.containsKey(vo.getId())) {
            vo.setApplications(PerformanceAppraisalConveter.convertApplications(finalPaasGroupMap.get(vo.getId()), finalApplicationMap));
        }

        // 评价计划关联的分组信息
        List<PerformanceAppraisalProjectGroup> groupList = groupService.list(Wrappers.lambdaQuery(PerformanceAppraisalProjectGroup.class)
                .eq(PerformanceAppraisalProjectGroup::getAppraisalId, id));
        // 对计划内待评价项目进行了分组
        if (CollUtil.isNotEmpty(groupList)) {
            // 获取分组信息
            List<PerformanceAppraisalProjectGroupVO> groups = groupList.stream().map(g -> {
                PerformanceAppraisalProjectGroupVO groupVo = new PerformanceAppraisalProjectGroupVO();
                groupVo.setId(g.getId());
                groupVo.setAppraisalId(id);
                groupVo.setName(g.getName());
                String reAppraisalUsersStr = g.getReAppraisalUsers();
                List<UserFullInfoDTO> reAppraisalUsers = Arrays.stream(reAppraisalUsersStr.split(StrPool.COMMA))
                        .map(w -> userInfoHelper.getUserFullInfo(Long.parseLong(w))).collect(Collectors.toList());
                groupVo.setReAppraisalUsers(reAppraisalUsers);
                String verificationUsersStr = g.getVerificationUsers();
                List<UserFullInfoDTO> verificationUsers = Arrays.stream(verificationUsersStr.split(StrPool.COMMA))
                        .map(w -> userInfoHelper.getUserFullInfo(Long.parseLong(w))).collect(Collectors.toList());
                groupVo.setVerificationUsers(verificationUsers);
                if (StringUtils.isNotBlank(g.getVerifyLeader())) {
                    UserFullInfoDTO dto = userInfoHelper.getUserFullInfo(Long.valueOf(g.getVerifyLeader()));
                    groupVo.setVerifyLeader(dto);
                }
                groupVo.setCreateOn(g.getCreateOn());
                return groupVo;
            }).collect(Collectors.toList());
            vo.setGroups(groups);
        }
        return vo;
    }

    /**
     * 新建计划
     *
     * @param createDTO
     * @return
     */
    @Transactional
    public String create(PerformanceAppraisalCreateDTO createDTO) {
        UserInfoDetails user = LoginUserUtil.loginUserDetail();
        // 计划名称重复校验
        deduplicationName(createDTO);
        PerformanceAppraisal pa = BeanUtil.copyProperties(createDTO, PerformanceAppraisal.class);


        pa.setCreateOn(LocalDateTime.now());
        pa.setCreateBy(user.getUsername());
        pa.setUpdateOn(LocalDateTime.now());
        pa.setUpdateBy(user.getUsername());
        performanceAppraisalService.save(pa);

        if (CollUtil.isNotEmpty(createDTO.getProjects())
                && StringUtils.isNotBlank(createDTO.getTarget())
                && createDTO.getTarget().contains(EvalObjectEnum.PROJECT.getCode())) {
            saveProjects(createDTO, pa.getId(), user);
        }

        if (CollUtil.isNotEmpty(createDTO.getApplicationIds())
                && StringUtils.isNotBlank(createDTO.getTarget())
                && createDTO.getTarget().contains(EvalObjectEnum.APP.getCode())) {
            saveApplications(createDTO, pa.getId(), user);
        }

        return "新建成功";
    }


    /**
     * 编辑计划
     *
     * @param editDTO
     * @return
     */
    @Transactional
    public String edit(PerformanceAppraisalEditDTO editDTO) {
        UserInfoDetails user = LoginUserUtil.loginUserDetail();

        deduplicationName(editDTO);

        PerformanceAppraisal pa = BeanUtil.copyProperties(editDTO, PerformanceAppraisal.class);

        pa.setUpdateOn(LocalDateTime.now());
        pa.setUpdateBy(user.getUsername());
        performanceAppraisalService.updateById(pa);
        String target = editDTO.getTarget();
        // 如果新编辑的评价计划不包含项目，删除原计划添加的评价项目信息
        if (StringUtils.isNotBlank(target) && !target.contains(EvalObjectEnum.PROJECT.getCode())) {
            performanceAppraisalProjectService.remove(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                    .eq(PerformanceAppraisalProject::getAppraisalId, editDTO.getId()));
        }

        // 如果新编辑的评价计划不包含应用，删除原计划添加的评价应用信息
        if (StringUtils.isNotBlank(target) && !target.contains(EvalObjectEnum.APP.getCode())) {
            performanceAppraisalApplicationService.remove(Wrappers.lambdaQuery(PerformanceAppraisalApplication.class)
                    .eq(PerformanceAppraisalApplication::getAppraisalId, editDTO.getId()));
        }

        if (StringUtils.isNotBlank(target) &&
                target.contains(EvalObjectEnum.PROJECT.getCode()) &&
                CollUtil.isNotEmpty(editDTO.getProjects())) {
            saveProjects(editDTO, user);
        }

        if (StringUtils.isNotBlank(target) &&
                target.contains(EvalObjectEnum.APP.getCode()) &&
                CollUtil.isNotEmpty(editDTO.getApplicationIds())) {
            saveApplications(editDTO, user);
        }

        return "编辑成功";
    }

    /**
     * 名称去重
     *
     * @param dto
     */
    private void deduplicationName(PerformanceAppraisalCreateDTO dto) {
        long count = performanceAppraisalService.count(Wrappers.lambdaQuery(PerformanceAppraisal.class)
                .eq(PerformanceAppraisal::getName, dto.getName()));
        VUtils.isTrue(count > 0).throwMessage("名称已经存在");
    }

    private void deduplicationName(PerformanceAppraisalEditDTO dto) {
        if (StringUtils.isNotBlank(dto.getName())) {
            long count = performanceAppraisalService.count(Wrappers.lambdaQuery(PerformanceAppraisal.class)
                    .eq(PerformanceAppraisal::getName, dto.getName())
                    .ne(Objects.nonNull(dto.getId()), PerformanceAppraisal::getId, dto.getId()));
            VUtils.isTrue(count > 0).throwMessage("名称已经存在");
        }
    }

    @Transactional
    public void saveProjects(PerformanceAppraisalCreateDTO createDTO, Long id, UserInfoDetails user) {
        if (CollUtil.isEmpty(createDTO.getProjects())) {
            return;
        }
        Integer startSelfDays = createDTO.getStartSelfDays();
        Integer completeSelfDays = createDTO.getCompleteSelfDays();
        List<AppraisalProjectDTO> projects = createDTO.getProjects();

        List<Long> proIdList = performanceAppraisalProjectService.list().stream()
                .map(PerformanceAppraisalProject::getProjectId).collect(Collectors.toList());

        List<Long> projectIdList = projects.stream().map(AppraisalProjectDTO::getId).collect(Collectors.toList());
        // 判断提交时，项目是否已经被添加到其他评价计划中
        if (Boolean.TRUE.equals(haveIntersection(projectIdList, proIdList))) {
            // 得到交集
            List<Long> intersection = Lists.newArrayList(projectIdList);
            intersection.retainAll(proIdList);
            // 获取重复添加的项目名称
            String names = intersection.stream().map(i -> {
                Project project = projectService.getById(i);
                if (Objects.nonNull(project)) {
                    return project.getProjectName();
                }
                return StrPool.EMPTY;
            }).collect(Collectors.joining(StrPool.COMMA));
            throw new BizException(names + CommonConst.PROJECT_REPEAT);
        }

        for (AppraisalProjectDTO appraisalProject : projects) {
            Project newProject = projectService.getNewProject(appraisalProject.getId());
            VUtils.isTrue(Objects.isNull(newProject)).throwMessage("项目不存在 " + appraisalProject.getId());
            // 获取项目终验完成的时间
            LocalDateTime finishTime = getProjectFinishTime(newProject);

            PerformanceAppraisalProject pap = new PerformanceAppraisalProject();
            pap.setAppraisalId(id);
            pap.setProjectId(appraisalProject.getId());
            pap.setProjectCode(newProject.getProjectCode());
            pap.setIsReAppraisal(appraisalProject.getIsReAppraisal());
            pap.setCreateBy(user.getUsername());
            pap.setCreateOn(LocalDateTime.now());
            pap.setUpdateBy(user.getUsername());
            pap.setUpdateOn(LocalDateTime.now());
            LocalDateTime selfAppraisalStart = finishTime.plusDays(startSelfDays);
            pap.setSelfAppraisalStart(selfAppraisalStart);
            long days = startSelfDays + completeSelfDays;
            LocalDateTime selfAppraisalEnd = finishTime.plusDays(days);
            pap.setSelfAppraisalEnd(selfAppraisalEnd);
            performanceAppraisalProjectService.save(pap);
        }
    }

    private LocalDateTime getProjectFinishTime(Project newProject) {
        //查出历史版本的 所有项目ID
        List<Long> allVersionProjectIds = projectService.getAllVersionProjectId(newProject);
        // 根据项目ID查询出项目终验流程的流程状态
        ProjectInst projectInst = projectInstService.getOne(Wrappers.lambdaQuery(ProjectInst.class)
                .in(ProjectInst::getProjectId, allVersionProjectIds)
                .eq(ProjectInst::getInstType, InstTypeEnum.PROJECT_FINAL_INSPECTION.getCode())
                .orderByDesc(ProjectInst::getCreatOn)
                .last(BizConst.LIMIT_1));

        if (Objects.isNull(projectInst)) {
            throw new BizException("未获取到项目终验审批流程信息!");
        }

        LocalDateTime finishTime;
        String instCode = projectInst.getInstCode();
        ProcessProgressVo instanceDetail = processInstanceService.getProgressInstanceDetail(null, instCode);
        // 装配节点审核人员信息
        List<ProgressNode> progressInfo = instanceDetail.getProgressInfo();
        if (CollUtil.isNotEmpty(progressInfo)) {
            buildUserUtils.buildUserByProcessInfo(progressInfo);
            ProgressNode progressNode = progressInfo.get(progressInfo.size() - 1);
            finishTime = NdDateUtils.date2LocalDateTime(progressNode.getFinishTime());
        } else {
            finishTime = NdDateUtils.date2LocalDateTime(instanceDetail.getStartTime());
        }
        return finishTime;
    }

    @Transactional
    public void saveApplications(PerformanceAppraisalCreateDTO createDTO, Long id, UserInfoDetails user) {
        if (CollUtil.isEmpty(createDTO.getApplicationIds())) {
            return;
        }

        List<Long> applicationIdList = createDTO.getApplicationIds();
        // 获取已经创建的评价计划中添加的评价应用ID
        List<Long> applicationIds = performanceAppraisalApplicationService.list().stream()
                .map(PerformanceAppraisalApplication::getApplicationId).collect(Collectors.toList());

        // 如果有交集,说明选择的应用中，有已经在其他评价计划中的应用
        if (Boolean.TRUE.equals(haveIntersection(applicationIdList, applicationIds))) {
            // 得到交集
            List<Long> intersection = Lists.newArrayList(applicationIdList);
            intersection.retainAll(applicationIds);
            // 获取重复添加的应用名称
            String names = intersection.stream().map(i -> {
                ProjectApplication application = applicationService.getById(i);
                if (Objects.nonNull(application)) {
                    return Objects.nonNull(application.getApplicationName()) ? application.getApplicationName()
                            : application.getRelatedExistsApplication();
                }
                return StrPool.EMPTY;
            }).collect(Collectors.joining(StrPool.COMMA));
            throw new BizException(names + CommonConst.APP_REPEAT);
        }

        Map<Long, ProjectApplication> applicationMap = applicationService.list(Wrappers.lambdaQuery(ProjectApplication.class)
                        .in(ProjectApplication::getId, applicationIdList)).stream()
                .collect(Collectors.toMap(ProjectApplication::getId, a -> a));
        for (Long applicationId : applicationIdList) {
            PerformanceAppraisalApplication paa = new PerformanceAppraisalApplication();
            paa.setAppraisalId(id);
            paa.setApplicationId(applicationId);
            ProjectApplication projectApplication = applicationMap.get(applicationId);
            if (Objects.nonNull(projectApplication)) {
                paa.setAppraisalProjectId(projectApplication.getProjectId());
                paa.setAppraisalProjectCode(projectApplication.getProjectCode());
            }
            paa.setCreateBy(user.getUsername());
            paa.setCreateOn(LocalDateTime.now());
            paa.setUpdateBy(user.getUsername());
            paa.setUpdateOn(LocalDateTime.now());
            performanceAppraisalApplicationService.save(paa);
        }
    }

    @Transactional
    public void saveProjects(PerformanceAppraisalEditDTO editDTO, UserInfoDetails user) {
        if (Objects.isNull(editDTO.getProjects())) {
            return;
        }

        // 删除计划内的项目
        performanceAppraisalProjectService.remove(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                .eq(PerformanceAppraisalProject::getAppraisalId, editDTO.getId()));
        // 删除项目的打分信息
        List<Long> projectIds = editDTO.getProjects().stream().map(AppraisalProjectDTO::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(projectIds)) {
            throw new BizException("请选择至少一个评价项目!");
        }
        List<String> projectCodes = projectService.listByIds(projectIds).stream().map(Project::getProjectCode).collect(Collectors.toList());
        // 删除项目的打分信息
        performanceAppraisalScoreInfoService.remove(Wrappers.lambdaQuery(PerformanceAppraisalScoreInfo.class)
                .eq(PerformanceAppraisalScoreInfo::getAppraisalId, editDTO.getId())
                .in(PerformanceAppraisalScoreInfo::getAppraisalProjectCode, projectCodes));

        Integer startSelfDays = editDTO.getStartSelfDays();
        Integer completeSelfDays = editDTO.getCompleteSelfDays();
        List<AppraisalProjectDTO> projects = editDTO.getProjects();
        for (AppraisalProjectDTO appraisalProject : projects) {
            Project newProject = projectService.getNewProject(appraisalProject.getId());
            VUtils.isTrue(Objects.isNull(newProject)).throwMessage("项目不存在 " + appraisalProject.getId());
            // 获取项目终验完成的时间
            LocalDateTime finishTime = getProjectFinishTime(newProject);
            PerformanceAppraisalProject pap = new PerformanceAppraisalProject();
            pap.setAppraisalId(editDTO.getId());
            pap.setProjectId(appraisalProject.getId());
            pap.setProjectCode(newProject.getProjectCode());
            pap.setIsReAppraisal(appraisalProject.getIsReAppraisal());
            pap.setCreateBy(user.getUsername());
            pap.setCreateOn(LocalDateTime.now());
            pap.setUpdateBy(user.getUsername());
            pap.setUpdateOn(LocalDateTime.now());
            LocalDateTime selfAppraisalStart = finishTime.plusDays(startSelfDays);
            pap.setSelfAppraisalStart(selfAppraisalStart);
            long days = startSelfDays + completeSelfDays;
            LocalDateTime selfAppraisalEnd = finishTime.plusDays(days);
            pap.setSelfAppraisalEnd(selfAppraisalEnd);
            performanceAppraisalProjectService.save(pap);
        }
    }

    @Transactional
    public void saveApplications(PerformanceAppraisalEditDTO editDTO, UserInfoDetails user) {
        if (Objects.isNull(editDTO.getApplicationIds())) {
            return;
        }
        // 删除计划内的应用
        performanceAppraisalApplicationService.remove(Wrappers.lambdaQuery(PerformanceAppraisalApplication.class)
                .eq(PerformanceAppraisalApplication::getAppraisalId, editDTO.getId()));
        // 删除计划内应用的打分信息
        List<Long> applicationIdList = editDTO.getApplicationIds();
        if (CollUtil.isEmpty(applicationIdList)) {
            throw new BizException("请选择至少一个应用!");
        }
        // 删除应用的打分信息
        performanceAppraisalAppScoreInfoService.remove(Wrappers.lambdaQuery(PerformanceAppraisalAppScoreInfo.class)
                .eq(PerformanceAppraisalAppScoreInfo::getAppraisalId, editDTO.getId())
                .in(PerformanceAppraisalAppScoreInfo::getApplicationId, applicationIdList));

        Map<Long, ProjectApplication> applicationMap = applicationService.list(Wrappers.lambdaQuery(ProjectApplication.class)
                        .in(ProjectApplication::getId, applicationIdList)).stream()
                .collect(Collectors.toMap(ProjectApplication::getId, a -> a));
        for (Long applicationId : applicationIdList) {
            PerformanceAppraisalApplication paa = new PerformanceAppraisalApplication();
            paa.setAppraisalId(editDTO.getId());
            paa.setApplicationId(applicationId);
            ProjectApplication projectApplication = applicationMap.get(applicationId);
            if (Objects.nonNull(projectApplication)) {
                paa.setAppraisalProjectId(projectApplication.getProjectId());
                paa.setAppraisalProjectCode(projectApplication.getProjectCode());
            }
            paa.setCreateBy(user.getUsername());
            paa.setCreateOn(LocalDateTime.now());
            paa.setUpdateBy(user.getUsername());
            paa.setUpdateOn(LocalDateTime.now());
            performanceAppraisalApplicationService.save(paa);
        }
    }

    /**
     * 删除绩效评价计划
     * 连带删除 其下所有
     *
     * @param id
     * @return
     */
    public String delete(Long id) {
        PerformanceAppraisal pa = performanceAppraisalService.getById(id);
        VUtils.isTrue(Objects.isNull(pa)).throwMessage("绩效评价不存在 删除失败!");

        // 获取评价计划内的待评价项目信息,并按自评开始时间排序
        List<PerformanceAppraisalProject> paps = performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                .eq(PerformanceAppraisalProject::getAppraisalId, id)
                .orderBy(Boolean.TRUE, Boolean.TRUE, PerformanceAppraisalProject::getSelfAppraisalStart));
        // 获取计划内项目的自评开始时间
        Optional<LocalDateTime> min = paps.stream().map(PerformanceAppraisalProject::getSelfAppraisalStart).min(LocalDateTime::compareTo);
        if (min.isPresent()) {
            // 比较当前时间与自评开始时间最小值
            if (LocalDateTime.now().isAfter(min.get())) {
                throw new BizException("评价计划内已有项目到达自评时间，无法删除!");
            }
        }

        if (performanceAppraisalService.removeById(id)) {
            // 删除评价计划关联的项目
            //绩效关联的项目
            if (CollUtil.isNotEmpty(paps)) {
                performanceAppraisalProjectService.removeBatchByIds(paps);
                List<String> projectCodes = paps.stream().map(PerformanceAppraisalProject::getProjectCode).collect(Collectors.toList());
                // 删除项目的打分信息
                List<PerformanceAppraisalScoreInfo> scoreInfos = performanceAppraisalScoreInfoService.list(Wrappers.lambdaQuery(PerformanceAppraisalScoreInfo.class)
                        .eq(PerformanceAppraisalScoreInfo::getAppraisalId, id)
                        .in(PerformanceAppraisalScoreInfo::getAppraisalProjectCode, projectCodes));
                if (CollUtil.isNotEmpty(scoreInfos)) {
                    performanceAppraisalScoreInfoService.removeBatchByIds(scoreInfos);
                }
            }
            // 删除评价计划关联的应用
            //绩效关联的应用
            List<PerformanceAppraisalApplication> paas = performanceAppraisalApplicationService.list(Wrappers.lambdaQuery(PerformanceAppraisalApplication.class)
                    .eq(PerformanceAppraisalApplication::getAppraisalId, id));
            if (CollUtil.isNotEmpty(paas)) {
                performanceAppraisalApplicationService.removeBatchByIds(paas);
                List<Long> applicationIds = paas.stream().map(PerformanceAppraisalApplication::getApplicationId).collect(Collectors.toList());
                // 删除应用的打分信息
                List<PerformanceAppraisalAppScoreInfo> scoreInfos = performanceAppraisalAppScoreInfoService
                        .list(Wrappers.lambdaQuery(PerformanceAppraisalAppScoreInfo.class)
                                .eq(PerformanceAppraisalAppScoreInfo::getAppraisalId, id)
                                .in(PerformanceAppraisalAppScoreInfo::getApplicationId, applicationIds));
                if (CollUtil.isNotEmpty(scoreInfos)) {
                    performanceAppraisalAppScoreInfoService.removeBatchByIds(scoreInfos);
                }
            }
            // 删除评级计划关联的分组信息
            groupService.remove(Wrappers.lambdaQuery(PerformanceAppraisalProjectGroup.class)
                    .eq(PerformanceAppraisalProjectGroup::getAppraisalId, id));
            return "删除成功";
        }
        return "删除失败";
    }

    public List<PerformanceAppraisalProjectGroupVO> groupList(Long appraisalId, String name) {
        List<PerformanceAppraisalProjectGroup> groups = groupService.list(
                Wrappers.lambdaQuery(PerformanceAppraisalProjectGroup.class)
                        .eq(PerformanceAppraisalProjectGroup::getAppraisalId, appraisalId)
                        .like(StringUtils.isNotBlank(name), PerformanceAppraisalProjectGroup::getName, name)
                        .orderByDesc(PerformanceAppraisalProjectGroup::getCreateOn));
        if (CollUtil.isEmpty(groups)) {
            return Collections.emptyList();
        }

        Set<String> allEmployeeCodes = Sets.newHashSet();
        Set<String> projectCodes = Sets.newHashSet();
        Map<Long, UserFullInfoDTO> userMap = Maps.newHashMap();
        Map<String, Project> projectMap = Maps.newHashMap();
        groups.forEach(g -> {
            allEmployeeCodes.addAll(CodeUtil.convertStrToList(g.getReAppraisalUsers()));
            allEmployeeCodes.addAll(CodeUtil.convertStrToList(g.getVerificationUsers()));
            projectCodes.addAll(CodeUtil.convertStrToList(g.getProjectCodes()));
        });

        if (CollUtil.isNotEmpty(allEmployeeCodes)) {
            List<UserFullInfoDTO> users = Lists.newArrayList();
            for (String employeeCode : allEmployeeCodes) {
                UserFullInfoDTO userFullInfo = userInfoHelper.getUserFullInfo(Long.parseLong(employeeCode));
                users.add(userFullInfo);
            }
            users.forEach(w -> userMap.put(w.getUserId(), w));
        }

        if (CollUtil.isNotEmpty(projectCodes)) {
            List<Project> projects = projectService.list(Wrappers.lambdaQuery(Project.class)
                    .in(Project::getProjectCode, projectCodes)
                    .eq(Project::getNewest, Boolean.TRUE));
            if (CollUtil.isNotEmpty(projects)) {
                projects.forEach(w -> projectMap.put(w.getProjectCode(), w));
            }
        }

        return groups.stream().map(g -> {
            PerformanceAppraisalProjectGroupVO vo = new PerformanceAppraisalProjectGroupVO();
            vo.setAppraisalId(g.getAppraisalId());
            vo.setName(g.getName());
            vo.setCreateOn(g.getCreateOn());
            vo.setCreateBy(g.getCreateBy());
            vo.setUpdateBy(g.getUpdateBy());
            vo.setUpdateOn(g.getUpdateOn());
            vo.setId(g.getId());
            vo.setProjects(checkProject(g.getProjectCodes(), projectMap));
            vo.setReAppraisalUsers(checkUser(g.getReAppraisalUsers(), userMap));
            vo.setVerificationUsers(checkUser(g.getVerificationUsers(), userMap));
            if (StringUtils.isNotBlank(g.getVerifyLeader())) {
                UserFullInfoDTO userFullInfoDto = userMap.get(Long.parseLong(g.getVerifyLeader()));
                vo.setVerifyLeader(userFullInfoDto);
            }
            return vo;
        }).collect(Collectors.toList());
    }

    /**
     * 分组详情
     *
     * @param id
     * @return
     */
    public PerformanceAppraisalProjectGroupVO groupDetail(Long id) {
        PerformanceAppraisalProjectGroup group = groupService.getById(id);
        if (Objects.isNull(group)) {
            return null;
        }

        Map<String, Project> projectMap = Maps.newHashMap();
        List<Project> projects = projectService.list(Wrappers.lambdaQuery(Project.class)
                .in(StringUtils.isNotBlank(group.getProjectCodes()),
                        Project::getProjectCode, Arrays.stream(group.getProjectCodes()
                                .split(StrPool.COMMA)).collect(Collectors.toList()))
                .eq(Project::getNewest, Boolean.TRUE));
        if (CollUtil.isNotEmpty(projects)) {
            projects.forEach(w -> projectMap.put(w.getProjectCode(), w));
        }

        Map<Long, UserFullInfoDTO> userMap = Maps.newHashMap();
        Set<String> allEmployeeCodes = Sets.newHashSet();
        allEmployeeCodes.addAll(CodeUtil.convertStrToList(group.getReAppraisalUsers()));
        allEmployeeCodes.addAll(CodeUtil.convertStrToList(group.getVerificationUsers()));
        if (CollUtil.isNotEmpty(allEmployeeCodes)) {
            List<UserFullInfoDTO> users = Lists.newArrayList();
            for (String employeeCode : allEmployeeCodes) {
                users.add(userInfoHelper.getUserFullInfo(Long.valueOf(employeeCode)));
            }
            users.forEach(w -> userMap.put(w.getUserId(), w));
        }

        PerformanceAppraisalProjectGroupVO vo = new PerformanceAppraisalProjectGroupVO();
        vo.setAppraisalId(group.getAppraisalId());
        vo.setName(group.getName());
        vo.setCreateOn(group.getCreateOn());
        vo.setCreateBy(group.getCreateBy());
        vo.setUpdateBy(group.getUpdateBy());
        vo.setUpdateOn(group.getUpdateOn());
        vo.setId(group.getId());
        vo.setProjects(checkProject(group.getProjectCodes(), projectMap));
        vo.setReAppraisalUsers(checkUser(group.getReAppraisalUsers(), userMap));
        vo.setVerificationUsers(checkUser(group.getVerificationUsers(), userMap));
        if (StringUtils.isNotBlank(group.getVerifyLeader())) {
            UserFullInfoDTO dto = userMap.get(Long.parseLong(group.getVerifyLeader()));
            vo.setVerifyLeader(dto);
        }
        return vo;
    }

    /**
     * 分组 保存
     *
     * @param dto
     * @return
     */
    public String groupSave(PerformanceAppraisalProjectGroupSaveDTO dto) {
        UserInfoDetails user = LoginUserUtil.loginUserDetail();

        PerformanceAppraisalProjectGroup group = BeanUtil.copyProperties(dto, PerformanceAppraisalProjectGroup.class);
        // 获取当前评价计划内的分组信息
        List<PerformanceAppraisalProjectGroup> groupList = groupService.list(Wrappers.lambdaQuery(PerformanceAppraisalProjectGroup.class)
                .eq(PerformanceAppraisalProjectGroup::getAppraisalId, dto.getAppraisalId()));
        if (Objects.isNull(dto.getId())) {
            group.setId(null);
            group.setCreateOn(LocalDateTime.now());
            group.setCreateBy(user.getUsername());
        } else {
            // 编辑分组
            PerformanceAppraisalProjectGroup old = groupService.getById(dto.getId());
            VUtils.isTrue(Objects.isNull(old)).throwMessage("该分组不存在 编辑失败！");
            group.setId(old.getId());
            // 先删除旧的分组
            groupList.remove(old);
        }
        if (CollUtil.isNotEmpty(dto.getProjectCodes())) {
            // 判断选择的项目是否已经在当前评价计划的其他分组内
            // 获取当前评价计划的其他分组的项目信息
            List<String> projectCodeList = groupList.stream()
                    .map(PerformanceAppraisalProjectGroup::getProjectCodes)
                    .collect(Collectors.toList());
            List<String> compareCodes = Lists.newArrayList();
            for (String projectCode : projectCodeList) {
                if (projectCode.contains(StrPool.COMMA)) {
                    List<String> codes = Arrays.asList(projectCode.split(StrPool.COMMA));
                    compareCodes.addAll(codes);
                } else {
                    compareCodes.add(projectCode);
                }
            }
            checkProjectCodes(dto.getProjectCodes(), compareCodes);
            group.setProjectCodes(String.join(StrPool.COMMA, dto.getProjectCodes()));
        }
        if (CollUtil.isNotEmpty(dto.getReAppraisalUsers())) {
            // 判断选择的复评人员是否已经在当前评价计划的其他分组内
            // 获取当前评价计划的其他分组的复评人员信息
            List<String> reUserList = groupList.stream()
                    .map(PerformanceAppraisalProjectGroup::getReAppraisalUsers)
                    .collect(Collectors.toList());
            List<String> compareUsers = Lists.newArrayList();
            for (String reUser : reUserList) {
                if (reUser.contains(StrPool.COMMA)) {
                    List<String> users = Arrays.asList(reUser.split(StrPool.COMMA));
                    compareUsers.addAll(users);
                } else {
                    compareUsers.add(reUser);
                }
            }
            checkReAppraisalAndVerifyUsers(dto.getReAppraisalUsers(), compareUsers, CommonConst.REAPPRAISAL_TYPE);
            group.setReAppraisalUsers(String.join(StrPool.COMMA, dto.getReAppraisalUsers()));
        }
        if (CollUtil.isNotEmpty(dto.getVerificationUsers())) {
            // 判断选择的核查人员是否已经在当前评价计划的其他分组内
            // 获取当前评价计划的其他分组的核查人员信息
            List<String> verifyList = groupList.stream()
                    .map(PerformanceAppraisalProjectGroup::getVerificationUsers)
                    .collect(Collectors.toList());
            List<String> compareUsers = Lists.newArrayList();
            for (String verifyUser : verifyList) {
                if (verifyUser.contains(StrPool.COMMA)) {
                    List<String> users = Arrays.asList(verifyUser.split(StrPool.COMMA));
                    compareUsers.addAll(users);
                } else {
                    compareUsers.add(verifyUser);
                }
            }
            checkReAppraisalAndVerifyUsers(dto.getVerificationUsers(), compareUsers, CommonConst.VERIFY_TYPE);
            group.setVerificationUsers(String.join(StrPool.COMMA, dto.getVerificationUsers()));
        }
        group.setUpdateOn(LocalDateTime.now());
        group.setUpdateBy(user.getUsername());
        groupService.saveOrUpdate(group);
        return "操作成功";
    }

    private void checkProjectCodes(List<String> projectCodes, List<String> projectCodeList) {
        // 判断选择的项目是否已经在当前评价计划的其他分组内
        // 如果提交的项目在该评价计划其他分组中
        if (!CollectionUtil.intersection(projectCodes, projectCodeList).isEmpty()) {
            ArrayList<String> proCodes = Lists.newArrayList(projectCodes);
            proCodes.retainAll(projectCodeList);
            // 获取重复添加的项目Code
            String names = proCodes.stream().map(i -> {
                Project project = projectService.getProjectByCode(i);
                if (Objects.nonNull(project)) {
                    return project.getProjectName();
                }
                return StrPool.EMPTY;
            }).collect(Collectors.joining(StrPool.COMMA));
            throw new BizException("项目：" + names + CommonConst.REPEAT);
        }
    }

    private void checkReAppraisalAndVerifyUsers(List<String> checkUsers, List<String> compareUsers, Integer type) {
        // 如果提交的复评/核查人员在该评价计划其他分组中
        if (!CollectionUtil.intersection(checkUsers, compareUsers).isEmpty()) {
            ArrayList<String> reUsers = Lists.newArrayList(checkUsers);
            reUsers.retainAll(compareUsers);
            // 获取重复添加的复评/核查人员名字
            String names = reUsers.stream().map(i -> {
                UserFullInfoDTO info = userInfoHelper.getUserFullInfo(Long.valueOf(i));
                if (Objects.nonNull(info)) {
                    return info.getUsername();
                }
                return StrPool.EMPTY;
            }).collect(Collectors.joining(StrPool.COMMA));
            if (CommonConst.REAPPRAISAL_TYPE.equals(type)) {
                throw new BizException("复评人员：" + names + CommonConst.REPEAT);
            } else if (CommonConst.VERIFY_TYPE.equals(type)) {
                throw new BizException("核查人员：" + names + CommonConst.REPEAT);
            }
        }
    }

    /**
     * 删除分组
     *
     * @param id
     * @return
     */
    public String groupDelete(Long id) {
        PerformanceAppraisalProjectGroup group = groupService.getById(id);
        VUtils.isTrue(Objects.isNull(group)).throwMessage("分组不存在");

        //评价Id
        Long appraisalId = group.getAppraisalId();

        PerformanceAppraisal pa = performanceAppraisalService.getById(appraisalId);
        VUtils.isTrue(Objects.isNull(pa)).throwMessage("评价不存在");

        if (groupService.removeById(id)) {
            return "删除成功";
        }
        return "删除失败";
    }

    private List<PerformanceAppraisalProjectVO> checkProject(String projectIds, Map<String, Project> projectMap) {
        if (StringUtils.isBlank(projectIds)) {
            return Collections.emptyList();
        }
        return Arrays.stream(projectIds.split(StrPool.COMMA)).map(projectCode -> {
            PerformanceAppraisalProjectVO vo = new PerformanceAppraisalProjectVO();
            if (projectMap.containsKey(projectCode)) {
                Project project = projectMap.get(projectCode);
                vo.setProjectName(project.getProjectName());
                vo.setProjectTypeName(BizUtils.getProjectTypeName(project.getProjectType()));
                vo.setProjectType(project.getProjectType());
                vo.setProjectId(project.getId());
                vo.setProjectCode(projectCode);
                vo.setProjectYear(project.getProjectYear());
                vo.setDeclareAmount(project.getDeclareAmount());
            }
            return vo;
        }).collect(Collectors.toList());
    }

    private List<UserFullInfoDTO> checkUser(String users, Map<Long, UserFullInfoDTO> userMap) {
        if (StringUtils.isBlank(users)) {
            return Collections.emptyList();
        }
        return Arrays.stream(users.split(StrPool.COMMA))
                .filter(NumberUtil::isLong)
                .map(w -> userMap.get(Long.parseLong(w)))
                .collect(Collectors.toList());
    }

    public PageVo<PerformanceAppraisalApplicationVO> applicationList(PerformanceAppraisalListReq req) {
        Page<ProjectApplication> page = req.page();
        // 获取登录用户所在区域已验收项目
        List<Project> projects = projectService.list(Wrappers.lambdaQuery(Project.class)
                .eq(Project::getStatus, ProjectStatusEnum.ACCEPTED.getCode())
                .eq(Project::getNewest, Boolean.TRUE));
        // 获取已验收项目关联的应用信息
        List<Integer> projectVersions = projects.stream().map(Project::getVersion).collect(Collectors.toList());
        List<String> projectCodes = projects.stream().map(Project::getProjectCode).collect(Collectors.toList());
        LambdaQueryWrapper<ProjectApplication> wrapper = Wrappers.lambdaQuery(ProjectApplication.class)
                .like(StringUtils.isNotBlank(req.getApplicationName()), ProjectApplication::getApplicationName, req.getApplicationName())
                .like(StringUtils.isNotBlank(req.getBuildOrgName()), ProjectApplication::getBuildOrgName, req.getBuildOrgName())
                .in(ProjectApplication::getProjectCode, projectCodes)
                .in(ProjectApplication::getProjectVersion, projectVersions)
                .orderByDesc(ProjectApplication::getCreateOn);
        applicationService.page(page, wrapper);
        if (CollUtil.isEmpty(page.getRecords())) {
            return PageVo.empty();
        }
        List<PerformanceAppraisalApplicationVO> res = page.getRecords().stream().map(r -> {
            PerformanceAppraisalApplicationVO vo = new PerformanceAppraisalApplicationVO();
            vo.setAppId(r.getId());
            vo.setAppraisalProjectId(r.getProjectId());
            vo.setAppraisalProjectCode(r.getProjectCode());
            vo.setApplicationName(Objects.nonNull(r.getRelatedExistsApplication()) ? r.getRelatedExistsApplication() : r.getApplicationName());
            vo.setBuildOrgName(r.getBuildOrgName());
            vo.setApplicationType(r.getApplicationType());
            vo.setBizDomain(r.getBizDomain());
            vo.setPublishSide(r.getPublishSide());
            return vo;
        }).collect(Collectors.toList());
        return PageVo.of(res, page.getTotal());
    }

    public String addProject(AddAppraisalObjectDTO addDTO) {
        List<Long> projectIdList = addDTO.getProjectIds();
        if (CollUtil.isEmpty(projectIdList)) {
            throw new BizException("请选择至少一个评价项目!");
        }
        // 获取已经创建的评价计划中添加的评价项目ID
        List<Long> projectIds = performanceAppraisalProjectService.list().stream()
                .map(PerformanceAppraisalProject::getProjectId).collect(Collectors.toList());
        Long appraisalId = addDTO.getAppraisalId();
        // 如果评价计划不为空，说明是编辑评价计划，
        // 评价计划中原来已经勾选的待评价项目，不作为判断重复添加的内容
        if (Objects.nonNull(appraisalId)) {
            // 获取当前编辑的评价计划中选择的项目
            List<Long> proIds = performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                            .eq(PerformanceAppraisalProject::getAppraisalId, appraisalId)).stream()
                    .map(PerformanceAppraisalProject::getProjectId).collect(Collectors.toList());
            // 去除这些项目
            projectIds.removeAll(proIds);
        }
        // 如果有交集,说明选择的项目中，有已经在其他评价计划中的项目
        if (Boolean.TRUE.equals(haveIntersection(projectIdList, projectIds))) {
            // 得到交集
            List<Long> intersection = Lists.newArrayList(projectIdList);
            intersection.retainAll(projectIds);
            // 获取重复添加的项目名称
            String names = intersection.stream().map(i -> {
                Project project = projectService.getById(i);
                if (Objects.nonNull(project)) {
                    return project.getProjectName();
                }
                return StrPool.EMPTY;
            }).collect(Collectors.joining(StrPool.COMMA));
            throw new BizException(names + CommonConst.PROJECT_REPEAT);
        }
        return "添加成功";
    }


    public String addApplication(AddAppraisalObjectDTO addDTO) {
        List<Long> applicationIdList = addDTO.getApplicationIds();
        if (CollUtil.isEmpty(applicationIdList)) {
            throw new BizException("请选择至少一个评应用!");
        }
        // 获取已经创建的评价计划中添加的评价应用ID
        List<Long> applicationIds = performanceAppraisalApplicationService.list().stream()
                .map(PerformanceAppraisalApplication::getApplicationId).collect(Collectors.toList());
        Long appraisalId = addDTO.getAppraisalId();
        // 如果评价计划不为空，说明是编辑评价计划，
        // 评价计划中原来已经勾选的待评价应用，不作为判断重复添加的内容
        if (Objects.nonNull(appraisalId)) {
            // 获取当前编辑的评价计划中选择的应用
            List<Long> appIds = performanceAppraisalApplicationService.list(Wrappers.lambdaQuery(PerformanceAppraisalApplication.class)
                            .eq(PerformanceAppraisalApplication::getAppraisalId, appraisalId)).stream()
                    .map(PerformanceAppraisalApplication::getApplicationId).collect(Collectors.toList());
            // 去除这些应用
            applicationIds.removeAll(appIds);
        }
        // 如果有交集,说明选择的应用中，有已经在其他评价计划中的应用
        if (Boolean.TRUE.equals(haveIntersection(applicationIdList, applicationIds))) {
            // 得到交集
            List<Long> intersection = Lists.newArrayList(applicationIdList);
            intersection.retainAll(applicationIds);
            // 获取重复添加的应用名称
            String names = intersection.stream().map(i -> {
                ProjectApplication application = applicationService.getById(i);
                if (Objects.nonNull(application)) {
                    return Objects.nonNull(application.getApplicationName()) ? application.getApplicationName()
                            : application.getRelatedExistsApplication();
                }
                return StrPool.EMPTY;
            }).collect(Collectors.joining(StrPool.COMMA));
            throw new BizException(names + CommonConst.APP_REPEAT);
        }
        return "添加成功";
    }

    private Boolean haveIntersection(List<Long> idList, List<Long> ids) {
        return !CollectionUtil.intersection(idList, ids).isEmpty();
    }

    public PageVo<PerformanceAppraisalProjectVO> projectList(PerformanceAppraisalListReq req) {
        Long appraisalId = req.getAppraisalId();
        VUtils.isTrue(Objects.isNull(appraisalId)).throwMessage("未传入评价计划ID");
        String projectName = req.getProjectName();
        String buildOrgName = req.getBuildOrgName();
        // 获取评价计划内的选择的项目信息
        List<PerformanceAppraisalProject> appraisalProjectList = performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                .eq(PerformanceAppraisalProject::getAppraisalId, appraisalId));
        List<String> projectCodes = appraisalProjectList.stream().map(PerformanceAppraisalProject::getProjectCode).collect(Collectors.toList());
        if (CollUtil.isEmpty(projectCodes)) {
            return PageVo.empty();
        }
        LambdaQueryWrapper<Project> wrapper = Wrappers.lambdaQuery(Project.class)
                .in(Project::getProjectCode, projectCodes)
                .eq(Project::getNewest, Boolean.TRUE);

        // 如果对项目名称进行模糊查询
        if (StringUtils.isNotBlank(projectName) && StringUtils.isBlank(buildOrgName)) {
            wrapper.like(Project::getProjectName, projectName);
        }
        // 如果对申报单位进行模糊查询
        else if (StringUtils.isNotBlank(buildOrgName) && StringUtils.isBlank(projectName)) {
            wrapper.like(Project::getBuildOrgName, buildOrgName);
        }
        // 同时对项目名称和申报单位进行模糊查询
        else if (StringUtils.isNotBlank(projectName) && StringUtils.isNotBlank(buildOrgName)) {
            wrapper.like(Project::getProjectName, projectName)
                    .like(Project::getBuildOrgName, buildOrgName);
        }
        List<Project> projects = projectService.list(wrapper);
        if (CollUtil.isEmpty(projects)) {
            return PageVo.empty();
        }
        List<PerformanceAppraisalProjectVO> voList = projects.stream().map(p -> {
            PerformanceAppraisalProjectVO appraisalProjectVo = new PerformanceAppraisalProjectVO();
            BeanUtil.copyProperties(p, appraisalProjectVo);
            appraisalProjectVo.setProjectTypeName(ProjectTypeNewEnum.getDesc(p.getProjectType()));
            return appraisalProjectVo;
        }).collect(Collectors.toList());
        return PageVo.of(voList, voList.size());
    }

    public PageVo<ProjectLibListItemVO> finalProjectList(PerformanceAppraisalListReq req) {

        UserFullInfoDTO user = userInfoHelper.getUserFullInfo(LoginUserUtil.getUserId());

        Long appraisalId = req.getAppraisalId();
        String projectName = req.getProjectName();
        String buildOrgName = req.getBuildOrgName();
        String projectType = req.getProjectType();
        Integer projectYear = req.getProjectYear();
        // 从项目库获取本区域已验收的项目列表
        ProjectListReq param = new ProjectListReq();
        param.setProjectName(projectName);
        param.setBuildOrgName(buildOrgName);
        param.setProjectType(projectType);
        param.setProjectYear(projectYear);
        param.setStatus(ProjectStatusEnum.ACCEPTED.getCode());
        // 获取已添加到评价计划中的项目
        List<String> projectCodes = performanceAppraisalProjectService.list().stream()
                .map(PerformanceAppraisalProject::getProjectCode).collect(Collectors.toList());
        // 如果是编辑评价计划，获取当前评价计划已添加的项目，并保留当前计划已添加的项目
        if (Objects.nonNull(appraisalId)) {
            List<PerformanceAppraisalProject> projects = performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                    .eq(PerformanceAppraisalProject::getAppraisalId, appraisalId));
            if (CollUtil.isNotEmpty(projects)) {
                List<String> projectCodeList = projects.stream().map(PerformanceAppraisalProject::getProjectCode).collect(Collectors.toList());
                projectCodes.removeAll(projectCodeList);
            }
        }
        // 过滤掉已经添加到评价计划中的项目(如果是编辑评价计划，保留当前计划已添加的项目)
        param.setProjectCodes(projectCodes);
        return projectLibManage.projectLibListWithPermission(param, user);
    }

    public PageVo<ProjectApplicationVO> finalApplicationList(PerformanceAppraisalListReq req) {
        Long appraisalId = req.getAppraisalId();

        LambdaQueryWrapper<ProjectApplication> wrapper = Wrappers.lambdaQuery(ProjectApplication.class)
                .like(StringUtils.isNotBlank(req.getBuildOrgName()), ProjectApplication::getBuildOrgName, req.getBuildOrgName());

        if (StringUtils.isNotBlank(req.getApplicationName())) {
            wrapper.and(q1 -> q1.like(ProjectApplication::getApplicationName, req.getApplicationName())
                    .or(q2 -> q2.like(ProjectApplication::getRelatedExistsApplication, req.getApplicationName())));
        }
        // 获取本区域已验收的项目关联的应用
        List<Project> projectList = projectService.list(Wrappers.lambdaQuery(Project.class)
                .eq(Project::getNewest, Boolean.TRUE)
                .eq(Project::getStatus, ProjectStatusEnum.ACCEPTED.getCode()));
        if (CollUtil.isEmpty(projectList)) {
            return PageVo.empty();
        }
        List<String> projectCodeList = projectList.stream().map(Project::getProjectCode).collect(Collectors.toList());
        List<Integer> projectVersionList = projectList.stream().map(Project::getVersion).collect(Collectors.toList());
        wrapper.in(ProjectApplication::getProjectCode, projectCodeList);
        wrapper.in(ProjectApplication::getProjectVersion, projectVersionList);
        wrapper.orderByDesc(ProjectApplication::getUpdateOn);
        List<ProjectApplication> appList = projectApplicationService.list(wrapper);
        if (CollUtil.isEmpty(appList)) {
            return PageVo.empty();
        }

        List<ProjectApplication> applicationList = Lists.newArrayList();

        // 按项目编号+应用名称+IRS关联应用名称分组，获取最新版本的应用
        Map<String, List<ProjectApplication>> appMap = appList.stream().collect(Collectors.groupingBy(p -> p.getProjectCode() + p.getRelatedExistsApplication() + p.getApplicationName()));
        for (Map.Entry<String, List<ProjectApplication>> entry : appMap.entrySet()) {
            List<ProjectApplication> applications = entry.getValue();
            Optional<ProjectApplication> max = applications.stream().max(Comparator.comparingInt(ProjectApplication::getProjectVersion));
            if (max.isPresent()) {
                ProjectApplication application = max.get();
                applicationList.add(application);
            }
        }
        if (CollUtil.isEmpty(applicationList)) {
            return PageVo.empty();
        }
        // 获取已添加到评价计划中的应用
        List<Long> applicationIdList = performanceAppraisalApplicationService.list().stream()
                .map(PerformanceAppraisalApplication::getApplicationId).collect(Collectors.toList());
        // 如果是编辑评价计划，保留当前计划已添加的应用
        if (Objects.nonNull(appraisalId)) {
            List<PerformanceAppraisalApplication> projectApplications = performanceAppraisalApplicationService.list(Wrappers.lambdaQuery(PerformanceAppraisalApplication.class)
                    .eq(PerformanceAppraisalApplication::getAppraisalId, appraisalId));
            if (CollUtil.isNotEmpty(projectApplications)) {
                List<Long> appIdList = projectApplications.stream().map(PerformanceAppraisalApplication::getApplicationId).collect(Collectors.toList());
                applicationIdList.removeAll(appIdList);
            }
        }
        List<ProjectApplication> resList = applicationList.stream().filter(a -> !applicationIdList.contains(a.getId())).collect(Collectors.toList());
        if (CollUtil.isEmpty(resList)) {
            return PageVo.empty();
        }
        //List<ProjectApplication> relatedAppList = Lists.newArrayList();
        //// TODO 对IRS关联应用是否按照应用名称和应用code进行去重(在不同项目中,已经在IRS注册过的同一个应用只显示一个)？
        //List<ProjectApplication> relatedList = resList.stream().filter(r -> StringUtils.isNotBlank(r.getRelatedExistsApplication())).collect(Collectors.toList());
        //if (CollUtil.isNotEmpty(relatedList)) {
        //    resList.removeAll(relatedList);
        //    Map<String, List<ProjectApplication>> relatedAppMap = relatedList.stream()
        //            .collect(Collectors.groupingBy(r -> r.getRelatedExistsApplication() + r.getRelatedExistsApplicationCode()));
        //    for (Map.Entry<String, List<ProjectApplication>> entry : relatedAppMap.entrySet()) {
        //        List<ProjectApplication> value = entry.getValue();
        //        relatedAppList.add(value.get(0));
        //    }
        //    resList.addAll(relatedAppList);
        //}
        //// TODO 对初次建设应用,是否根据建设方案申报时填写的应用名称、应用类型、发布端、应用简介、等保级别、密评级别 去重？
        Integer pageNumber = req.getPageNumber();
        Integer pageSize = req.getPageSize();
        List<ProjectApplication> resultList = resList.stream()
                .skip((long) (pageNumber - 1) * pageSize)
                .limit(pageSize)
                .collect(Collectors.toList());

        List<ProjectApplicationVO> res = resultList.stream()
                .map(app -> BeanUtil.copyProperties(app, ProjectApplicationVO.class))
                .collect(Collectors.toList());

        return PageVo.of(res, resList.size());
    }
}
