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

import com.xinyilu.common.constant.Constants;
import com.xinyilu.common.core.domain.AjaxResult;
import com.xinyilu.common.enums.ItemCodeEnums;
import com.xinyilu.system.domain.systemarea.SysArea;
import com.xinyilu.system.domain.testLevel.TestItemLevel;
import com.xinyilu.system.domain.vo.kinderPhysiqueAnalysis.StudentAndKindergartenVO;
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.mapper.kindergarteninfo.KindergartenInfoMapper;
import com.xinyilu.system.mapper.systemarea.SysAreaMapper;
import com.xinyilu.system.mapper.testItem.TestItemsMapper;
import com.xinyilu.system.service.physicalActionAnalysis.PhysicalActionAnalysisService;
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.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description 幼儿身体素质/动作发展状况分析业务层实现类
 * @Author 纪寒
 * @Date 2022-08-19 11:14:52
 * @Version 1.0
 */
@Service
public class PhysicalActionAnalysisServiceImpl implements PhysicalActionAnalysisService {

    @Resource
    private TestItemsMapper testItemsMapper;
    @Resource
    private KindergartenInfoMapper kindergartenInfoMapper;
    @Resource
    private SysAreaMapper sysAreaMapper;

    /**
     * 男性
     */
    private static final String MALE = "MALE";

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

    /**
     * 根据幼儿园id和班级类型查询分析数据
     *
     * @param kindergartenId 幼儿园id
     * @param classType      班级类型
     * @param batchCode      批次编号
     * @return 分析数据结果
     */
    @Override
    public AjaxResult 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 AjaxResult.success();
        }
        //获取项目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 AjaxResult.success(physicalActionVO);
        }
        //循环计算合格人数和合格率
        this.getItemQualifyCount(dataList, itemFractionMap, itemLevelMap);
        physicalActionVO.setClassTypeName(classTypeName);
        physicalActionVO.setPhysicalActionList(dataList);
        return AjaxResult.success(physicalActionVO);
    }

    /**
     * 设置班级类型名称
     *
     * @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;
    }

    /**
     * 计算各项目的平均得分和全市的平均得分
     *
     * @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 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);
            }
        });
    }

    /**
     * 根据幼儿园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;
    }
}
