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

import com.xinyilu.common.core.domain.entity.SysDictData;
import com.xinyilu.common.enums.CategoryLevelEnum;
import com.xinyilu.common.enums.ItemCodeEnums;
import com.xinyilu.common.enums.ItemFlagEnum;
import com.xinyilu.common.enums.StudentAgeFlagEnum;
import com.xinyilu.common.utils.AgeUtil;
import com.xinyilu.system.domain.heightWeightInfo.HeightWeightInfo;
import com.xinyilu.system.domain.testLevel.TestItemLevel;
import com.xinyilu.system.domain.vo.BodyShapeAnalysisVO;
import com.xinyilu.system.domain.vo.BodyShapeItemScoreVO;
import com.xinyilu.system.domain.vo.physiqueAnalysis.PhysiqueAnalysisVO;
import com.xinyilu.system.domain.vo.physiqueAnalysis.PhysiqueCategoryVO;
import com.xinyilu.system.mapper.SysDictDataMapper;
import com.xinyilu.system.mapper.heightWeightInfo.HeightWeightInfoMapper;
import com.xinyilu.system.mapper.studentInfo.StudentInfoMapper;
import com.xinyilu.system.mapper.testItem.TestItemsMapper;
import com.xinyilu.system.service.checkreport.PhysiqueBodyShapeAnalysisService;
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.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 个人综合分析和身体形态分析报告查询方法业务层实现类
 * @Author 纪寒
 * @Date 2022-09-27 09:23:19
 * @Version 1.0
 */
@Service
@Slf4j
public class PhysiqueBodyShapeAnalysisServiceImpl implements PhysiqueBodyShapeAnalysisService {

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

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

    /**
     * 男性值
     */
    private static final String MALE_VALUE = "男";

    /**
     * 女性值
     */
    private static final String FEMALE_VALUE = "女";

    /**
     * 一岁年龄值
     */
    private static final Double ONE_YEAR = 1.0;

    @Resource
    private StudentInfoMapper studentInfoMapper;
    @Resource
    private SysDictDataMapper sysDictDataMapper;
    @Resource
    private TestItemsMapper testItemsMapper;
    @Resource
    private HeightWeightInfoMapper heightWeightInfoMapper;

    /**
     * 查询学生个人综合分析信息
     *
     * @param studentInfo 学生信息
     * @param studentId   学生id
     * @param batchCode   批次code
     * @return PhysiqueAnalysisVO 学生信息
     * @throws Exception 异常信息
     */
    @Override
    public PhysiqueAnalysisVO getStudentPhysiqueAnalysis(PhysiqueAnalysisVO studentInfo, Long studentId, String batchCode) throws Exception {
        //设置批次编号
        studentInfo.setBatchCode(batchCode);
        //计算学生年龄
        if (Objects.nonNull(studentInfo.getBirthDate())) {
            studentInfo.setStudentAge(AgeUtil.getStudentAgeMonth(studentInfo.getBirthDate().toString()));
        }
        //性别
        String studentSex = StringUtils.isBlank(studentInfo.getStudentSex()) ? "" : studentInfo.getStudentSex();
        switch (studentSex) {
            case MALE:
                studentInfo.setStudentSex(MALE_VALUE);
                studentInfo.setStudentSexStr(MALE);
                break;
            case FEMALE:
                studentInfo.setStudentSex(FEMALE_VALUE);
                studentInfo.setStudentSexStr(FEMALE);
                break;
            default:
                studentInfo.setStudentSex("");
                studentInfo.setStudentSexStr("");
                break;
        }
        //查询综合得分
        List<PhysiqueCategoryVO> firstItemCategoryList = studentInfoMapper.getFirstItemCategory(studentId, CategoryLevelEnum.FIRST_LEVEL.getLevelId(), batchCode, ItemCodeEnums.BMI_CODE.getInfo());
        studentInfo.setTotalCategoryScore(firstItemCategoryList.stream().filter(item -> Objects.nonNull(item.getCategoryScore())).map(PhysiqueCategoryVO::getCategoryScore).reduce(BigDecimal.ZERO, BigDecimal::add));
        List<PhysiqueCategoryVO> physiqueCategoryVOList = new ArrayList<>();
        Map<Long, List<PhysiqueCategoryVO>> physiqueCategoryMap = firstItemCategoryList.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getId())).collect(Collectors.groupingBy(PhysiqueCategoryVO::getId));
        physiqueCategoryMap.forEach((id, physiqueCategory) -> {
            PhysiqueCategoryVO physiqueCategoryVO = new PhysiqueCategoryVO();
            physiqueCategoryVO.setId(Objects.isNull(id) ? null : id);
            physiqueCategoryVO.setCategoryName(StringUtils.isBlank(physiqueCategory.get(0).getCategoryName()) ? "" : physiqueCategory.get(0).getCategoryName());
            BigDecimal bigDecimal = physiqueCategory.stream().filter(item -> Objects.nonNull(item.getCategoryScore()))
                    .map(PhysiqueCategoryVO::getCategoryScore)
                    .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP);
            if (Objects.nonNull(bigDecimal)){
                physiqueCategoryVO.setCategoryScore(bigDecimal);
            }
            physiqueCategoryVOList.add(physiqueCategoryVO);
        });
        studentInfo.setFirstItemCategoryList(physiqueCategoryVOList);
        //查询综合体质分析图形数据
        List<PhysiqueCategoryVO> itemCategoryScoreList = studentInfoMapper.getItemCategoryScore(studentId, batchCode, ItemCodeEnums.BMI_CODE.getInfo());
        if (CollectionUtils.isEmpty(itemCategoryScoreList)) {
            studentInfo.setPhysiqueCategoryList(itemCategoryScoreList);
            return studentInfo;
        }
        //分类id集合
        List<Long> categoryIdList = itemCategoryScoreList.stream().filter(item -> Objects.nonNull(item.getId())).map(PhysiqueCategoryVO::getId).collect(Collectors.toList());
        //根据分类id查询各分类得分区间信息
        Map<Long, List<TestItemLevel>> levelMap = studentInfoMapper.getTestItemLevelByCategoryId(categoryIdList).stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getItemCategoryId())).collect(Collectors.groupingBy(TestItemLevel::getItemCategoryId));
        if (levelMap.isEmpty()) {
            studentInfo.setPhysiqueCategoryList(itemCategoryScoreList);
        }
        //匹配各每个成绩的级别描述信息
        itemCategoryScoreList.forEach(item -> {
            List<TestItemLevel> levelList = levelMap.getOrDefault(item.getId(), Lists.newArrayList());
            levelList.forEach(level -> {
                if (Objects.nonNull(item.getCategoryScore()) && Objects.nonNull(level.getLevelMinScore())
                        && Objects.nonNull(level.getLevelMaxScore())) {
                    if (item.getCategoryScore().compareTo(level.getLevelMinScore()) >= 0
                            && item.getCategoryScore().compareTo(level.getLevelMaxScore()) <= 0) {
                        item.setLevelName(StringUtils.isBlank(level.getLevelName()) ? "" : level.getLevelName());
                    }
                }
            });
            //获取区间最大值
            List<BigDecimal> maxScoreList = levelList.stream().filter(score -> Objects.nonNull(score.getLevelMaxScore())).map(TestItemLevel::getLevelMaxScore).collect(Collectors.toList());
            BigDecimal max = BigDecimal.ZERO;
            if (CollectionUtils.isNotEmpty(maxScoreList)) {
                max = Collections.max(maxScoreList);
            }
            item.setMaxScore(max);
        });
        studentInfo.setPhysiqueCategoryList(itemCategoryScoreList);
        return studentInfo;
    }

    /**
     * 查询学生身体形态分析数据
     *
     * @param studentInfo 学生信息
     * @param studentId   学生id
     * @param batchCode   批次编号
     * @return 身体形态分析数据信息
     * @throws Exception 异常信息
     */
    @Override
    public BodyShapeAnalysisVO getStudentBodyShapeAnalysis(PhysiqueAnalysisVO studentInfo, Long studentId, String batchCode) throws Exception {
        BodyShapeAnalysisVO analysisVO = new BodyShapeAnalysisVO();
        analysisVO.setStudentName(StringUtils.isBlank(studentInfo.getStudentName()) ? "" : studentInfo.getStudentName());
        //查询身体形态标题和身体形态描述信息
        List<SysDictData> bodyShapeDict = sysDictDataMapper.selectDictDataByType("body_shape_test");
        if (CollectionUtils.isNotEmpty(bodyShapeDict)) {
            analysisVO.setShapeTitle(StringUtils.isBlank(bodyShapeDict.get(0).getDictLabel()) ? "" : bodyShapeDict.get(0).getDictLabel());
            analysisVO.setShapeDescription(StringUtils.isBlank(bodyShapeDict.get(0).getRemark()) ? "" : bodyShapeDict.get(0).getRemark());
        }
        //获取身高和体重项目编号
        List<String> itemCodeList = Lists.newArrayList();
        itemCodeList.add(ItemCodeEnums.HEIGHT_CODE.getInfo());
        itemCodeList.add(ItemCodeEnums.WEIGHT_CODE.getInfo());
        //查询身高项目和体重项目的成绩信息
        List<BodyShapeItemScoreVO> itemScoreList = testItemsMapper.getBodyShapeScoreInfo(studentId, itemCodeList, batchCode);
        Map<String, BodyShapeItemScoreVO> itemCodeMap = itemScoreList.stream().filter(Objects::nonNull)
                .filter(item -> StringUtils.isNotBlank(item.getItemCode()))
                .collect(Collectors.toMap(BodyShapeItemScoreVO::getItemCode, item -> item));
        //计算身高体重信息
        this.setHeightAndWeightInfo(itemCodeMap, analysisVO);
        //计算年龄身高比和体重身高比信息
        this.getHeightAndWeightInfo(studentInfo, analysisVO);
        //查询BMI项目成绩信息
        this.getBmiItemInfo(analysisVO, ItemCodeEnums.BMI_CODE.getInfo());
        return analysisVO;
    }

    /**
     * 设置身高体重项目成绩以及计算BMI
     *
     * @param itemCodeMap 身高体重项目信息
     * @param analysisVO  返回值
     */
    private void setHeightAndWeightInfo(Map<String, BodyShapeItemScoreVO> itemCodeMap, BodyShapeAnalysisVO analysisVO) {
        if (!itemCodeMap.isEmpty()) {
            //获取身高项目信息
            BodyShapeItemScoreVO heightInfo = itemCodeMap.getOrDefault(ItemCodeEnums.HEIGHT_CODE.getInfo(), new BodyShapeItemScoreVO());
            analysisVO.setHeightName(StringUtils.isEmpty(heightInfo.getItemName()) ? "" : heightInfo.getItemName());
            analysisVO.setHeightMeasureUnit(StringUtils.isEmpty(heightInfo.getMeasureUnit()) ? "" : heightInfo.getMeasureUnit());
            BigDecimal heightScore = Objects.isNull(heightInfo.getItemScore()) ? BigDecimal.ZERO : heightInfo.getItemScore();
            analysisVO.setHeightScore(heightScore);
            //获取体重信息
            BodyShapeItemScoreVO weightInfo = itemCodeMap.getOrDefault(ItemCodeEnums.WEIGHT_CODE.getInfo(), new BodyShapeItemScoreVO());
            analysisVO.setWeightName(StringUtils.isEmpty(weightInfo.getItemName()) ? "" : weightInfo.getItemName());
            analysisVO.setWeightMeasureUnit(StringUtils.isEmpty(weightInfo.getMeasureUnit()) ? "" : weightInfo.getMeasureUnit());
            BigDecimal weightScore = Objects.isNull(weightInfo.getItemScore()) ? BigDecimal.ZERO : weightInfo.getItemScore();
            analysisVO.setWeightScore(weightScore);
            //计算BMI，BMI = 体重 / 身高的平方
            BigDecimal squareHeight = heightScore.multiply(heightScore).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_HALF_UP);
            if (Objects.nonNull(squareHeight) && squareHeight.compareTo(BigDecimal.ZERO) != 0) {
                BigDecimal bmiScore = weightScore.divide(squareHeight, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                analysisVO.setBmi(bmiScore);
            } else {
                analysisVO.setBmi(BigDecimal.ZERO);
            }
        } else {
            analysisVO.setHeightName("");
            analysisVO.setHeightMeasureUnit("");
            analysisVO.setHeightScore(BigDecimal.ZERO);
            analysisVO.setWeightName("");
            analysisVO.setWeightMeasureUnit("");
            analysisVO.setWeightScore(BigDecimal.ZERO);
            analysisVO.setBmi(BigDecimal.ZERO);
        }
    }

    /**
     * 查询年龄身高比信息和体重身高比信息
     *
     * @param studentInfo 学生信息
     * @param analysisVO  返回值信息
     * @throws Exception 异常信息
     */
    private void getHeightAndWeightInfo(PhysiqueAnalysisVO studentInfo, BodyShapeAnalysisVO analysisVO) throws Exception {
        //根据出生日期计算学生的年龄，支持到年即：几岁，不支持几个月
        Double studentAge = AgeUtil.getStudentAgeMonth(Objects.isNull(studentInfo.getBirthDate()) ? LocalDate.now().toString() : studentInfo.getBirthDate().toString());
        HeightWeightInfo heightWeightInfo = new HeightWeightInfo();
        if (studentAge.equals(ONE_YEAR)) {
            //一岁表中存的是12个月，作特殊处理
            heightWeightInfo.setAge(BigDecimal.valueOf(12));
            heightWeightInfo.setMonthAgeFlag(StudentAgeFlagEnum.MONTH.getInfo());
        } else {
            heightWeightInfo.setAge(BigDecimal.valueOf(studentAge));
            heightWeightInfo.setMonthAgeFlag(StudentAgeFlagEnum.YEAR.getInfo());
        }
        heightWeightInfo.setSex(StringUtils.isEmpty(studentInfo.getStudentSexStr()) ? "" : studentInfo.getStudentSexStr());
        List<HeightWeightInfo> heightWeightInfoList = heightWeightInfoMapper.selectHeightWeightInfoList(heightWeightInfo);
        Map<String, HeightWeightInfo> weightInfoMap = heightWeightInfoList.stream().filter(Objects::nonNull)
                .filter(item -> StringUtils.isNotBlank(item.getItemFlag()))
                .collect(Collectors.toMap(HeightWeightInfo::getItemFlag, item -> item));
        if (!weightInfoMap.isEmpty()) {
            //年龄身高比信息
            HeightWeightInfo heightAgeInfo = weightInfoMap.getOrDefault(ItemFlagEnum.HEIGHT.getInfo(), new HeightWeightInfo());
            BigDecimal ageHeightMin = Objects.isNull(heightAgeInfo.getMinValue()) ? BigDecimal.ZERO : heightAgeInfo.getMinValue();
            BigDecimal ageHeightMax = Objects.isNull(heightAgeInfo.getMaxValue()) ? BigDecimal.ZERO : heightAgeInfo.getMaxValue();
            analysisVO.setAgeHeightMin(ageHeightMin);
            analysisVO.setAgeHeightMax(ageHeightMax);
            //判断年龄身高比是否达标
            if (Objects.nonNull(analysisVO.getHeightScore()) && analysisVO.getHeightScore().compareTo(ageHeightMin) >= 0
                    && analysisVO.getHeightScore().compareTo(ageHeightMax) <= 0) {
                analysisVO.setAgeHeightDescription("达标");
            } else {
                analysisVO.setAgeHeightDescription("");
            }
            //年龄体重比信息
            HeightWeightInfo weightAgeInfo = weightInfoMap.getOrDefault(ItemFlagEnum.WEIGHT.getInfo(), new HeightWeightInfo());
            BigDecimal ageWeightMin = Objects.isNull(weightAgeInfo.getMinValue()) ? BigDecimal.ZERO : weightAgeInfo.getMinValue();
            BigDecimal ageWeightMax = Objects.isNull(weightAgeInfo.getMaxValue()) ? BigDecimal.ZERO : weightAgeInfo.getMaxValue();
            analysisVO.setAgeWeightMin(ageWeightMin);
            analysisVO.setAgeWeightMax(ageWeightMax);
            //判断年龄身高比是否达标
            if (Objects.nonNull(analysisVO.getWeightScore()) && analysisVO.getWeightScore().compareTo(ageWeightMin) >= 0
                    && analysisVO.getWeightScore().compareTo(ageWeightMax) <= 0) {
                analysisVO.setAgeWeightDescription("达标");
            } else {
                analysisVO.setAgeWeightDescription("");
            }
        } else {
            analysisVO.setAgeHeightMin(BigDecimal.ZERO);
            analysisVO.setAgeHeightMax(BigDecimal.ZERO);
            analysisVO.setAgeHeightDescription("");
            analysisVO.setAgeWeightMin(BigDecimal.ZERO);
            analysisVO.setAgeWeightMax(BigDecimal.ZERO);
            analysisVO.setAgeWeightDescription("");
        }
    }

    /**
     * 查询BMI项目区级信息
     *
     * @param analysisVO 返回值对应
     * @param itemCode   项目编号
     */
    private void getBmiItemInfo(BodyShapeAnalysisVO analysisVO, String itemCode) {
        List<TestItemLevel> testItemsLevelList = testItemsMapper.getTestItemsLevelList(itemCode);
        if (CollectionUtils.isNotEmpty(testItemsLevelList)) {
            for (TestItemLevel testItemLevel : testItemsLevelList) {
                if (Objects.nonNull(testItemLevel.getLevelMinScore()) && Objects.nonNull(testItemLevel.getLevelMaxScore())) {
                    if (Objects.nonNull(analysisVO.getBmi()) && analysisVO.getBmi().compareTo(testItemLevel.getLevelMinScore()) >= 0
                            && analysisVO.getBmi().compareTo(testItemLevel.getLevelMaxScore()) <= 0) {
                        analysisVO.setBmiDescription(StringUtils.isBlank(testItemLevel.getLevelName()) ? "" : testItemLevel.getLevelName());
                    }
                }
            }
            analysisVO.setBmiItemLevel(testItemsLevelList);
        }
    }
}
