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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.StrPool;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.hz.pm.api.common.helper.UserInfoHelper;
import com.hz.pm.api.performance.enumration.AppraisalTypeEnum;
import com.hz.pm.api.performance.enumration.RectifyAuditEnum;
import com.hz.pm.api.performance.enumration.RectifyStatusEnum;
import com.hz.pm.api.performance.model.dto.ProjectAppraisalDTO;
import com.hz.pm.api.performance.model.dto.ProjectAppraisalInfoDTO;
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.PerformanceAppraisalProjectVO;
import com.hz.pm.api.performance.model.vo.PerformanceAppraisalVO;
import com.hz.pm.api.performance.service.*;
import com.hz.pm.api.projectlib.model.entity.Project;
import com.hz.pm.api.projectlib.model.enumeration.ProjectTypeNewEnum;
import com.hz.pm.api.projectlib.service.IProjectService;
import com.hz.pm.api.sys.model.entity.Role;
import com.hz.pm.api.sys.service.IRoleService;
import com.hz.pm.api.user.model.enumeration.RoleEnum;
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 lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * RectifyAuditManage
 *
 * @author CMM
 * @return
 * @since 2023/08/12 17:36
 */
@Component
@Slf4j
@AllArgsConstructor
public class RectifyAuditManage {

    private final IPerformanceAppraisalService performanceAppraisalService;
    private final IPerformanceAppraisalProjectService performanceAppraisalProjectService;
    private final IProjectService projectService;
    private final IRoleService roleService;
    private final UserInfoHelper userInfoHelper;
    private final IPerformanceAppraisalProjectGroupService groupService;
    private final IPerformanceIndicatorProjectTemplateDetailService indicatorProjectTemplateDetailService;
    private final IPerformanceAppraisalScoreInfoService performanceAppraisalScoreInfoService;

    /**
     * 绩效列表
     *
     * @param req
     * @return
     */
    public PageVo<PerformanceAppraisalVO> list(PerformanceAppraisalListReq req) {
        UserInfoDetails user = LoginUserUtil.loginUserDetail();

        // 当前登录用户 单位code
        String employeeCode = user.getEmployeeCode();
        // 获取当前登录用户的角色列表，只有专家才能查看该列表
        List<Role> userRoleList = user.getUserRoleList();
        List<Long> roleIdList = userRoleList.stream().map(Role::getId).collect(Collectors.toList());
        Role role =
                roleService.getOne(Wrappers.lambdaQuery(Role.class).eq(Role::getName, RoleEnum.EXPERT.getDesc()));
        if (Objects.isNull(role)) {
            throw new BizException("登录用户没有专家角色!");
        }

        // 登录用户不是专家，不能查看本单位的整改审核计划列表
        if (!roleIdList.contains(role.getId())) {
            return PageVo.empty();
        }

        // 从绩效评价 分组表中获取当前登录专家所在的分组信息 且登录用户为核查组长
        List<PerformanceAppraisalProjectGroup> groups = Lists.newArrayList();
        List<PerformanceAppraisalProjectGroup> projectGroups = groupService.list();
        for (PerformanceAppraisalProjectGroup projectGroup : projectGroups) {
            String verifyLeader = projectGroup.getVerifyLeader();
            if (Objects.nonNull(verifyLeader) && verifyLeader.equals(employeeCode)) {
                groups.add(projectGroup);
            }
        }
        // 当前登录专家没有绩效分组信息
        if (CollUtil.isEmpty(groups)) {
            return PageVo.empty();
        }

        // 获取分组所在的评价计划ID
        List<Long> appraisalIds =
                groups.stream().map(PerformanceAppraisalProjectGroup::getAppraisalId).collect(Collectors.toList());

        // 获取评价计划内的所有需整改核查项目信息(整改状态为整改待审核、整改审核不通过、整改审核通过)
        List<PerformanceAppraisalProject> paps = performanceAppraisalProjectService.list(Wrappers
                .lambdaQuery(PerformanceAppraisalProject.class)
                .in(PerformanceAppraisalProject::getAppraisalId, appraisalIds)
                .and(wp -> wp.eq(PerformanceAppraisalProject::getRectifyStatus, RectifyStatusEnum.TO_BE_REVIEWED.getCode())
                        .or().eq(PerformanceAppraisalProject::getRectifyStatus, RectifyStatusEnum.NOT_APPROVED.getCode()).or()
                        .eq(PerformanceAppraisalProject::getRectifyStatus, RectifyStatusEnum.APPROVED.getCode()))
                .eq(PerformanceAppraisalProject::getIsRectify, Boolean.TRUE));
        // 评价计划内符合条件的项目数为空
        if (CollUtil.isEmpty(paps)) {
            return PageVo.empty();
        }

        Set<Long> appraisalIdList = paps.stream().map(PerformanceAppraisalProject::getAppraisalId).collect(Collectors.toSet());

        Page<PerformanceAppraisal> page = req.page();
        LambdaQueryWrapper<PerformanceAppraisal> wrapper = Wrappers.lambdaQuery(PerformanceAppraisal.class)
                .in(PerformanceAppraisal::getId, appraisalIdList).orderByDesc(PerformanceAppraisal::getUpdateOn);
        performanceAppraisalService.page(page, wrapper);
        if (CollUtil.isEmpty(page.getRecords())) {
            return PageVo.empty();
        }

        // 按评价计划分组
        Map<Long, List<PerformanceAppraisalProject>> papsMap =
                paps.stream().collect(Collectors.groupingBy(PerformanceAppraisalProject::getAppraisalId));

        List<PerformanceAppraisalVO> res = page.getRecords().stream().map(p -> {
            PerformanceAppraisalVO vo = BeanUtil.copyProperties(p, PerformanceAppraisalVO.class);
            // 统计评价计划待核查项目数量(整改状态为：整改待审核)
            List<PerformanceAppraisalProject> projects = papsMap.get(p.getId());
            if (CollUtil.isNotEmpty(projects)) {
                List<PerformanceAppraisalProject> unRectifyAuditProjects =
                        projects.stream().filter(d -> RectifyStatusEnum.TO_BE_REVIEWED.getCode().equals(d.getRectifyStatus()))
                                .collect(Collectors.toList());
                vo.setUnRectifyAuditNumber(unRectifyAuditProjects.size());
                // 统计评价计划已核查项目数量(整改状态为：整改核查不通过、整改审核通过)
                List<PerformanceAppraisalProject> rectifiedAuditProjects =
                        paps.stream()
                                .filter(d -> RectifyStatusEnum.NOT_APPROVED.getCode().equals(d.getRectifyStatus())
                                        || RectifyStatusEnum.APPROVED.getCode().equals(d.getRectifyStatus()))
                                .collect(Collectors.toList());
                vo.setRectifiedAuditNumber(rectifiedAuditProjects.size());
            }
            return vo;
        }).collect(Collectors.toList());
        return PageVo.of(res, page.getTotal());
    }

    public PageVo<PerformanceAppraisalProjectVO> unAuditList(Long planId, PerformanceAppraisalListReq req) {
        UserInfoDetails user = LoginUserUtil.loginUserDetail();
        String employeeCode = user.getEmployeeCode();

        PerformanceAppraisal plan = performanceAppraisalService.getById(planId);
        VUtils.isTrue(Objects.isNull(plan)).throwMessage("该评价计划不存在!");

        // 因为一个核查用户只能出现在一个评价计划中的一个分组中，所以根据评价计划ID和核查组长信息可以确定分组内项目信息
        PerformanceAppraisalProjectGroup projectGroup =
                groupService.getOne(Wrappers.lambdaQuery(PerformanceAppraisalProjectGroup.class)
                        .eq(PerformanceAppraisalProjectGroup::getAppraisalId, planId)
                        .eq(PerformanceAppraisalProjectGroup::getVerifyLeader, employeeCode));
        // 当前登录专家没有为核查组长的绩效分组信息
        if (Objects.isNull(projectGroup)) {
            return PageVo.empty();
        }

        String groupProjectCodes = projectGroup.getProjectCodes();
        List<String> codes = Lists.newArrayList();
        if (groupProjectCodes.contains(StrPool.COMMA)) {
            codes.addAll(Arrays.asList(groupProjectCodes.split(StrPool.COMMA)));
        } else {
            codes.add(groupProjectCodes);
        }
        // 获取评价计划内已添加的核查组长为当前登录专家用户的待整改审核项目信息
        List<PerformanceAppraisalProject> paps =
                performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                        .eq(PerformanceAppraisalProject::getAppraisalId, plan.getId())
                        .in(PerformanceAppraisalProject::getProjectCode, codes)
                        .eq(PerformanceAppraisalProject::getIsRectify, Boolean.TRUE)
                        .eq(PerformanceAppraisalProject::getRectifyStatus, RectifyStatusEnum.TO_BE_REVIEWED.getCode()));
        if (CollUtil.isEmpty(paps)) {
            return PageVo.empty();
        }
        Map<Long, PerformanceAppraisalProject> papsMap =
                paps.stream().collect(Collectors.toMap(PerformanceAppraisalProject::getProjectId, p -> p));

        // 获取本单位在当前评价计划内的项目
        Set<String> projectCodes =
                paps.stream().map(PerformanceAppraisalProject::getProjectCode).collect(Collectors.toSet());
        Page<Project> page = req.page();
        LambdaQueryWrapper<Project> wrapper = Wrappers.lambdaQuery(Project.class)
                .in(Project::getProjectCode, projectCodes).eq(Project::getNewest, Boolean.TRUE)
                .like(StringUtils.isNotBlank(req.getBuildOrgName()), Project::getBuildOrgName, req.getBuildOrgName())
                .like(StringUtils.isNotBlank(req.getProjectName()), Project::getProjectName, req.getProjectName());
        projectService.page(page, wrapper);

        if (CollUtil.isEmpty(page.getRecords())) {
            return PageVo.empty();
        }

        List<PerformanceAppraisalProjectVO> res = page.getRecords().stream().map(p -> {
            PerformanceAppraisalProjectVO vo = BeanUtil.copyProperties(p, PerformanceAppraisalProjectVO.class);
            PerformanceAppraisalProject appraisalProject = papsMap.get(p.getId());
            BeanUtil.copyProperties(appraisalProject, vo);
            vo.setProjectId(appraisalProject.getProjectId());
            vo.setProjectCode(appraisalProject.getProjectCode());
            vo.setProjectTypeName(ProjectTypeNewEnum.getDesc(p.getProjectType()));
            vo.setAppraisalId(planId);
            vo.setRectifyStatus(appraisalProject.getRectifyStatus());
            vo.setRectifyStatusName(RectifyStatusEnum.getDesc(appraisalProject.getRectifyStatus()));
            vo.setGroupId(projectGroup.getId());
            return vo;
        }).collect(Collectors.toList());

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

    public PageVo<PerformanceAppraisalProjectVO> auditedList(Long planId, PerformanceAppraisalListReq req) {
        UserInfoDetails user = LoginUserUtil.loginUserDetail();
        String employeeCode = user.getEmployeeCode();

        PerformanceAppraisal plan = performanceAppraisalService.getById(planId);
        VUtils.isTrue(Objects.isNull(plan)).throwMessage("该评价计划不存在!");

        // 因为一个核查用户只能出现在一个评价计划中的一个分组中，所以根据评价计划ID和核查组长信息可以确定分组内项目信息
        PerformanceAppraisalProjectGroup projectGroup =
                groupService.getOne(Wrappers.lambdaQuery(PerformanceAppraisalProjectGroup.class)
                        .eq(PerformanceAppraisalProjectGroup::getAppraisalId, planId)
                        .eq(PerformanceAppraisalProjectGroup::getVerifyLeader, employeeCode));
        // 当前登录专家没有为核查组长的绩效分组信息
        if (Objects.isNull(projectGroup)) {
            return PageVo.empty();
        }

        String groupProjectCodes = projectGroup.getProjectCodes();
        List<String> codes = Lists.newArrayList();
        if (groupProjectCodes.contains(StrPool.COMMA)) {
            codes.addAll(Arrays.asList(groupProjectCodes.split(StrPool.COMMA)));
        } else {
            codes.add(groupProjectCodes);
        }
        // 获取评价计划内已添加的核查组长为当前登录专家用户的已整改审核项目信息
        List<
                PerformanceAppraisalProject> paps =
                performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                        .eq(PerformanceAppraisalProject::getAppraisalId, plan.getId())
                        .in(PerformanceAppraisalProject::getProjectCode, codes)
                        .eq(PerformanceAppraisalProject::getIsRectify, Boolean.TRUE)
                        .and(wp -> wp
                                .eq(PerformanceAppraisalProject::getRectifyStatus, RectifyStatusEnum.NOT_APPROVED.getCode())
                                .or().eq(PerformanceAppraisalProject::getRectifyStatus, RectifyStatusEnum.APPROVED.getCode())));
        if (CollUtil.isEmpty(paps)) {
            return PageVo.empty();
        }
        Map<Long, PerformanceAppraisalProject> papsMap =
                paps.stream().collect(Collectors.toMap(PerformanceAppraisalProject::getProjectId, p -> p));

        // 获取评价计划内的项目
        Set<String> projectCodes =
                paps.stream().map(PerformanceAppraisalProject::getProjectCode).collect(Collectors.toSet());
        Page<Project> page = req.page();
        LambdaQueryWrapper<Project> wrapper = Wrappers.lambdaQuery(Project.class)
                .in(Project::getProjectCode, projectCodes).eq(Project::getNewest, Boolean.TRUE)
                .like(StringUtils.isNotBlank(req.getBuildOrgName()), Project::getBuildOrgName, req.getBuildOrgName())
                .like(StringUtils.isNotBlank(req.getProjectName()), Project::getProjectName, req.getProjectName());
        projectService.page(page, wrapper);

        if (CollUtil.isEmpty(page.getRecords())) {
            return PageVo.empty();
        }

        List<PerformanceAppraisalProjectVO> res = page.getRecords().stream().map(p -> {
            PerformanceAppraisalProjectVO vo = BeanUtil.copyProperties(p, PerformanceAppraisalProjectVO.class);
            PerformanceAppraisalProject appraisalProject = papsMap.get(p.getId());
            BeanUtil.copyProperties(appraisalProject, vo);
            vo.setProjectId(appraisalProject.getProjectId());
            vo.setProjectCode(appraisalProject.getProjectCode());
            vo.setProjectTypeName(ProjectTypeNewEnum.getDesc(p.getProjectType()));
            vo.setAppraisalId(planId);
            vo.setRectifyStatus(appraisalProject.getRectifyStatus());
            vo.setRectifyStatusName(RectifyStatusEnum.getDesc(appraisalProject.getRectifyStatus()));
            vo.setGroupId(projectGroup.getId());
            return vo;
        }).collect(Collectors.toList());

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

    @Transactional(rollbackFor = Exception.class)
    public String submit(ProjectAppraisalDTO param) {
        UserInfoDetails userDetail = LoginUserUtil.loginUserDetail();
        String userIdStr = String.valueOf(userDetail.getUserId());
        String username = userDetail.getUsername();
        Long appraisalId = param.getAppraisalId();
        Long appraisalProjectId = param.getAppraisalProjectId();
        String appraisalProjectCode = param.getAppraisalProjectCode();
        Integer rectifyAuditResult = param.getRectifyAuditResult();
        String rectifyAuditOpinion = param.getRectifyAuditOpinion();
        String rectifyAuditAppendix = param.getRectifyAuditAppendix();
        List<ProjectAppraisalInfoDTO> appraisalInfoList = param.getAppraisalInfoList();

        // 获取评价项目
        PerformanceAppraisalProject appraisalProject = performanceAppraisalProjectService.getOne(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                .eq(PerformanceAppraisalProject::getAppraisalId, appraisalId)
                .eq(PerformanceAppraisalProject::getProjectCode, appraisalProjectCode)
                .eq(PerformanceAppraisalProject::getProjectId, appraisalProjectId));

        List<Long> ids = appraisalInfoList.stream()
                .map(ProjectAppraisalInfoDTO::getProjectTemplateDetailId)
                .collect(Collectors.toList());
        // 查出项目模版详情信息
        List<PerformanceIndicatorProjectTemplateDetail> detailList = indicatorProjectTemplateDetailService.list(Wrappers.lambdaQuery(PerformanceIndicatorProjectTemplateDetail.class)
                .in(PerformanceIndicatorProjectTemplateDetail::getId, ids));
        if (CollUtil.isEmpty(detailList)) {
            throw new BizException("评价指标不存在!");
        }
        Map<Long, PerformanceIndicatorProjectTemplateDetail> detailMap = detailList.stream().collect(Collectors.toMap(PerformanceIndicatorProjectTemplateDetail::getId, d -> d));
        List<PerformanceAppraisalScoreInfo> scoreInfos = appraisalInfoList.stream().map(a -> {
            PerformanceIndicatorProjectTemplateDetail templateDetail = detailMap.get(a.getProjectTemplateDetailId());
            BigDecimal score = a.getScore();
            BigDecimal indexScore = templateDetail.getIndexScore();
            if (score.compareTo(indexScore) > 0 || score.compareTo(BigDecimal.ZERO) < 0) {
                throw new BizException("核查审核得分必须大于等于0且小于等于指标分值!");
            }
            // 保存核查分数信息
            PerformanceAppraisalScoreInfo scoreInfo = new PerformanceAppraisalScoreInfo();
            scoreInfo.setAppraisalBasis(a.getAppraisalBasis());
            scoreInfo.setAppraisalScore(a.getScore());
            scoreInfo.setAppraisalBasisAppendix(a.getAppraisalBasisAppendix());
            scoreInfo.setAppraisalType(AppraisalTypeEnum.EXPERT_RECTIFY_AUDIT.getCode());
            scoreInfo.setTemplateDetailId(templateDetail.getId());
            scoreInfo.setTemplateId(templateDetail.getTemplateId());
            scoreInfo.setAppraisalUserId(userIdStr);
            scoreInfo.setAppraisalUserName(username);
            scoreInfo.setAppraisalId(appraisalId);
            scoreInfo.setAppraisalProjectId(appraisalProjectId);
            scoreInfo.setAppraisalProjectCode(appraisalProjectCode);
            scoreInfo.setCreateOn(LocalDateTime.now());
            scoreInfo.setCreateBy(username);
            return scoreInfo;
        }).collect(Collectors.toList());

        if (performanceAppraisalScoreInfoService.saveBatch(scoreInfos)) {
            // 计算核查总分并保存
            BigDecimal rectifyTotalScore = appraisalInfoList.stream()
                    .map(ProjectAppraisalInfoDTO::getScore)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            // 保存整改审核相关信息
            appraisalProject.setRectifyTotalScore(rectifyTotalScore);
            appraisalProject.setRectifyScoreTime(LocalDateTime.now());
            appraisalProject.setUpdateOn(LocalDateTime.now());
            appraisalProject.setUpdateBy(username);
            appraisalProject.setRectifyAuditResult(rectifyAuditResult);
            appraisalProject.setRectifyAuditOpinion(rectifyAuditOpinion);
            appraisalProject.setRectifyAuditAppendix(rectifyAuditAppendix);
            if (RectifyAuditEnum.APPROVED.getCode().equals(rectifyAuditResult)) {
                appraisalProject.setRectifyStatus(RectifyStatusEnum.APPROVED.getCode());
            } else if (RectifyAuditEnum.NOT_APPROVED.getCode().equals(rectifyAuditResult)) {
                appraisalProject.setRectifyStatus(RectifyStatusEnum.NOT_APPROVED.getCode());
            }
            performanceAppraisalProjectService.updateById(appraisalProject);
            return "提交成功";
        }
        return "提交失败";
    }
}
