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

import com.xinyilu.common.constant.Constants;
import com.xinyilu.common.enums.ItemCodeEnums;
import com.xinyilu.common.utils.AgeUtil;
import com.xinyilu.common.utils.BigDecimalUtil;
import com.xinyilu.system.domain.systemarea.SysArea;
import com.xinyilu.system.domain.testLevel.TestItemLevel;
import com.xinyilu.system.domain.vo.TestItemAvgScoreVO;
import com.xinyilu.system.domain.vo.kinderPhysiqueAnalysis.*;
import com.xinyilu.system.domain.vo.physicalActionAnalysis.ItemFractionInfo;
import com.xinyilu.system.domain.vo.physicalActionAnalysis.PhysicalActionAnalysisVO;
import com.xinyilu.system.domain.vo.physicalActionAnalysis.PhysicalActionVO;
import com.xinyilu.system.domain.vo.testItemAvgScore.ClassAvgCategoryScoreVO;
import com.xinyilu.system.domain.vo.testItemAvgScore.TestItemAvgScoreClassVO;
import com.xinyilu.system.mapper.kindergarteninfo.KindergartenInfoMapper;
import com.xinyilu.system.mapper.studentInfo.StudentInfoMapper;
import com.xinyilu.system.mapper.systemarea.SysAreaMapper;
import com.xinyilu.system.mapper.testItem.TestItemsMapper;
import com.xinyilu.system.mapper.testItemScoreinfo.TestItemScoreMapper;
import com.xinyilu.system.service.checkreport.KindergartenShapeAnalysiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 幼儿园综合体质分析
 *
 * @author wanghao
 * @create 2022/9/29 0029
 */
@Service
@Slf4j
public class KindergartenShapeAnalysiServiceImpl implements KindergartenShapeAnalysiService {

    @Resource
    private KindergartenInfoMapper kindergartenInfoMapper;
    @Resource
    private StudentInfoMapper studentInfoMapper;
    @Resource
    private TestItemsMapper testItemsMapper;
    @Resource
    private TestItemScoreMapper testItemScoreMapper;
    @Resource
    private SysAreaMapper sysAreaMapper;
    /**
     * 男性
     */
    private static final String MALE = "MALE";

    /**
     * 女性
     */
    private static final String FEMALE = "FEMALE";

    /**
     * 获取幼儿园动作发展状况数据
     *
     * @param kindergartenId 幼儿园id
     * @param batchCode      批次编号
     * @param classType      班级类型
     * @return PhysicalActionVO
     */
    @Override
    public PhysicalActionVO getPhysicalActionAnalysis(Long kindergartenId, String classType, String batchCode) {
        //班级类型名称
        String classTypeName = getClassTypeName(classType);
        //查询幼儿园不同班级类型的男女项目的得分信息
        List<PhysicalActionAnalysisVO> itemAvgScoreList = testItemsMapper.getItemAvgScore(kindergartenId, classType, batchCode, ItemCodeEnums.BMI_CODE.getInfo());
        if (CollectionUtils.isEmpty(itemAvgScoreList)) {
            return new PhysicalActionVO();
        }
        //获取项目id
        List<Long> itemIdList = itemAvgScoreList.stream().filter(item -> Objects.nonNull(item.getItemId())).map(PhysicalActionAnalysisVO::getItemId).distinct().collect(Collectors.toList());
        List<PhysicalActionAnalysisVO> dataList = Lists.newArrayList();
        //查询当前幼儿园所属地市下不同班级类型下的男女平均得分信息
        List<Long> areaIdList = this.getSysAreaInfoByKindergartenId(kindergartenId);
        List<PhysicalActionAnalysisVO> cityAvgScoreList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(areaIdList)) {
            //该市下所有的幼儿园id集合
            List<Long> kindergartenIdList = kindergartenInfoMapper.getStudentAndKindergartenCount(areaIdList).stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getKindergartenId())).map(StudentAndKindergartenVO::getKindergartenId).distinct().collect(Collectors.toList());
            cityAvgScoreList = testItemsMapper.getItemCityAvgScore(kindergartenIdList, classType, batchCode, ItemCodeEnums.BMI_CODE.getInfo());
        }
        //计算各项目的平均成绩信息以及全市平均成绩信息
        this.getItemAvgScoreAndAvgCityScore(itemAvgScoreList, cityAvgScoreList, itemIdList, dataList);
        //查询每个项目的得分信息
        Map<Long, List<ItemFractionInfo>> itemFractionMap = testItemsMapper.getItemFractionInfo(kindergartenId, classType, batchCode, itemIdList, ItemCodeEnums.BMI_CODE.getInfo()).stream().filter(item -> Objects.nonNull(item.getItemId())).collect(Collectors.groupingBy(ItemFractionInfo::getItemId));
        //查询每个项目的区间信息
        Map<Long, List<TestItemLevel>> itemLevelMap = testItemsMapper.getTestItemLevelByItemId(itemIdList).stream().filter(item -> Objects.nonNull(item.getItemId())).collect(Collectors.groupingBy(TestItemLevel::getItemId));
        PhysicalActionVO physicalActionVO = new PhysicalActionVO();
        if (itemFractionMap.isEmpty() || itemLevelMap.isEmpty()) {
            physicalActionVO.setClassTypeName(classTypeName);
            physicalActionVO.setPhysicalActionList(dataList);
            return physicalActionVO;
        }
        //循环计算合格人数和合格率
        this.getItemQualifyCount(dataList, itemFractionMap, itemLevelMap);
        physicalActionVO.setClassTypeName(classTypeName);
        physicalActionVO.setPhysicalActionList(dataList);
        return physicalActionVO;
    }

    /**
     * 获取幼儿园班级体质分析
     *
     * @param kindergartenId 幼儿园id
     * @param batchCode      批次编号
     * @param classId        班级id
     * @return ClassAvgCategoryScoreVO
     */
    @Override
    public ClassAvgCategoryScoreVO selectTestItemAvgScoreList(Long classId, Long kindergartenId, String batchCode) {
        List<TestItemAvgScoreVO> dataList = Lists.newArrayList();
        TestItemAvgScoreVO testItemAvgScoreVO = new TestItemAvgScoreVO();
        // 查询每个分类的平均得分
        List<TestItemAvgScoreClassVO> testItemAvgScoreList = testItemScoreMapper.selectTestItemAvgScoreList(classId, kindergartenId, batchCode, ItemCodeEnums.BMI_CODE.getInfo());
        if (CollectionUtils.isEmpty(testItemAvgScoreList)) {
            return new ClassAvgCategoryScoreVO();
        }
        //计算平均总分
        testItemAvgScoreList.forEach(item -> {
            if (Objects.nonNull(item.getAvgScore())) {
                item.setAvgScore(item.getAvgScore().setScale(2, BigDecimal.ROUND_HALF_UP));
            } else {
                item.setAvgScore(BigDecimal.ZERO);
            }
        });
        testItemAvgScoreVO.setClassName(StringUtils.isBlank(testItemAvgScoreList.get(0).getClassName()) ? "" : testItemAvgScoreList.get(0).getClassName());
        testItemAvgScoreVO.setTotalAvScore(testItemAvgScoreList.stream()
                .filter(item -> Objects.nonNull(item.getAvgScore()))
                .map(TestItemAvgScoreClassVO::getAvgScore)
                .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP));
        testItemAvgScoreVO.setCategoryScoreList(testItemAvgScoreList);
        dataList.add(testItemAvgScoreVO);
        //设置班级类型名称
        String classTypeName = this.setClassTypeName(StringUtils.isBlank(testItemAvgScoreList.get(0).getClassType()) ? "" : testItemAvgScoreList.get(0).getClassType());
        //分类id
        List<Long> categoryIdList = testItemAvgScoreList.stream().filter(item -> Objects.nonNull(item.getCategoryId())).map(TestItemAvgScoreClassVO::getCategoryId).distinct().collect(Collectors.toList());
        //查询本园班级平均得分
        this.getKindergartenAvgScore(testItemAvgScoreList, kindergartenId, batchCode, classTypeName, dataList, categoryIdList);
        //查询全市平均得分
        this.getCityAvgScore(kindergartenId, testItemAvgScoreList, classTypeName, batchCode, categoryIdList, dataList);
        //获取表头的信息
        List<CategoryTableName> categoryTableNameList = this.setCategoryTableName(testItemAvgScoreList);
        ClassAvgCategoryScoreVO classAvgCategoryScoreVO = new ClassAvgCategoryScoreVO();
        classAvgCategoryScoreVO.setCategoryTableNameList(categoryTableNameList);
        classAvgCategoryScoreVO.setCategoryScoreList(dataList);
        return classAvgCategoryScoreVO;
    }

    /**
     * 根据本机类型返回班级类型名称
     *
     * @param classType 班级类型
     * @return 班级类型名称
     */
    private String setClassTypeName(String classType) {
        String classTypeName;
        switch (classType) {
            case "LARGE_CLASS":
                classTypeName = "大班";
                break;
            case "MIDDLE_CLASS":
                classTypeName = "中班";
                break;
            case "SMALL_CLASS":
                classTypeName = "小班";
                break;
            default:
                classTypeName = "";
        }
        return classTypeName;
    }

    /**
     * 计算全园平均得分
     *
     * @param testItemAvgScoreList 测试项目分平均得分信息
     * @param kindergartenId       幼儿园id
     * @param batchCode            批次编号
     * @param classTypeName        班级类型名称
     * @param dataList             返回值数据集合
     * @param categoryIdList       分类id集合
     */
    private void getKindergartenAvgScore(List<TestItemAvgScoreClassVO> testItemAvgScoreList, Long kindergartenId, String batchCode,
                                         String classTypeName, List<TestItemAvgScoreVO> dataList, List<Long> categoryIdList) {
        // 查询本园班级平均得分
        List<TestItemAvgScoreClassVO> itemAvgScoreSchoolList = testItemScoreMapper.selectTestItemAvgScoreSchoolList(testItemAvgScoreList.get(0).getClassType(), kindergartenId, batchCode, categoryIdList, ItemCodeEnums.BMI_CODE.getInfo());
        // 得到每个项目的平均分数 进行相加得到 平均分数之和
        if (CollectionUtils.isNotEmpty(itemAvgScoreSchoolList)) {
            TestItemAvgScoreVO kinderClassAvgScoreVO = new TestItemAvgScoreVO();
            itemAvgScoreSchoolList.forEach(item -> {
                if (Objects.nonNull(item.getAvgScore())) {
                    item.setAvgScore(item.getAvgScore().setScale(2, BigDecimal.ROUND_HALF_UP));
                } else {
                    item.setAvgScore(BigDecimal.ZERO);
                }
            });
            kinderClassAvgScoreVO.setClassName("本园" + classTypeName + "平均分");
            kinderClassAvgScoreVO.setTotalAvScore(itemAvgScoreSchoolList.stream()
                    .filter(item -> Objects.nonNull(item.getAvgScore()))
                    .map(TestItemAvgScoreClassVO::getAvgScore)
                    .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP));
            kinderClassAvgScoreVO.setCategoryScoreList(itemAvgScoreSchoolList);
            dataList.add(kinderClassAvgScoreVO);
        } else {
            TestItemAvgScoreVO kinderClassAvgScoreVO = new TestItemAvgScoreVO();
            kinderClassAvgScoreVO.setClassName("本园" + classTypeName + "平均分");
            kinderClassAvgScoreVO.setTotalAvScore(BigDecimal.ZERO);
            kinderClassAvgScoreVO.setCategoryScoreList(Lists.newArrayList());
            dataList.add(kinderClassAvgScoreVO);
        }
    }


    /**
     * 计算全市平均得分
     *
     * @param kindergartenId       幼儿园id
     * @param testItemAvgScoreList 测试项目分类平均成绩信息
     * @param classTypeName        班级类型名称
     * @param batchCode            批次编号
     * @param categoryIdList       分类id集合
     * @param dataList             返回结果集
     */
    private void getCityAvgScore(Long kindergartenId, List<TestItemAvgScoreClassVO> testItemAvgScoreList, String classTypeName,
                                 String batchCode, List<Long> categoryIdList, List<TestItemAvgScoreVO> dataList) {
        List<Long> areaIdList = this.getSysAreaInfoByKindergartenId(kindergartenId);
        List<Long> kindergartenIdList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(areaIdList)) {
            //该市下所有的幼儿园id集合
            kindergartenIdList = kindergartenInfoMapper.getKindergartenIdListByArea(areaIdList);
        }
        // 查出全市平均得分
        List<TestItemAvgScoreClassVO> testItemAvgScoreCityList = testItemScoreMapper.selectTestItemAvgScoreCityList(testItemAvgScoreList.get(0).getClassType(), kindergartenIdList, batchCode, categoryIdList, ItemCodeEnums.BMI_CODE.getInfo());
        // 得到每个项目的平均分数 进行相加得到 平均分数之和
        if (CollectionUtils.isNotEmpty(testItemAvgScoreCityList)) {
            TestItemAvgScoreVO cityClassAvgScoreVO = new TestItemAvgScoreVO();
            testItemAvgScoreCityList.forEach(item -> {
                if (Objects.nonNull(item.getAvgScore())) {
                    item.setAvgScore(item.getAvgScore().setScale(2, BigDecimal.ROUND_HALF_UP));
                } else {
                    item.setAvgScore(BigDecimal.ZERO);
                }
            });
            cityClassAvgScoreVO.setClassName("全市" + classTypeName + "平均分");
            cityClassAvgScoreVO.setTotalAvScore(testItemAvgScoreCityList.stream()
                    .filter(item -> Objects.nonNull(item.getAvgScore()))
                    .map(TestItemAvgScoreClassVO::getAvgScore)
                    .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP));
            cityClassAvgScoreVO.setCategoryScoreList(testItemAvgScoreCityList);
            dataList.add(cityClassAvgScoreVO);
        } else {
            TestItemAvgScoreVO cityClassAvgScoreVO = new TestItemAvgScoreVO();
            cityClassAvgScoreVO.setClassName("全市" + classTypeName + "平均分");
            cityClassAvgScoreVO.setTotalAvScore(BigDecimal.ZERO);
            cityClassAvgScoreVO.setCategoryScoreList(Lists.newArrayList());
            dataList.add(cityClassAvgScoreVO);
        }
    }

    /**
     * 分类表头信息
     *
     * @param avgKinderCategoryScoreInfo 表头信息
     * @return List<CategoryTableName> 表头信息
     */
    private List<CategoryTableName> setCategoryTableName(List<TestItemAvgScoreClassVO> avgKinderCategoryScoreInfo) {
        Map<Long, List<TestItemAvgScoreClassVO>> tableNameMap = avgKinderCategoryScoreInfo.stream()
                .filter(item -> Objects.nonNull(item.getParentId()))
                .collect(Collectors.groupingBy(TestItemAvgScoreClassVO::getParentId));
        List<CategoryTableName> categoryTableNameList = Lists.newArrayList();
        for (Map.Entry<Long, List<TestItemAvgScoreClassVO>> tableName : tableNameMap.entrySet()) {
            CategoryTableName categoryTableName = new CategoryTableName();
            categoryTableName.setParentId(Objects.isNull(tableName.getKey()) ? 0L : tableName.getKey());
            List<TestItemAvgScoreClassVO> tableNameList = tableName.getValue();
            if (tableNameList.size() > 0) {
                categoryTableName.setParentName(tableNameList.get(0).getParentName());
            }
            List<ChildrenTableName> childrenTableNameList = tableNameList.stream().map(item -> ChildrenTableName.builder().categoryId(item.getCategoryId()).categoryName(item.getCategoryName()).build()).collect(Collectors.toList());
            categoryTableName.setChildrenTableNameList(childrenTableNameList);
            categoryTableNameList.add(categoryTableName);
        }
        return categoryTableNameList;
    }


    /**
     * 计算合格人数和合格率
     *
     * @param dataList        数据集合
     * @param itemFractionMap 得分集合
     * @param itemLevelMap    得分级别信息集合
     */
    private void getItemQualifyCount(List<PhysicalActionAnalysisVO> dataList, Map<Long, List<ItemFractionInfo>> itemFractionMap,
                                     Map<Long, List<TestItemLevel>> itemLevelMap) {
        //循环计算合格人数和合格率
        dataList.forEach(item -> {
            //每个项目得分信息
            List<ItemFractionInfo> fractionInfoList = itemFractionMap.getOrDefault(Objects.isNull(item.getItemId()) ? 0L : item.getItemId(), Lists.newArrayList());
            //每个项目的区间信息
            List<TestItemLevel> itemLevelList = itemLevelMap.getOrDefault(Objects.isNull(item.getItemId()) ? 0L : item.getItemId(), Lists.newArrayList());
            //女性得分信息
            List<ItemFractionInfo> femaleFractionInfoList = fractionInfoList.stream().filter(score -> Objects.nonNull(score.getItemId()))
                    .filter(score -> FEMALE.equals(score.getStudentSex())).collect(Collectors.toList());
            //男性得分信息
            List<ItemFractionInfo> maleFractionInfoList = fractionInfoList.stream().filter(score -> Objects.nonNull(score.getItemId()))
                    .filter(score -> MALE.equals(score.getStudentSex())).collect(Collectors.toList());
            //女性达标人数
            int femaleStandardCount = (int) femaleFractionInfoList.stream().mapToLong(femaleScore -> itemLevelList.stream()
                    .filter(female -> Objects.nonNull(female.getLevelMinScore()) && Objects.nonNull(female.getLevelMaxScore()))
                    .filter(female -> femaleScore.getItemFraction().compareTo(female.getLevelMinScore()) >= 0 && femaleScore.getItemFraction().compareTo(female.getLevelMaxScore()) <= 0).count()).sum();
            item.setFeMalePassCount(femaleStandardCount);
            //男性达标人数
            int maleStandardCount = (int) maleFractionInfoList.stream().mapToLong(femaleScore -> itemLevelList.stream()
                    .filter(female -> Objects.nonNull(female.getLevelMinScore()) && Objects.nonNull(female.getLevelMaxScore()))
                    .filter(female -> femaleScore.getItemFraction().compareTo(female.getLevelMinScore()) >= 0 && femaleScore.getItemFraction().compareTo(female.getLevelMaxScore()) <= 0).count()).sum();
            item.setMalePassCount(maleStandardCount);
            //女性达标率
            if (femaleFractionInfoList.size() != 0) {
                item.setFeMalePassRate(BigDecimal.valueOf(femaleStandardCount).divide(BigDecimal.valueOf(femaleFractionInfoList.size()), 2, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP));
            } else {
                item.setFeMalePassRate(BigDecimal.ZERO);
            }
            //男性达标率
            if (maleFractionInfoList.size() != 0) {
                item.setMalePassRate(BigDecimal.valueOf(maleStandardCount).divide(BigDecimal.valueOf(maleFractionInfoList.size()), 2, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP));
            } else {
                item.setMalePassRate(BigDecimal.ZERO);
            }
        });
    }


    /**
     * 计算各项目的平均得分和全市的平均得分
     *
     * @param itemAvgScoreList 各项目平均得分信息
     * @param cityAvgScoreList 各项目全市平均得分信息
     * @param itemIdList       项目id集合
     * @param dataList         数据集合
     */
    private void getItemAvgScoreAndAvgCityScore(List<PhysicalActionAnalysisVO> itemAvgScoreList, List<PhysicalActionAnalysisVO> cityAvgScoreList,
                                                List<Long> itemIdList, List<PhysicalActionAnalysisVO> dataList) {
        //以项目id进行分组组装数据
        Map<Long, List<PhysicalActionAnalysisVO>> scoreMap = itemAvgScoreList.stream().filter(item -> Objects.nonNull(item.getItemId())).collect(Collectors.groupingBy(PhysicalActionAnalysisVO::getItemId));
        for (Long itemId : itemIdList) {
            List<PhysicalActionAnalysisVO> analysisList = scoreMap.getOrDefault(itemId, Lists.newArrayList());
            if (CollectionUtils.isEmpty(analysisList)) {
                continue;
            }
            //女性平均得分信息
            PhysicalActionAnalysisVO femaleInfo = analysisList.stream().filter(item -> StringUtils.isNotBlank(item.getStudentSex()) && FEMALE.equals(item.getStudentSex())).findFirst().orElseGet(PhysicalActionAnalysisVO::new);
            //男性平均得分信息
            PhysicalActionAnalysisVO maleInfo = analysisList.stream().filter(item -> StringUtils.isNotBlank(item.getStudentSex()) && MALE.equals(item.getStudentSex())).findFirst().orElseGet(PhysicalActionAnalysisVO::new);
            //女性全市平均得分信息
            PhysicalActionAnalysisVO cityFemaleInfo = cityAvgScoreList.stream().filter(item -> Objects.nonNull(item.getItemId()) && StringUtils.isNotBlank(item.getStudentSex()))
                    .filter(item -> itemId.equals(item.getItemId()) && FEMALE.equals(item.getStudentSex())).findFirst().orElseGet(PhysicalActionAnalysisVO::new);
            //男性全市平均得分信息
            PhysicalActionAnalysisVO cityMaleInfo = cityAvgScoreList.stream()
                    .filter(item -> Objects.nonNull(item.getItemId()) && StringUtils.isNotBlank(item.getStudentSex()))
                    .filter(item -> itemId.equals(item.getItemId()) && MALE.equals(item.getStudentSex())).findFirst().orElseGet(PhysicalActionAnalysisVO::new);
            PhysicalActionAnalysisVO actionAnalysisVO = new PhysicalActionAnalysisVO();
            actionAnalysisVO.setItemId(itemId);
            actionAnalysisVO.setItemName(StringUtils.isBlank(analysisList.get(0).getItemName()) ? "" : analysisList.get(0).getItemName());
            actionAnalysisVO.setFeMaleAvgScore(Objects.isNull(femaleInfo.getFeMaleAvgScore()) ? BigDecimal.ZERO : femaleInfo.getFeMaleAvgScore().setScale(2, BigDecimal.ROUND_HALF_UP));
            actionAnalysisVO.setFeMaleCityAvgScore(Objects.isNull(cityFemaleInfo.getFeMaleCityAvgScore()) ? BigDecimal.ZERO : cityFemaleInfo.getFeMaleCityAvgScore().setScale(2, BigDecimal.ROUND_HALF_UP));
            actionAnalysisVO.setMaleAvgScore(Objects.isNull(maleInfo.getMaleAvgScore()) ? BigDecimal.ZERO : maleInfo.getMaleAvgScore().setScale(2, BigDecimal.ROUND_HALF_UP));
            actionAnalysisVO.setMaleCityAvgScore(Objects.isNull(cityMaleInfo.getMaleCityAvgScore()) ? BigDecimal.ZERO : cityMaleInfo.getMaleCityAvgScore().setScale(2, BigDecimal.ROUND_HALF_UP));
            dataList.add(actionAnalysisVO);
        }
    }

    /**
     * 设置班级类型名称
     *
     * @param classType 班级类型
     * @return 班级类型名称
     */
    private String getClassTypeName(String classType) {
        //班级类型名称
        String classTypeName;
        switch (classType) {
            case "LARGE_CLASS":
                classTypeName = "大班";
                break;
            case "MIDDLE_CLASS":
                classTypeName = "中班";
                break;
            case "SMALL_CLASS":
                classTypeName = "小班";
                break;
            default:
                classTypeName = "";
                break;
        }
        return classTypeName;
    }

    /**
     * 根据幼儿园id和批次信息查询综合体质分析数据
     *
     * @param kindergartenId 幼儿园id
     * @param batchCode      批次编号
     * @param studentSex     性别
     * @return AjaxResult 综合体质分析数据
     * @throws Exception 异常信息
     */
    @Override
    public KinderPhysiqueAnalysisVO getKindShapeAnalysiInfo(Long kindergartenId, String batchCode, String studentSex) throws Exception {
        //查询一级分类的得分信息
        List<KinderCategoryScoreVO> kinderCategoryScoreList = kindergartenInfoMapper.getFirstKinderCategoryScoreInfo(kindergartenId, batchCode, studentSex, ItemCodeEnums.BMI_CODE.getInfo());
        if (CollectionUtils.isEmpty(kinderCategoryScoreList)) {
            return new KinderPhysiqueAnalysisVO();
        }
        //计算每个一级分类的平均得分
        Map<Long, List<KinderCategoryScoreVO>> firstCategoryMap = kinderCategoryScoreList.stream().filter(item -> Objects.nonNull(item.getId())).collect(Collectors.groupingBy(KinderCategoryScoreVO::getId));
        if (firstCategoryMap.isEmpty()) {
            return new KinderPhysiqueAnalysisVO();
        }
        KinderPhysiqueAnalysisVO analysisVO = new KinderPhysiqueAnalysisVO();
        //计算一级分类平均得分信息和总平均分信息
        this.getFirstCategoryInfo(firstCategoryMap, analysisVO);
        //查询每个分类的成绩信息
        List<KinderCategoryScoreVO> categoryScoreInfoList = kindergartenInfoMapper.getKinderCategoryScoreInfo(kindergartenId, batchCode, studentSex, ItemCodeEnums.BMI_CODE.getInfo());
        if (CollectionUtils.isEmpty(categoryScoreInfoList)) {
            return new KinderPhysiqueAnalysisVO();
        }
        //查询每个分类的得分区间信息
        List<Long> categoryIdList = categoryScoreInfoList.stream().filter(item -> Objects.nonNull(item.getId())).map(KinderCategoryScoreVO::getId).distinct().collect(Collectors.toList());
        Map<Long, List<TestItemLevel>> itemLevelMap = studentInfoMapper.getTestItemLevelByCategoryId(categoryIdList).stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getItemCategoryId())).collect(Collectors.groupingBy(TestItemLevel::getItemCategoryId));
        if (itemLevelMap.isEmpty()) {
            return new KinderPhysiqueAnalysisVO();
        }
        //计算每个分类的平均得分以及每个分类的平均得分描述信息
        this.getCategoryLevelInfo(categoryScoreInfoList, itemLevelMap, analysisVO);
        //计算不同年龄段的各分类的平均得分
        List<CategoryScoreVO> categoryAvgScoreInfo = this.getCategoryAvgScoreInfo(categoryScoreInfoList, categoryIdList);
        //求全园平均成绩
        List<FirstCategoryScoreVO> avgKinderCategoryScoreInfo = kindergartenInfoMapper.getAvgKinderCategoryScoreInfo(kindergartenId, batchCode, studentSex, ItemCodeEnums.BMI_CODE.getInfo());
        long studentCount = categoryScoreInfoList.stream().filter(item -> Objects.nonNull(item.getStudentId())).map(KinderCategoryScoreVO::getStudentId).distinct().count();
        avgKinderCategoryScoreInfo.forEach(item -> {
            if (studentCount != 0 && Objects.nonNull(item.getAvgCategoryFraction())) {
                item.setAvgCategoryFraction(BigDecimalUtil.getAvgScore(BigDecimal.valueOf(studentCount), item.getAvgCategoryFraction()));
            }
        });
        CategoryScoreVO avgKinderCategoryScore = new CategoryScoreVO();
        avgKinderCategoryScore.setStudentAge("全园平均分");
        avgKinderCategoryScore.setTotalAvgFraction(avgKinderCategoryScoreInfo.stream().filter(item -> Objects.nonNull(item.getAvgCategoryFraction())).map(FirstCategoryScoreVO::getAvgCategoryFraction).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP));
        avgKinderCategoryScore.setCategoryAvgFractionList(avgKinderCategoryScoreInfo);
        categoryAvgScoreInfo.add(avgKinderCategoryScore);
        //全市平均成绩
        this.getAvgCityScoreIno(kindergartenId, studentSex, batchCode, categoryAvgScoreInfo, analysisVO);
        //区表头信息
        setCategoryTableName(avgKinderCategoryScoreInfo, analysisVO);
        return analysisVO;
    }


    /**
     * 计算不同年龄段的分类平均得分信息
     *
     * @param categoryScoreInfoList 分类得分信息集合
     * @param categoryIdList        分类id集合
     * @return List<CategoryScoreVO> 不同年龄段每个分类的平均成绩信息
     */
    private List<CategoryScoreVO> getCategoryAvgScoreInfo(List<KinderCategoryScoreVO> categoryScoreInfoList, List<Long> categoryIdList) {
        Map<Double, List<KinderCategoryScoreVO>> studentAgeMap = categoryScoreInfoList.stream()
                .filter(item -> Objects.nonNull(item.getStudentAge()) && item.getStudentAge() != 0)
                .collect(Collectors.groupingBy(KinderCategoryScoreVO::getStudentAge));
        List<CategoryScoreVO> categoryAgeFractionList = Lists.newArrayList();
        for (Map.Entry<Double, List<KinderCategoryScoreVO>> studentAgeEntry : studentAgeMap.entrySet()) {
            CategoryScoreVO categoryScoreVO = new CategoryScoreVO();
            //年龄
            categoryScoreVO.setStudentAge(Objects.isNull(studentAgeEntry.getKey()) ? "0.0" : studentAgeEntry.getKey() + "岁");
            //每个分类的信息
            List<KinderCategoryScoreVO> scoreList = CollectionUtils.isEmpty(studentAgeEntry.getValue()) ? Lists.newArrayList() : studentAgeEntry.getValue();
            Map<Long, List<KinderCategoryScoreVO>> categoryIdMap = scoreList.stream().filter(item -> Objects.nonNull(item.getId())).collect(Collectors.groupingBy(KinderCategoryScoreVO::getId));
            //每个分类的平均得分
            List<FirstCategoryScoreVO> categoryAvgFractionList = Lists.newArrayList();
            for (Long categoryId : categoryIdList) {
                List<KinderCategoryScoreVO> categoryList = categoryIdMap.getOrDefault(categoryId, Lists.newArrayList());
                if (CollectionUtils.isEmpty(categoryList)) {
                    continue;
                }
                FirstCategoryScoreVO firstCategoryScoreVO = new FirstCategoryScoreVO();
                //分类id
                firstCategoryScoreVO.setCategoryId(categoryId);
                //分类名称
                firstCategoryScoreVO.setCategoryName(categoryList.get(0).getCategoryName());
                //平均成绩
                long studentCount = categoryList.stream().filter(item -> Objects.nonNull(item.getStudentId())).map(KinderCategoryScoreVO::getStudentId).distinct().count();
                BigDecimal totalItemFraction = categoryList.stream().filter(item -> Objects.nonNull(item.getItemFraction())).map(KinderCategoryScoreVO::getItemFraction).reduce(BigDecimal.ZERO, BigDecimal::add);
                firstCategoryScoreVO.setAvgCategoryFraction(BigDecimalUtil.getAvgScore(BigDecimal.valueOf(studentCount), totalItemFraction));
                categoryAvgFractionList.add(firstCategoryScoreVO);
            }
            //每个分类的平均成绩
            categoryScoreVO.setCategoryAvgFractionList(categoryAvgFractionList);
            //平均总分
            categoryScoreVO.setTotalAvgFraction(categoryAvgFractionList.stream().filter(item -> Objects.nonNull(item.getAvgCategoryFraction())).map(FirstCategoryScoreVO::getAvgCategoryFraction).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP));
            categoryAgeFractionList.add(categoryScoreVO);
        }
        return categoryAgeFractionList;
    }


    /**
     * 查询全是平均成绩信息
     *
     * @param kindergartenId       幼儿园id
     * @param studentSex           学生性别
     * @param batchCode            批次编号
     * @param categoryAvgScoreInfo 平均成绩信息集合
     * @param analysisVO           返回值
     */
    private void getAvgCityScoreIno(Long kindergartenId, String studentSex, String batchCode,
                                    List<CategoryScoreVO> categoryAvgScoreInfo, KinderPhysiqueAnalysisVO analysisVO) {
        //全市平均成绩
        List<Long> areaIdList = this.getSysAreaInfoByKindergartenId(kindergartenId);
        //查询当前幼儿园所属市下得所有的幼儿园信息和学生信息
        List<StudentAndKindergartenVO> studentAndKindergartenList = kindergartenInfoMapper.getStudentAndKindergartenCount(areaIdList);
        if (CollectionUtils.isEmpty(areaIdList) && CollectionUtils.isEmpty(studentAndKindergartenList)) {
            CategoryScoreVO avgCityCategoryScore = new CategoryScoreVO();
            avgCityCategoryScore.setStudentAge("全市平均分");
            avgCityCategoryScore.setTotalAvgFraction(BigDecimal.ZERO);
            avgCityCategoryScore.setCategoryAvgFractionList(Lists.newArrayList());
            categoryAvgScoreInfo.add(avgCityCategoryScore);
            analysisVO.setCategoryAgeFractionList(categoryAvgScoreInfo);
            return;
        }
        //全市下的幼儿园id集合
        List<Long> kindergartenIdList = studentAndKindergartenList.stream().filter(item -> Objects.nonNull(item.getKindergartenId())).map(StudentAndKindergartenVO::getKindergartenId).distinct().collect(Collectors.toList());
        //全市下的所有学生数量
        long studentSexCount = studentAndKindergartenList.stream().filter(item -> Objects.nonNull(item.getStudentId()) && StringUtils.isNotBlank(item.getStudentSex())).filter(item -> studentSex.equals(item.getStudentSex())).distinct().count();
        //查询全市下的每个分类的总成绩信息
        List<FirstCategoryScoreVO> avgWholeCityCategoryScoreInfo = kindergartenInfoMapper.getAvgWholeCityCategoryScoreInfo(kindergartenIdList, batchCode, studentSex, ItemCodeEnums.BMI_CODE.getInfo());
        //计算平均成绩
        avgWholeCityCategoryScoreInfo.forEach(item -> {
            if (studentSexCount != 0 && Objects.nonNull(item.getAvgCategoryFraction())) {
                item.setAvgCategoryFraction(BigDecimalUtil.getAvgScore(BigDecimal.valueOf(studentSexCount), item.getAvgCategoryFraction()));
            }
        });
        //全市平均成绩
        CategoryScoreVO avgCityCategoryScore = new CategoryScoreVO();
        avgCityCategoryScore.setStudentAge("全市平均分");
        avgCityCategoryScore.setTotalAvgFraction(avgWholeCityCategoryScoreInfo.stream().filter(item -> Objects.nonNull(item.getAvgCategoryFraction())).map(FirstCategoryScoreVO::getAvgCategoryFraction).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP));
        avgCityCategoryScore.setCategoryAvgFractionList(avgWholeCityCategoryScoreInfo);
        categoryAvgScoreInfo.add(avgCityCategoryScore);
        analysisVO.setCategoryAgeFractionList(categoryAvgScoreInfo);
    }

    /**
     * 根据幼儿园id查询对应得区域信息
     *
     * @param kindergartenId 幼儿园id
     * @return 区域信息集合
     */
    private List<Long> getSysAreaInfoByKindergartenId(Long kindergartenId) {
        SysArea sysArea = kindergartenInfoMapper.getSysAreaByKindergartenId(kindergartenId);
        List<Long> sysAreaIdList = Lists.newArrayList();
        if (Objects.nonNull(sysArea.getLevel())) {
            //所属市
            if (Constants.CITY_LEVEL.equals(sysArea.getLevel())) {
                sysAreaIdList = sysAreaMapper.getSysAreaIdList(Objects.isNull(sysArea.getId()) ? 0L : sysArea.getId());
                if (Objects.nonNull(sysArea.getId())) {
                    sysAreaIdList.add(sysArea.getId());
                }
            }
            //所属区
            if (Constants.REGION_LEVEL.equals(sysArea.getLevel())) {
                sysAreaIdList = sysAreaMapper.getSysAreaIdList(Objects.isNull(sysArea.getParentId()) ? 0L : sysArea.getParentId());
                if (Objects.nonNull(sysArea.getParentId())) {
                    sysAreaIdList.add(sysArea.getParentId());
                }
            }
        }
        return sysAreaIdList;
    }

    /**
     * 分类表头信息
     *
     * @param avgKinderCategoryScoreInfo 表头信息
     * @param analysisVO                 各级表头信息
     */
    private void setCategoryTableName(List<FirstCategoryScoreVO> avgKinderCategoryScoreInfo,
                                      KinderPhysiqueAnalysisVO analysisVO) {
        Map<Long, List<FirstCategoryScoreVO>> tableNameMap = avgKinderCategoryScoreInfo.stream().filter(item -> Objects.nonNull(item.getParentId())).collect(Collectors.groupingBy(FirstCategoryScoreVO::getParentId));
        List<CategoryTableName> categoryTableNameList = Lists.newArrayList();
        for (Map.Entry<Long, List<FirstCategoryScoreVO>> tableName : tableNameMap.entrySet()) {
            CategoryTableName categoryTableName = new CategoryTableName();
            categoryTableName.setParentId(Objects.isNull(tableName.getKey()) ? 0L : tableName.getKey());
            List<FirstCategoryScoreVO> tableNameList = tableName.getValue();
            if (tableNameList.size() > 0L) {
                categoryTableName.setParentName(tableNameList.get(0).getParentName());
            }
            List<ChildrenTableName> childrenTableNameList = tableNameList.stream().map(item -> ChildrenTableName.builder().categoryId(item.getCategoryId()).categoryName(item.getCategoryName()).build()).collect(Collectors.toList());
            categoryTableName.setChildrenTableNameList(childrenTableNameList);
            categoryTableNameList.add(categoryTableName);
        }
        analysisVO.setCategoryTableNameList(categoryTableNameList);
    }

    /**
     * 每个分类的得分区间信息
     *
     * @param categoryScoreInfoList 每个分类的成绩信息
     * @param itemLevelMap          分类信息键值对
     * @param analysisVO            返回值信息
     * @throws Exception 异常信息
     */
    private void getCategoryLevelInfo(List<KinderCategoryScoreVO> categoryScoreInfoList,
                                      Map<Long, List<TestItemLevel>> itemLevelMap,
                                      KinderPhysiqueAnalysisVO analysisVO) throws Exception {
        //计算每个分类的平均得分以及每个分类的平均得分描述信息
        for (KinderCategoryScoreVO score : categoryScoreInfoList) {
            List<TestItemLevel> itemLevelList = itemLevelMap.getOrDefault(Objects.isNull(score.getId()) ? 0 : score.getId(), Lists.newArrayList());
            for (TestItemLevel level : itemLevelList) {
                setCategoryName(score, level);
            }
            //学生年龄
            if (Objects.nonNull(score.getBirthDate())) {
                score.setStudentAge(AgeUtil.getStudentAgeMonth(score.getBirthDate().toString()));
            }
            //求每个区间的最高得分
            List<BigDecimal> minScoreList = itemLevelList.stream().filter(item -> Objects.nonNull(item.getLevelMinScore())).map(TestItemLevel::getLevelMinScore).distinct().collect(Collectors.toList());
            List<BigDecimal> maxScoreList = itemLevelList.stream().filter(item -> Objects.nonNull(item.getLevelMaxScore())).map(TestItemLevel::getLevelMaxScore).distinct().collect(Collectors.toList());
            List<BigDecimal> scoreList = Lists.newArrayList();
            scoreList.addAll(minScoreList);
            scoreList.addAll(maxScoreList);
            BigDecimal max = BigDecimal.ZERO;
            if (CollectionUtils.isNotEmpty(scoreList)) {
                max = Collections.max(scoreList);
            }
            score.setMaxFraction(max);
        }
        //将一级分类区间信息去除
        List<KinderCategoryScoreVO> distinctScoreList = categoryScoreInfoList.stream().filter(item -> Objects.nonNull(item.getId())).distinct().collect(Collectors.toList());
        analysisVO.setCategoryScoreList(distinctScoreList);
    }

    /**
     * 设置平均得分区间描述信息
     *
     * @param score 得分信息
     * @param level 得分区间标准信息
     */
    private void setCategoryName(KinderCategoryScoreVO score, TestItemLevel level) throws Exception {
        if (Objects.nonNull(score.getItemFraction()) && Objects.nonNull(level.getLevelMinScore())
                && Objects.nonNull(level.getLevelMaxScore())) {
            if ((score.getItemFraction().compareTo(level.getLevelMinScore()) >= 0
                    && score.getItemFraction().compareTo(level.getLevelMaxScore()) <= 0)) {
                //得分区间信息
                score.setAvgCategoryName(StringUtils.isBlank(level.getLevelName()) ? "" : level.getLevelName());
            }
        }
    }

    /**
     * 计算一级分类的得分平得分信息
     *
     * @param firstCategoryMap 输入参数
     * @param analysisVO       返回值信息
     */
    private void getFirstCategoryInfo(Map<Long, List<KinderCategoryScoreVO>> firstCategoryMap,
                                      KinderPhysiqueAnalysisVO analysisVO) {
        List<FirstCategoryScoreVO> firstCategoryScoreList = Lists.newArrayList();
        for (Map.Entry<Long, List<KinderCategoryScoreVO>> categoryEntry : firstCategoryMap.entrySet()) {
            List<KinderCategoryScoreVO> categoryScoreList = categoryEntry.getValue();
            if (CollectionUtils.isEmpty(categoryScoreList)) {
                continue;
            }
            //参加每个分类测试的总人数
            long studentCount = categoryScoreList.stream().filter(item -> Objects.nonNull(item.getStudentId())).map(KinderCategoryScoreVO::getStudentId).distinct().count();
            //每个分类的总成绩相加
            BigDecimal totalScore = categoryScoreList.stream().filter(item -> Objects.nonNull(item.getItemFraction())).map(KinderCategoryScoreVO::getItemFraction).reduce(BigDecimal.ZERO, BigDecimal::add);
            FirstCategoryScoreVO categoryScoreVO = new FirstCategoryScoreVO();
            categoryScoreVO.setCategoryName(categoryScoreList.get(0).getCategoryName());
            if (Objects.nonNull(totalScore) && studentCount != 0) {
                categoryScoreVO.setAvgCategoryFraction(BigDecimalUtil.getAvgScore(BigDecimal.valueOf(studentCount), totalScore));
            } else {
                categoryScoreVO.setAvgCategoryFraction(BigDecimal.ZERO);
            }
            firstCategoryScoreList.add(categoryScoreVO);
        }
        //一级分类总的平均得分
        analysisVO.setTotalAvgFraction(firstCategoryScoreList.stream().filter(item -> Objects.nonNull(item.getAvgCategoryFraction())).map(FirstCategoryScoreVO::getAvgCategoryFraction).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP));
        //一级分类平得分集合信息
        analysisVO.setFirstCategoryScoreList(firstCategoryScoreList);
    }
}
