package com.xinyilu.system.service.kindergartenSideAnalysis.impl;

import com.xinyilu.common.constant.Constants;
import com.xinyilu.common.core.domain.AjaxResult;
import com.xinyilu.common.enums.ItemCodeEnums;
import com.xinyilu.common.utils.AgeUtil;
import com.xinyilu.system.domain.vo.kindergartenSideAnalysis.KindergartenSideAnalysisVO;
import com.xinyilu.system.domain.vo.kindergartenSideAnalysis.KindergartenTestItemVO;
import com.xinyilu.system.mapper.kindergarteninfo.KindergartenInfoMapper;
import com.xinyilu.system.service.kindergartenSideAnalysis.KindergartenSideAnalysisService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description 幼儿园体侧项目各年龄段人数分布以及达标率业务层实现类
 * @Author 纪寒
 * @Date 2022-08-13 15:16:56
 * @Version 1.0
 */
@Service
public class KindergartenSideAnalysisServiceImpl implements KindergartenSideAnalysisService {

    @Resource
    private KindergartenInfoMapper kindergartenInfoMapper;

    /**
     * 三岁年龄值
     */
    private static final double THREE_AGE = 3;
    /**
     * 四岁年龄值
     */
    private static final double FOUR_AGE = 4;
    /**
     * 五岁年龄值
     */
    private static final double FIVE_AGE = 5;

    /**
     * 六岁年龄值
     */
    private static final double SIX_AGE = 6;
    /**
     * 二十分标识
     */
    private static final BigDecimal TWENTY_SCORE = BigDecimal.valueOf(20);

    /**
     * 二十七分标识
     */
    private static final BigDecimal TWENTY_SEVEN_SCORE = BigDecimal.valueOf(27);

    /**
     * 三十一分标识
     */
    private static final BigDecimal THIRTY_ONE_SCORE = BigDecimal.valueOf(31);


    /**
     * 六十分标识
     */
    private static final BigDecimal SIXTY_SCORE = BigDecimal.valueOf(60);

    /**
     * 八十分标识
     */
    private static final BigDecimal EIGHTY_SCORE = BigDecimal.valueOf(80);

    /**
     * 国民体质八项（立定跳远）
     */
    private static final long NATIONAL_PHYSIQUE_ONE = 1L;

    /**
     * 国民体质八项（双脚连续跳）
     */
    private static final long NATIONAL_PHYSIQUE_TWO = 2L;

    /**
     * 国民体质八项（网球掷远）
     */
    private static final long NATIONAL_PHYSIQUE_THREE = 3L;

    /**
     * 国民体质八项（走平衡木）
     */
    private static final long NATIONAL_PHYSIQUE_FOUR = 4L;

    /**
     * 国民体质八项（坐位体前屈）
     */
    private static final long NATIONAL_PHYSIQUE_FIVE = 5L;

    /**
     * 国民体质八项（10米折返跑）
     */
    private static final long NATIONAL_PHYSIQUE_SIX = 6L;

    /**
     * 国民体质八项（身高）
     */
    private static final long NATIONAL_PHYSIQUE_NINETEEN = 19L;

    /**
     * 国民体质八项（体重）
     */
    private static final long NATIONAL_PHYSIQUE_TWENTY = 20L;


    /**
     * 查询幼儿园下测试项目某个批次的数据分析信息
     *
     * @param kindergartenId 幼儿园id
     * @param batchCode      批次号
     * @return 数据分析
     * @throws Exception 异常信息
     */
    @Override
    public AjaxResult getKindergartenSideAnalysisInfo(Long kindergartenId, String batchCode) throws Exception {
        List<Long> nationalPhysiqueList = Arrays.asList(NATIONAL_PHYSIQUE_ONE, NATIONAL_PHYSIQUE_TWO, NATIONAL_PHYSIQUE_THREE, NATIONAL_PHYSIQUE_FOUR, NATIONAL_PHYSIQUE_FIVE, NATIONAL_PHYSIQUE_SIX, NATIONAL_PHYSIQUE_NINETEEN, NATIONAL_PHYSIQUE_TWENTY);
        List<KindergartenTestItemVO> testItemList = kindergartenInfoMapper.getTestItemList(kindergartenId, batchCode, nationalPhysiqueList, ItemCodeEnums.BMI_CODE.getInfo());
        //查询某个幼儿园下的某个测试项目所有学生的成绩信息以及其幼儿园信息
        List<KindergartenSideAnalysisVO> sideAnalysisList = kindergartenInfoMapper.getKindergartenSideAnalysis(kindergartenId, batchCode);
        if (CollectionUtils.isEmpty(sideAnalysisList)) {
            return AjaxResult.success();
        }
        KindergartenSideAnalysisVO sideAnalysisVO = new KindergartenSideAnalysisVO();
        //幼儿园信息
        sideAnalysisVO.setKindergartenName(StringUtils.isBlank(sideAnalysisList.get(0).getKindergartenName()) ? "" : sideAnalysisList.get(0).getKindergartenName());
        sideAnalysisVO.setKindergartenType(StringUtils.isBlank(sideAnalysisList.get(0).getKindergartenType()) ? "" : sideAnalysisList.get(0).getKindergartenType());
        int totalCount = sideAnalysisList.size();
        sideAnalysisVO.setTestItemStudentCount(totalCount);
        //计算学生的年龄
        for (KindergartenSideAnalysisVO analysisVO : sideAnalysisList) {
            analysisVO.setStudentAge(AgeUtil.getStudentAgeMonth(Objects.isNull(analysisVO.getBirthDate()) ? LocalDate.now().toString() : analysisVO.getBirthDate().toString()));
        }
        //计算年龄为三岁和四岁的男性学生的人数
        double threeAndFourMaleCount = getStudentAgeCount(sideAnalysisList, Constants.MALE, THREE_AGE, FOUR_AGE);
        sideAnalysisVO.setThreeAndFourMaleCount(threeAndFourMaleCount);
        //计算年龄为三岁和四岁的女性学生的人数
        double threeAndFourFeMaleCount = getStudentAgeCount(sideAnalysisList, Constants.FEMALE, THREE_AGE, FOUR_AGE);
        sideAnalysisVO.setThreeAndFourFeMaleCount(threeAndFourFeMaleCount);
        //计算年龄为四岁和五岁的男性学生的人数
        double fourAndFiveMaleCount = getStudentAgeCount(sideAnalysisList, Constants.MALE, FOUR_AGE, FIVE_AGE);
        sideAnalysisVO.setFourAndFiveMaleCount(fourAndFiveMaleCount);
        //计算年龄为四岁和五岁的女性学生的人数
        double fourAndFiveFeMaleCount = getStudentAgeCount(sideAnalysisList, Constants.FEMALE, FOUR_AGE, FIVE_AGE);
        sideAnalysisVO.setFourAndFiveFeMaleCount(fourAndFiveFeMaleCount);
        //计算年龄为五岁和六岁的男性学生的人数
        double fiveAndSixMaleCount = getStudentAgeCount(sideAnalysisList, Constants.MALE, FIVE_AGE, SIX_AGE);
        sideAnalysisVO.setFiveAndSixMaleCount(fiveAndSixMaleCount);
        //计算年龄为五岁和六岁的女性学生的人数
        double fiveAndSixFeMaleCount = getStudentAgeCount(sideAnalysisList, Constants.FEMALE, FIVE_AGE, SIX_AGE);
        sideAnalysisVO.setFiveAndSixFeMaleCount(fiveAndSixFeMaleCount);
        //计算年龄为六岁以上的男性学生的人数
        double sixAndMoreMaleCount = getGreaterThanStudentAgeCount(sideAnalysisList, Constants.MALE);
        sideAnalysisVO.setSixAndMoreMaleCount(sixAndMoreMaleCount);
        //计算六岁以上的女性学生的人数
        double sixAndMoreFeMaleCount = getGreaterThanStudentAgeCount(sideAnalysisList, Constants.FEMALE);
        sideAnalysisVO.setSixAndMoreFeMaleCount(sixAndMoreFeMaleCount);
        //达标率计算
        if (CollectionUtils.isNotEmpty(testItemList)) {
            getTestItemList(testItemList, sideAnalysisVO, totalCount);
        }
        return AjaxResult.success(sideAnalysisVO);
    }


    /**
     * 计算不同年龄段的学生的数量
     *
     * @param sideAnalysisList 学生信息集合
     * @param startYear        开始年龄
     * @param endYear          结束年龄
     * @param studentSex       学生性别
     * @return 学生数量
     */
    private double getStudentAgeCount(List<KindergartenSideAnalysisVO> sideAnalysisList, String studentSex,
                                      double startYear, double endYear) {
        return sideAnalysisList.stream()
                .filter(item -> Objects.nonNull(item.getStudentAge()) && StringUtils.isNotBlank(item.getStudentSex()))
                .filter(item -> studentSex.equals(item.getStudentSex()))
                .filter(item -> item.getStudentAge() >= startYear && item.getStudentAge() < endYear).count();
    }

    /**
     * 计算大于年龄段的学生的数量
     *
     * @param sideAnalysisList 学生信息集合
     * @param studentSex       学生性别
     * @return 学生数量
     */
    private double getGreaterThanStudentAgeCount(List<KindergartenSideAnalysisVO> sideAnalysisList,
                                                 String studentSex) {
        return sideAnalysisList.stream()
                .filter(item -> Objects.nonNull(item.getStudentAge()) && StringUtils.isNotBlank(item.getStudentSex()))
                .filter(item -> studentSex.equals(item.getStudentSex()))
                .filter(item -> item.getStudentAge() >= KindergartenSideAnalysisServiceImpl.SIX_AGE).count();
    }

    /**
     * 得到测试项目列表
     *
     * @param testItemList   测试项目列表
     * @param sideAnalysisVO 幼儿园体侧项目各年龄段人数分布以及达标率返回值实体类
     * @param totalCount     总人数
     */
    private void getTestItemList(List<KindergartenTestItemVO> testItemList, KindergartenSideAnalysisVO sideAnalysisVO, int totalCount) {
        Map<Long, List<KindergartenTestItemVO>> studentIdMp = testItemList.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getStudentId())).collect(Collectors.groupingBy(KindergartenTestItemVO::getStudentId));
        studentIdMp.forEach((studentId, kindergartenTestItem) -> {
            KindergartenTestItemVO kindergartenTestItemVO = kindergartenTestItem.get(0);
            //每个素质的总分数
            BigDecimal testItemSumScore = kindergartenTestItem.stream().filter(item -> Objects.nonNull(item.getAvgScore()))
                    .map(KindergartenTestItemVO::getAvgScore)
                    .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP);
            kindergartenTestItemVO.setSumScore(testItemSumScore);
        });
        //小于二十分的人  20<
        long twentyCount = testItemList.stream().filter(score -> Objects.nonNull(score.getSumScore()))
                .filter(score -> score.getSumScore().compareTo(TWENTY_SCORE) < 0).count();
        sideAnalysisVO.setTwentyCount(twentyCount);
        //大于二十分的小于二十七的人 20 - 27
        long twentyScoreCount = testItemList.stream().filter(score -> Objects.nonNull(score.getSumScore()))
                .filter(score -> score.getSumScore().compareTo(TWENTY_SEVEN_SCORE) <= 0 && score.getSumScore().compareTo(TWENTY_SCORE) >= 0).count();
        sideAnalysisVO.setTwentyScoreCount(twentyScoreCount);
        //大于二十七分的小于三十一的人 27 - 31
        long twentySevenScoreCount = testItemList.stream().filter(score -> Objects.nonNull(score.getSumScore()))
                .filter(score -> score.getSumScore().compareTo(THIRTY_ONE_SCORE) <= 0 && score.getSumScore().compareTo(TWENTY_SEVEN_SCORE) > 0).count();
        sideAnalysisVO.setTwentySevenScoreCount(twentySevenScoreCount);
        //大于三十一分的人  >31
        long thirtyOneScoreCount = testItemList.stream().filter(score -> Objects.nonNull(score.getSumScore()))
                .filter(score -> score.getSumScore().compareTo(THIRTY_ONE_SCORE) > 0).count();
        sideAnalysisVO.setThirtyOneScoreCount(thirtyOneScoreCount);
        //达标率
        BigDecimal itemStandardScore = BigDecimal.valueOf(totalCount-twentyCount).divide(BigDecimal.valueOf(totalCount), 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100).setScale(2, BigDecimal.ROUND_HALF_UP));
        sideAnalysisVO.setStandardRate(Objects.isNull(itemStandardScore) ? BigDecimal.ZERO : itemStandardScore);
    }

}
