package com.ningdatech.pmapi.performance.manage;

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

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

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.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.StrPool;
import com.ningdatech.pmapi.performance.constant.BizConst;
import com.ningdatech.pmapi.performance.enumration.AppraisalTypeEnum;
import com.ningdatech.pmapi.performance.model.dto.ProjectAppraisalDTO;
import com.ningdatech.pmapi.performance.model.dto.ProjectAppraisalInfoDTO;
import com.ningdatech.pmapi.performance.model.entity.*;
import com.ningdatech.pmapi.performance.model.req.PerformanceAppraisalListReq;
import com.ningdatech.pmapi.performance.model.vo.PerformanceAppraisalProjectVO;
import com.ningdatech.pmapi.performance.model.vo.PerformanceAppraisalVO;
import com.ningdatech.pmapi.performance.service.*;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectTypeEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.sys.model.entity.Role;
import com.ningdatech.pmapi.sys.service.IRoleService;
import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.pmapi.user.util.LoginUserUtil;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * ReAppraisalManage
 * @return
 * @author CMM
 * @since 2023/08/10 8:55
 */
@Component
@Slf4j
@AllArgsConstructor
public class ReAppraisalManage {

    private final IPerformanceAppraisalService performanceAppraisalService;
    private final IPerformanceAppraisalProjectService performanceAppraisalProjectService;
    private final IProjectService projectService;
    private final IRoleService roleService;
    private final IPerformanceIndicatorProjectTemplateDetailService indicatorProjectTemplateDetailService;
    private final IPerformanceAppraisalScoreInfoService performanceAppraisalScoreInfoService;
    private final IPerformanceAppraisalProjectGroupService groupService;
    /**
     * 复评-评价计划列表
     * @param req
     * @return
     */
    public PageVo<PerformanceAppraisalVO> list(PerformanceAppraisalListReq req) {
        UserInfoDetails user = LoginUserUtil.loginUserDetail();
        String employeeCode = user.getEmployeeCode();
        //当前登录用户 单位code
        String empPosUnitCode = user.getEmpPosUnitCode();
        // 获取当前登录用户的角色列表，只有绩效复评人员才能查看该列表
        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, BizConst.REAPPRAISAL_ROLE));
        if (Objects.isNull(role)){
            throw new BizException("登录用户没有复评员角色!");
        }

        // 登录用户不是复评员，不能查看复评计划列表
        if (!roleIdList.contains(role.getId())){
            return PageVo.empty();
        }

        // 从绩效评价 项目表中获取已经完成单位自评的项目
        List<PerformanceAppraisalProject> paps = performanceAppraisalProjectService.list().stream()
                .filter(p -> Objects.nonNull(p.getSelfAppraisalScoreTime())).collect(Collectors.toList());

        // 已存在的评价计划添加的评价项目都未完成单位自评
        if(CollUtil.isEmpty(paps)){
            return PageVo.empty();
        }
        Set<Long> paIds = paps.stream().map(PerformanceAppraisalProject::getAppraisalId).collect(Collectors.toSet());

        // 获取评价计划关联的分组信息
        List<PerformanceAppraisalProjectGroup> groups = groupService.list(Wrappers.lambdaQuery(PerformanceAppraisalProjectGroup.class)
                .in(PerformanceAppraisalProjectGroup::getAppraisalId, paIds));
        // 获取当前登录复评员所在的分组信息
        List<PerformanceAppraisalProjectGroup> groupList = groups.stream().filter(g -> {
            String reAppraisalUsers = g.getReAppraisalUsers();
            List<String> empCodeList = Arrays.stream(reAppraisalUsers.split(StrPool.COMMA)).collect(Collectors.toList());
            if (empCodeList.contains(employeeCode)) {
                return true;
            }
            return false;
        }).collect(Collectors.toList());
        // 当前登录复评员用户，没有参加评价计划
        if (CollUtil.isEmpty(groupList)){
            return PageVo.empty();
        }
        // 获取分组所在的评价计划ID
        List<Long> appraisalIds = groupList.stream().map(PerformanceAppraisalProjectGroup::getAppraisalId).collect(Collectors.toList());
        // 因为同一个复评员只能出现在一个计划的一个分组中，所以分组信息可按照评价计划ID进行分组
        Map<Long, PerformanceAppraisalProjectGroup> groupMap = groupList.stream().collect(Collectors.toMap(PerformanceAppraisalProjectGroup::getAppraisalId, g -> g));
        // 获取复评计划列表
        Page<PerformanceAppraisal> page = req.page();
        LambdaQueryWrapper<PerformanceAppraisal> wrapper = Wrappers.lambdaQuery(PerformanceAppraisal.class)
                .in(PerformanceAppraisal::getId,appraisalIds)
                .orderByDesc(PerformanceAppraisal::getUpdateOn);
        performanceAppraisalService.page(page,wrapper);

        List<PerformanceAppraisalVO> res = page.getRecords().stream().map(p -> {
            PerformanceAppraisalVO vo = BeanUtil.copyProperties(p, PerformanceAppraisalVO.class);
            PerformanceAppraisalProjectGroup group = groupMap.get(p.getId());
            if (Objects.nonNull(group)) {
                vo.setReAppraisalGroupId(group.getId());
                vo.setReAppraisalGroupName(group.getName());
            }
            return vo;
        }).collect(Collectors.toList());
        return PageVo.of(res,page.getTotal());
    }

    /**
     * 是否可以复评
     *
     * @param employeeCode
     * @param projectCode
     * @param appraisalId
     * @return
     */
    private Boolean checkCanReAppraisal(String employeeCode, String projectCode, Long appraisalId) {
        // 首次复评(复评打分时间为空)
        // 从绩效评价打分信息表中查询打分类型为复评、打分人员为当前登录复评用户的打分信息
        // 如果没有相关的打分信息，说明是当前登录复评用户是首次复评
        List<PerformanceAppraisalScoreInfo> scoreInfos = performanceAppraisalScoreInfoService.list(Wrappers.lambdaQuery(PerformanceAppraisalScoreInfo.class)
                .eq(PerformanceAppraisalScoreInfo::getAppraisalType, AppraisalTypeEnum.RE_APPRAISAL.getCode())
                .eq(PerformanceAppraisalScoreInfo::getAppraisalProjectCode,projectCode)
                .eq(PerformanceAppraisalScoreInfo::getAppraisalId,appraisalId)
                .eq(PerformanceAppraisalScoreInfo::getAppraisalEmployeeCode, employeeCode));
        if (CollUtil.isEmpty(scoreInfos)){
            return true;
        }
        return Boolean.FALSE;
    }

    public PageVo<PerformanceAppraisalProjectVO> groupProjectList(Long groupId, PerformanceAppraisalListReq req) {

        UserInfoDetails userDetail = LoginUserUtil.loginUserDetail();
        String employeeCode = userDetail.getEmployeeCode();

        // 获取分组内的项目信息
        PerformanceAppraisalProjectGroup projectGroup = groupService.getById(groupId);
        String projectCodes = projectGroup.getProjectCodes();
        Long appraisalId = projectGroup.getAppraisalId();
        VUtils.isTrue(StringUtils.isBlank(projectCodes)).throwMessage("分组内项目信息不存在!");
        List<String> projectCodeList = Arrays.stream(projectCodes.split(StrPool.COMMA)).collect(Collectors.toList());

        // 筛选出分组内已完成单位自评、需要复评的评价项目信息
        List<PerformanceAppraisalProject> appraisalProjects = performanceAppraisalProjectService.list(Wrappers.lambdaQuery(PerformanceAppraisalProject.class)
                .in(PerformanceAppraisalProject::getProjectCode, projectCodeList)
                .eq(PerformanceAppraisalProject::getIsReAppraisal,Boolean.TRUE)
                .eq(PerformanceAppraisalProject::getIsCompleteSelfAppraisal, Boolean.TRUE));
        // 分组内已完成单位自评的项目信息不存在
        if (CollUtil.isEmpty(appraisalProjects)){
            return PageVo.empty();
        }
        List<String> proCodeList = appraisalProjects.stream().map(PerformanceAppraisalProject::getProjectCode).collect(Collectors.toList());
        Map<String, PerformanceAppraisalProject> appraisalProjectMap = appraisalProjects.stream().collect(Collectors.toMap(PerformanceAppraisalProject::getProjectCode, p -> p));

        Page<Project> page = req.page();
        LambdaQueryWrapper<Project> wrapper = Wrappers.lambdaQuery(Project.class)
                .in(Project::getProjectCode, proCodeList)
                .eq(Project::getNewest, Boolean.TRUE)
                .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 = appraisalProjectMap.get(p.getProjectCode());
                    BeanUtil.copyProperties(appraisalProject, vo);
                    vo.setProjectId(appraisalProject.getProjectId());
                    vo.setProjectTypeName(ProjectTypeEnum.getDesc(p.getProjectType()));
                    vo.setCanReAppraisal(checkCanReAppraisal(employeeCode,appraisalProject.getProjectCode(),appraisalId));
                    if (Boolean.TRUE.equals(appraisalProject.getIsCompleteReAppraisal())){
                        // 完成复评的项目可以进行核查
                        vo.setCanVerify(Boolean.TRUE);
                    }
                    vo.setGroupId(groupId);
                    return vo;
                })
                .collect(Collectors.toList());
        return PageVo.of(res,page.getTotal());
    }

    @Transactional(rollbackFor = Exception.class)
    public String submitReAppraisal(ProjectAppraisalDTO param) {
        UserInfoDetails userDetail = LoginUserUtil.loginUserDetail();
        String employeeCode = userDetail.getEmployeeCode();
        String username = userDetail.getUsername();
        Long appraisalId = param.getAppraisalId();
        Long appraisalProjectId = param.getAppraisalProjectId();
        String appraisalProjectCode = param.getAppraisalProjectCode();
        List<ProjectAppraisalInfoDTO> appraisalInfoList = param.getAppraisalInfoList();
        Long groupId = param.getGroupId();
        PerformanceAppraisalProjectGroup group = groupService.getById(groupId);

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

        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.RE_APPRAISAL.getCode());
            scoreInfo.setTemplateDetailId(templateDetail.getId());
            scoreInfo.setTemplateId(templateDetail.getTemplateId());
            scoreInfo.setAppraisalEmployeeCode(employeeCode);
            scoreInfo.setAppraisalEmployeeName(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 reAppraisalTotalScore = appraisalInfoList.stream()
                    .map(ProjectAppraisalInfoDTO::getScore)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal lastReappraisalTotalScore;
            // 判断项目所在分组内其他复评人员是否已经打分
            if (Objects.nonNull(appraisalProject.getReAppraisalTotalScore())){
                // 已经进行了复评，计算两个分值的平均分
                BigDecimal add = reAppraisalTotalScore.add(appraisalProject.getReAppraisalTotalScore());
                lastReappraisalTotalScore = add.divide(BigDecimal.valueOf(2));
            }else {
                // 还没有进行过复评
                lastReappraisalTotalScore = reAppraisalTotalScore;
            }
            appraisalProject.setReAppraisalTotalScore(lastReappraisalTotalScore);
            // 取最新地复评打分时间
            appraisalProject.setReAppraisalScoreTime(LocalDateTime.now());
            // 判断当前复评人是否为该评价项目所在分组的复评人员中的最后一个复评人
            judgeCompleteReAppraisal(group, appraisalProject);
            appraisalProject.setUpdateOn(LocalDateTime.now());
            appraisalProject.setUpdateBy(username);
            performanceAppraisalProjectService.updateById(appraisalProject);
            return "提交成功";
        }
        return "提交失败";
    }

    private void judgeCompleteReAppraisal(PerformanceAppraisalProjectGroup group, PerformanceAppraisalProject appraisalProject) {
        Map<String, List<PerformanceAppraisalScoreInfo>> scoreInfoMap = performanceAppraisalScoreInfoService.list(Wrappers.lambdaQuery(PerformanceAppraisalScoreInfo.class)
                        .eq(PerformanceAppraisalScoreInfo::getAppraisalType, AppraisalTypeEnum.RE_APPRAISAL.getCode()))
                .stream().collect(Collectors.groupingBy(PerformanceAppraisalScoreInfo::getAppraisalEmployeeCode));

        List<String> reUsers = Lists.newArrayList();
        String reAppraisalUsers = group.getReAppraisalUsers();
        String projectCodes = group.getProjectCodes();
        if (reAppraisalUsers.contains(StrPool.COMMA)){
            reUsers = Arrays.asList(reAppraisalUsers.split(StrPool.COMMA));
        }else {
            reUsers.add(reAppraisalUsers);
        }
        List<String> users = Lists.newArrayList();
        for (String reUser : reUsers) {
            // 获取分组内复评人员对分组内项目的复评分数信息
            List<PerformanceAppraisalScoreInfo> scoreInfoList = scoreInfoMap.get(reUser);
            if (CollUtil.isNotEmpty(scoreInfoList)){
                List<Long> projectIdList = scoreInfoList.stream()
                        .map(PerformanceAppraisalScoreInfo::getAppraisalProjectId)
                        .collect(Collectors.toList());
                List<String> proCodes = projectService.listByIds(projectIdList).stream()
                        .map(Project::getProjectCode)
                        .collect(Collectors.toList());
                // 当前登录用户所在分组的复评人员 对分组内所有项目进行了复评
                if (CollUtil.isNotEmpty(proCodes)){
                    String join = String.join(StrPool.COMMA, proCodes);
                    if (join.equals(projectCodes)) {
                        users.add(reUser);
                    }
                }
            }
        }
        if (CollUtil.isNotEmpty(users)) {
            String join = String.join(StrPool.COMMA, users);
            if (join.equals(reAppraisalUsers)) {
                // 标记项目完成复评
                appraisalProject.setIsCompleteReAppraisal(Boolean.TRUE);
            }
        }
    }
}
