package com.qmth.distributed.print.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.distributed.print.business.bean.dto.CourseDimensionDto;
import com.qmth.distributed.print.business.bean.dto.CourseWeightDetailDto;
import com.qmth.distributed.print.business.bean.dto.CourseWeightDto;
import com.qmth.distributed.print.business.bean.params.ObeCourseWeightParam;
import com.qmth.distributed.print.business.bean.result.ObeCourseEvaluationResult;
import com.qmth.distributed.print.business.bean.result.ObeCourseTargetResult;
import com.qmth.distributed.print.business.bean.result.ObeCourseWeightResult;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.CourseEvaluationTypeEnum;
import com.qmth.distributed.print.business.enums.CourseSettingTypeEnum;
import com.qmth.distributed.print.business.mapper.ObeCourseWeightMapper;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 课程权重设置 服务实现类
 * </p>
 *
 * @author CaoZixuan
 * @since 2024-02-22
 */
@Service
public class ObeCourseWeightServiceImpl extends ServiceImpl<ObeCourseWeightMapper, ObeCourseWeight> implements
        ObeCourseWeightService {

    @Resource
    private ObeCourseOutlineService obeCourseOutlineService;

    @Resource
    private ObeCourseTargetService obeCourseTargetService;

    @Resource
    private ObeCourseEvaluationService obeCourseEvaluationService;

    @Resource
    private ObeCourseRequirementDimensionService obeCourseRequirementDimensionService;

    @Resource
    private ObeCultureProgramRequirementService obeCultureProgramRequirementService;

    @Override
    public ObeCourseWeightResult findCourseWeight(Long obeCourseOutlineId) {
        ObeCourseOutline courseOutline = obeCourseOutlineService.getById(obeCourseOutlineId);
        if (Objects.isNull(courseOutline)) {
            throw ExceptionResultEnum.ERROR.exception("课程大纲不存在");
        }

        // 现有目标
        List<ObeCourseTargetResult> courseTargetList = obeCourseTargetService.findCourseTargetList(obeCourseOutlineId);
        // 现有评价方式
        List<ObeCourseEvaluationResult> obeCourseEvaluationResultList = obeCourseEvaluationService.findCourseEvaluationList(
                obeCourseOutlineId).stream().sorted((o1, o2) -> {
            if (o1.getType().getIndex() == o2.getType().getIndex()) {
                return o1.getEvaluationId() < o2.getEvaluationId() ? -1 : 0;
            } else {
                return o1.getType().getIndex() - o2.getType().getIndex();
            }
        }).collect(Collectors.toList());
        // 现有权重
        List<ObeCourseWeight> obeCourseWeightList = this.list(new QueryWrapper<ObeCourseWeight>().lambda().eq(ObeCourseWeight::getObeCourseOutlineId, obeCourseOutlineId));
        // 权重map
        Map<String, ObeCourseWeight> courseWeightMap = obeCourseWeightList.stream()
                .collect(Collectors.toMap(k -> k.getTargetId() + SystemConstant.HYPHEN + k.getEvaluationId(), v -> v));

        List<CourseWeightDto> submitForm = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(courseTargetList)) {
            for (ObeCourseTargetResult courseTarget : courseTargetList) {
                Long targetId = courseTarget.getId();
                String targetName = courseTarget.getTargetName();
                Long obeCultureProgramRequirementId = courseTarget.getObeCultureProgramRequirementId();
                ObeCultureProgramRequirement obeCultureProgramRequirement = obeCultureProgramRequirementService.getById(
                        obeCultureProgramRequirementId);
                if (Objects.isNull(obeCultureProgramRequirement)) {
                    throw ExceptionResultEnum.ERROR.exception("培养方案毕业要求指标点不存在");
                }

                List<CourseDimensionDto> dimensionList = obeCourseRequirementDimensionService.findByOutlineIdAndRequirementId(
                        obeCourseOutlineId, obeCultureProgramRequirementId);
                String degreeRequirement = courseTarget.getDegreeRequirement();
                BigDecimal totalWeight = courseTarget.getTotalWeight();
                BigDecimal totalScore = new BigDecimal(0);

                List<CourseWeightDetailDto> courseWeightDetailDtoList = new ArrayList<>();
                for (ObeCourseEvaluationResult obeCourseEvaluationResult : obeCourseEvaluationResultList) {
                    Long evaluationId = obeCourseEvaluationResult.getEvaluationId();
                    String evaluationName = obeCourseEvaluationResult.getEvaluation();
                    String key = targetId + SystemConstant.HYPHEN + evaluationId;

                    Boolean enable = false;
                    BigDecimal weight = BigDecimal.ZERO;
                    BigDecimal targetScore = BigDecimal.ZERO;
                    if (courseWeightMap.containsKey(key)) {
                        // 权重表中包含该目标评价的设置 - 获取权重表的数据
                        ObeCourseWeight obeCourseWeight = courseWeightMap.get(key);
                        enable = obeCourseWeight.getEnable();
                        weight = obeCourseWeight.getWeight();
                        targetScore = obeCourseWeight.getTargetScore();
                    }
                    CourseWeightDetailDto detail = new CourseWeightDetailDto();
                    detail.setEvaluationId(evaluationId);
                    detail.setEvaluationName(evaluationName);
                    detail.setEvaluationDesc(obeCourseEvaluationResult.getEvaluationDesc());
                    detail.setEnable(enable);
                    detail.setWeight(weight);
                    detail.setTargetScore(targetScore);
                    detail.setEvaluationType(obeCourseEvaluationResult.getType());
                    if (enable) {
                        totalScore = totalScore.add(targetScore);
                    }
                    courseWeightDetailDtoList.add(detail);
                }

                CourseWeightDto courseWeightDto = new CourseWeightDto();
                courseWeightDto.setCourseTargetId(targetId);
                courseWeightDto.setCourseTargetName(targetName);
                courseWeightDto.setDimensionList(dimensionList);
                courseWeightDto.analyzeDimensionStr();
                courseWeightDto.setDegreeRequirement(degreeRequirement);
                courseWeightDto.setTotalWeight(totalWeight);
                //                courseWeightDto.setTotalScore(totalScore);
                courseWeightDto.setEvaluationList(courseWeightDetailDtoList);
                courseWeightDto.analyzeDimensionStr();
                courseWeightDto.setObeCultureProgramRequirementId(obeCultureProgramRequirementId);
                courseWeightDto.setObeCultureProgramRequirementName(obeCultureProgramRequirement.getName());
                submitForm.add(courseWeightDto);
            }
        }
        ObeCourseWeightResult result = new ObeCourseWeightResult();
        result.setWeightSettingSign(courseOutline.getWeightSettingSign());
        result.setDimensionSign(courseOutline.getDimensionSign());
        result.setSubmitForm(submitForm);
        return result;
    }

    @Transactional
    @Override
    public void saveCourseWeight(ObeCourseWeightParam obeCourseWeightParam, SysUser requestUser) {
        List<String> errorMsgList = new ArrayList<>();
        Long requestUserId = requestUser.getId();
        Long obeCourseOutlineId = obeCourseWeightParam.getObeCourseOutlineId();

        List<CourseWeightDto> submitForm = obeCourseWeightParam.getSubmitForm();

        ObeCourseOutline courseOutline = obeCourseOutlineService.getById(obeCourseOutlineId);
        if (Objects.isNull(courseOutline)) {
            throw ExceptionResultEnum.ERROR.exception("教学课程不存在");
        }

        obeCourseOutlineService.clearCourseSetting(obeCourseOutlineId, CourseSettingTypeEnum.COURSE_WEIGHT);

        List<ObeCourseTarget> obeCourseTargetList = new ArrayList<>();
        List<ObeCourseWeight> obeCourseWeightList = new ArrayList<>();

        // 课程目标整体权重检测
        BigDecimal checkTargetTotalWeight = BigDecimal.ZERO;

        // 一个评价方式必须在一个目标下
        Map<Long, CourseEvaluationTypeEnum> evaluationMap = new HashMap<>();

        for (CourseWeightDto courseWeightDto : submitForm) {
            Long courseTargetId = courseWeightDto.getCourseTargetId();
            ObeCourseTarget obeCourseTarget = obeCourseTargetService.getById(courseTargetId);
            if (Objects.isNull(obeCourseTarget)) {
                throw ExceptionResultEnum.ERROR.exception("课程目标不存在");
            }

            // 目标整体权重
            BigDecimal totalWeight = courseWeightDto.getTotalWeight();
            obeCourseTarget.setTotalWeight(totalWeight);
            obeCourseTarget.updateInfo(requestUserId);
            obeCourseTargetList.add(obeCourseTarget);
            checkTargetTotalWeight = checkTargetTotalWeight.add(totalWeight);

            BigDecimal checkWeight = BigDecimal.ZERO;
            // 评价方式整体权重检测(自定义)
            List<CourseWeightDetailDto> detailDtoList = courseWeightDto.getEvaluationList();
            for (CourseWeightDetailDto detail : detailDtoList) {
                Long evaluationId = detail.getEvaluationId();
                ObeCourseEvaluation obeCourseEvaluation = obeCourseEvaluationService.getById(evaluationId);
                CourseEvaluationTypeEnum evaluationType = obeCourseEvaluation.getType();

                Boolean enable = detail.getEnable();
                BigDecimal weight = detail.getWeight();
                if (enable) {
                    checkWeight = checkWeight.add(weight);
                }

                if (enable && CourseEvaluationTypeEnum.CUSTOM.equals(evaluationType)) {
                    if (evaluationMap.containsKey(evaluationId)) {
                        throw ExceptionResultEnum.ERROR.exception("平时成绩类评价方式只能被一个课程目标使用");
                    } else {
                        evaluationMap.put(evaluationId, evaluationType);
                    }
                }

                ObeCourseWeight obeCourseWeight = new ObeCourseWeight();
                obeCourseWeight.setObeCourseOutlineId(obeCourseOutlineId);
                obeCourseWeight.setSchoolId(requestUser.getSchoolId());
                obeCourseWeight.setTargetId(courseTargetId);
                obeCourseWeight.setEvaluationId(evaluationId);
                obeCourseWeight.setEnable(enable);
                obeCourseWeight.setWeight(weight);
                // 目标分值计算: 3.3.4版本目标分值直接等于权重
                obeCourseWeight.setTargetScore(weight);
                obeCourseWeight.insertInfo(requestUserId);
                obeCourseWeightList.add(obeCourseWeight);
            }
            if (totalWeight.compareTo(checkWeight) != 0) {
                throw ExceptionResultEnum.ERROR.exception(
                        String.format("课程目标[%s]的权重设置有误,各评价方式权重之和不等于整体权重", obeCourseTarget.getTargetName()));
            }
        }

        // 数据校验3:目标整体权重应等于100%，用于计算课程整体达成度。
        int checkTargetTotalWeightCompareResult = checkTargetTotalWeight.compareTo(new BigDecimal(100));
        if (checkTargetTotalWeightCompareResult > 0) {
            errorMsgList.add(
                    String.format("所有课程目标整体权重为[%s],超过[%s]", String.valueOf(checkTargetTotalWeight) + '%', "100%"));
        } else if (checkTargetTotalWeightCompareResult < 0) {
            errorMsgList.add(
                    String.format("所有课程目标整体权重为[%s],低于[%s]", String.valueOf(checkTargetTotalWeight) + '%', "100%"));
        }
        if (CollectionUtils.isNotEmpty(errorMsgList)) {
            throw ExceptionResultEnum.ERROR.exception(String.join(";", errorMsgList));
        }

        // 更新目标整体权重
        obeCourseTargetService.updateBatchById(obeCourseTargetList);
        // 保存课程权重设置
        this.saveBatch(obeCourseWeightList);
        // 更新课程权重设置状态
        courseOutline.setWeightSetting(true);
        courseOutline.setWeightSettingSign(SystemConstant.getDbUuid());
        obeCourseOutlineService.updateById(courseOutline);
    }

    @Transactional
    @Override
    public void deleteCourseWeight(Long obeCourseOutlineId) {
        this.remove(new QueryWrapper<ObeCourseWeight>().lambda().eq(ObeCourseWeight::getObeCourseOutlineId, obeCourseOutlineId));
        UpdateWrapper<ObeCourseTarget> courseTargetUpdateWrapper = new UpdateWrapper<>();
        courseTargetUpdateWrapper.lambda().eq(ObeCourseTarget::getObeCourseOutlineId, obeCourseOutlineId)
                .set(ObeCourseTarget::getTotalWeight, null);
        obeCourseTargetService.update(courseTargetUpdateWrapper);

        UpdateWrapper<ObeCourseOutline> obeCourseOutlineUpdateWrapper = new UpdateWrapper<>();
        obeCourseOutlineUpdateWrapper.lambda().eq(ObeCourseOutline::getId, obeCourseOutlineId)
                .set(ObeCourseOutline::getWeightSettingSign, null);
        obeCourseOutlineService.update(obeCourseOutlineUpdateWrapper);
    }
}