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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
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.report.CourseTargetWebDto;
import com.qmth.distributed.print.business.bean.dto.report.DimensionDto;
import com.qmth.distributed.print.business.bean.params.ObeCourseTargetExpectValueParam;
import com.qmth.distributed.print.business.bean.params.ObeCourseTargetParam;
import com.qmth.distributed.print.business.bean.result.ObeCourseTargetResult;
import com.qmth.distributed.print.business.bean.result.report.PaperStructDimensionResult;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.CourseDimensionSourceEnum;
import com.qmth.distributed.print.business.enums.CourseSettingTypeEnum;
import com.qmth.distributed.print.business.mapper.ObeCourseTargetMapper;
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.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 课程目标表 服务实现类
 * </p>
 *
 * @author CaoZixuan
 * @since 2024-02-22
 */
@Service
public class ObeCourseTargetServiceImpl extends ServiceImpl<ObeCourseTargetMapper, ObeCourseTarget> implements
        ObeCourseTargetService {

    @Resource
    private ObeCourseDimensionService obeCourseDimensionService;

    @Resource
    private ObeCourseOutlineService obeCourseOutlineService;

    @Resource
    private ExamTaskPaperDataService examTaskPaperDataService;

    @Resource
    private ObeCourseRequirementDimensionService obeCourseRequirementDimensionService;

    @Override
    public List<ObeCourseTargetResult> findCourseTargetList(Long obeCourseOutlineId) {
        ObeCourseOutline courseOutline = obeCourseOutlineService.getById(obeCourseOutlineId);
        if (Objects.isNull(courseOutline)) {
            throw ExceptionResultEnum.ERROR.exception("课程大纲不存在");
        }
        return this.baseMapper.findCourseTargetList(obeCourseOutlineId);
    }

    @Transactional
    @Override
    public void saveCourseTarget(ObeCourseTargetParam obeCourseTargetParam, SysUser requestUser) {
        Long requestUserId = requestUser.getId();
        Long id = obeCourseTargetParam.getId();
        Long obeCourseOutlineId = obeCourseTargetParam.getObeCourseOutlineId();
        ObeCourseOutline courseOutline = obeCourseOutlineService.getById(obeCourseOutlineId);
        if (Objects.isNull(courseOutline)) {
            throw ExceptionResultEnum.ERROR.exception("课程大纲不存在");
        }

        // 指标点
        Long obeCultureProgramRequirementId = obeCourseTargetParam.getObeCultureProgramRequirementId();
        List<Long> dimensionIdList = obeCourseTargetParam.getDimensionIdList();
        String targetName = obeCourseTargetParam.getTargetName();
        String degreeRequirement = obeCourseTargetParam.getDegreeRequirement();

        // 知识点检查
        List<Long> occupiedDimensionIdList = obeCourseRequirementDimensionService.list(new QueryWrapper<ObeCourseRequirementDimension>().lambda()
                        .eq(ObeCourseRequirementDimension::getObeCourseOutlineId, obeCourseOutlineId)
                        .ne(ObeCourseRequirementDimension::getObeCultureProgramRequirementId, obeCultureProgramRequirementId)).stream()
                .map(ObeCourseRequirementDimension::getObeCourseDimensionId).distinct().collect(Collectors.toList());

        if (dimensionIdList.stream().anyMatch(occupiedDimensionIdList::contains)) {
            throw ExceptionResultEnum.ERROR.exception("知识点已被其他指标点占用");
        }

        ObeCourseTarget checkTargetName = this.getOne(new QueryWrapper<ObeCourseTarget>().lambda()
                .eq(ObeCourseTarget::getObeCourseOutlineId, obeCourseOutlineId).eq(ObeCourseTarget::getTargetName, targetName).last(SystemConstant.LIMIT1));
        if (Objects.nonNull(checkTargetName) && !checkTargetName.getId().equals(id)) {
            throw ExceptionResultEnum.ERROR.exception("课程目标名称重复");
        }
        ObeCourseTarget obeCourseTarget = new ObeCourseTarget();
        obeCourseTarget.setObeCourseOutlineId(obeCourseOutlineId);
        obeCourseTarget.setObeCultureProgramRequirementId(obeCultureProgramRequirementId);
        obeCourseTarget.setSchoolId(requestUser.getSchoolId());
        obeCourseTarget.setTargetName(targetName);
        obeCourseTarget.setDegreeRequirement(degreeRequirement);

        if (SystemConstant.longNotNull(id)) {
            // 编辑 (更新教学课程权重标识)
            UpdateWrapper<ObeCourseOutline> obeCourseOutlineUpdateWrapper = new UpdateWrapper<>();
            obeCourseOutlineUpdateWrapper.lambda().eq(ObeCourseOutline::getId, obeCourseOutlineId);

            ObeCourseTarget db = this.getById(id);
            // 指标点下如果存在知识点，判断新增知识点和原知识点是否完全一致
            List<Long> dbDimensionIdList = obeCourseRequirementDimensionService.list(new QueryWrapper<ObeCourseRequirementDimension>().lambda()
                            .eq(ObeCourseRequirementDimension::getObeCourseOutlineId, obeCourseOutlineId)
                            .eq(ObeCourseRequirementDimension::getObeCultureProgramRequirementId, obeCultureProgramRequirementId)).stream()
                    .map(ObeCourseRequirementDimension::getObeCourseDimensionId).distinct().collect(Collectors.toList());

            if (!dimensionIdList.containsAll(dbDimensionIdList) || !dbDimensionIdList.containsAll(dimensionIdList)) {
                // 关联知识点变化 重设知识点，权重md5更新
                obeCourseOutlineUpdateWrapper.lambda()
                        .set(ObeCourseOutline::getDimensionSign, SystemConstant.getDbUuid()).set(ObeCourseOutline::getWeightSettingSign, SystemConstant.getDbUuid());
                obeCourseOutlineService.update(obeCourseOutlineUpdateWrapper);
            }

            // 目标名称描述或绑定指标点变化 更新权重设置标识
            if (!obeCourseTarget.getTargetName().equals(db.getTargetName()) || !Objects.equals(obeCourseTarget.getDegreeRequirement(),
                    db.getDegreeRequirement()) || !Objects.equals(obeCourseTarget.getObeCultureProgramRequirementId(),
                    db.getObeCultureProgramRequirementId())) {
                obeCourseOutlineUpdateWrapper.lambda().set(ObeCourseOutline::getWeightSettingSign, SystemConstant.getDbUuid());
                obeCourseOutlineService.update(obeCourseOutlineUpdateWrapper);
            }

            obeCourseTarget.setId(id);
            obeCourseTarget.setExpectValue(db.getExpectValue());
            obeCourseTarget.updateInfo(requestUserId);
        } else {
            Double expectValue = findExpectValueByCourseOutlineId(obeCourseOutlineId);
            if (Objects.nonNull(expectValue)){
                obeCourseTarget.setExpectValue(expectValue);
            }
            // 新增 (清空权重设置)
            obeCourseOutlineService.update(new UpdateWrapper<ObeCourseOutline>().lambda()
                    .eq(ObeCourseOutline::getId, obeCourseTarget.getObeCourseOutlineId()).set(ObeCourseOutline::getDimensionSign, SystemConstant.getDbUuid()));
            obeCourseOutlineService.clearCourseSetting(obeCourseOutlineId, CourseSettingTypeEnum.COURSE_TARGET);
            obeCourseTarget.insertInfo(requestUserId);
        }
        this.saveOrUpdate(obeCourseTarget);

        // 更新指标点和知识点绑定关系
        obeCourseRequirementDimensionService.remove(new QueryWrapper<ObeCourseRequirementDimension>().lambda()
                .eq(ObeCourseRequirementDimension::getObeCourseOutlineId, obeCourseOutlineId)
                .eq(ObeCourseRequirementDimension::getObeCultureProgramRequirementId, obeCultureProgramRequirementId));
        List<ObeCourseRequirementDimension> willSave = dimensionIdList.stream().flatMap(e -> {
            ObeCourseRequirementDimension obeCourseRequirementDimension = new ObeCourseRequirementDimension();
            obeCourseRequirementDimension.setObeCourseOutlineId(obeCourseOutlineId);
            obeCourseRequirementDimension.setObeCultureProgramRequirementId(obeCultureProgramRequirementId);
            obeCourseRequirementDimension.setObeCourseDimensionId(e);
            obeCourseRequirementDimension.setSchoolId(requestUser.getSchoolId());
            obeCourseRequirementDimension.insertInfo(requestUserId);
            return Stream.of(obeCourseRequirementDimension);
        }).collect(Collectors.toList());
        obeCourseRequirementDimensionService.saveBatch(willSave);
    }

    @Transactional
    @Override
    public void deleteCourseTarget(Long id) {
        ObeCourseTarget obeCourseTarget = this.getById(id);
        if (Objects.nonNull(obeCourseTarget)) {
            obeCourseOutlineService.update(new UpdateWrapper<ObeCourseOutline>().lambda()
                    .eq(ObeCourseOutline::getId, obeCourseTarget.getObeCourseOutlineId()).set(ObeCourseOutline::getDimensionSign, SystemConstant.getDbUuid()));
            obeCourseOutlineService.clearCourseSetting(obeCourseTarget.getObeCourseOutlineId(), CourseSettingTypeEnum.COURSE_TARGET);
            this.removeById(id);
        }
    }

    @Override
    public List<PaperStructDimensionResult> findTikuPaperStruct(Long obeCourseOutlineId, String paperNumber, Long examId) {
        ObeCourseOutline courseOutline = obeCourseOutlineService.getById(obeCourseOutlineId);
        if (Objects.isNull(courseOutline)) {
            throw ExceptionResultEnum.ERROR.exception("课程大纲不存在");
        }
        List<PaperStructDimensionResult> result = new ArrayList<>();

        List<ObeCourseTarget> obeCourseTargetList = this.list(new QueryWrapper<ObeCourseTarget>().lambda().eq(ObeCourseTarget::getObeCourseOutlineId, courseOutline.getId()));
        List<ObeCourseDimension> obeCourseDimensionList = obeCourseDimensionService.list(
                new QueryWrapper<ObeCourseDimension>().lambda().eq(ObeCourseDimension::getObeCourseOutlineId, courseOutline.getId())
                        .eq(ObeCourseDimension::getSource, CourseDimensionSourceEnum.UNION_QUESTION));
        Map<String, ObeCourseDimension> courseDimensionMap = obeCourseDimensionList.stream()
                .collect(Collectors.toMap(ObeCourseDimension::getCode, e -> e));

        ExamTaskPaperData examTaskPaperData = examTaskPaperDataService.getOne(
                new QueryWrapper<ExamTaskPaperData>().lambda().eq(ExamTaskPaperData::getExamId, examId)
                        .eq(ExamTaskPaperData::getPaperNumber, paperNumber).last(SystemConstant.LIMIT1));
        if (Objects.nonNull(examTaskPaperData)) {
            String paperStruct = examTaskPaperData.getPaperJson();
            if (SystemConstant.strNotNull(paperStruct)) {
                JSONObject paperStructJson = JSONObject.parseObject(paperStruct);
                JSONArray detailList = paperStructJson.getJSONArray("details");
                AtomicInteger mainNumberIndex = new AtomicInteger(1);

                for (int d = 0; d < detailList.size(); d++) {
                    int mainNumber = mainNumberIndex.getAndIncrement();
                    JSONObject detail = detailList.getJSONObject(d);
                    JSONArray questionList = detail.getJSONArray("questions");
                    AtomicInteger subNumberIndex = new AtomicInteger(1);
                    for (int q = 0; q < questionList.size(); q++) {

                        JSONObject question = questionList.getJSONObject(q);
                        JSONArray subQuestionList = question.getJSONArray("subQuestions");
                        if (CollectionUtils.isNotEmpty(subQuestionList)) {
                            // 包含套题
                            for (int s = 0; s < subQuestionList.size(); s++) {
                                PaperStructDimensionResult subCell = new PaperStructDimensionResult();

                                JSONObject subQuestion = subQuestionList.getJSONObject(s);
                                Double score = subQuestion.getDouble("score");
                                String property = subQuestion.getString("property");
                                if (SystemConstant.strNotNull(property)) {
                                    List<DimensionDto> dimensionList = JSON.parseArray(property, CourseDimensionDto.class).stream()
                                            .filter(e -> courseDimensionMap.containsKey(e.getCode())).flatMap(e -> {
                                                DimensionDto dimensionDto = new DimensionDto();
                                                dimensionDto.setDimensionId(courseDimensionMap.get(e.getCode()).getId());
                                                dimensionDto.setDimensionCode(e.getCode());
                                                dimensionDto.setDimensionName(e.getName());
                                                return Stream.of(dimensionDto);
                                            }).collect(Collectors.toList());

                                    List<CourseTargetWebDto> courseTargetResultList = this.buildByDimensionList(
                                            obeCourseTargetList, dimensionList);
                                    if (CollectionUtils.isNotEmpty(courseTargetResultList)) {
                                        subCell.setCourseTargetName(courseTargetResultList.get(0).getTargetName());
                                    }
                                    subCell.setTargetList(courseTargetResultList);
                                }
                                subCell.setMainNumber(mainNumber);
                                subCell.setSubNumber(subNumberIndex.getAndIncrement());
                                subCell.setScore(score);
                                result.add(subCell);
                            }

                        } else {
                            // 不包含套题
                            PaperStructDimensionResult cell = new PaperStructDimensionResult();
                            Double score = question.getDouble("score");
                            String property = question.getString("property");
                            if (SystemConstant.strNotNull(property)) {
                                List<DimensionDto> dimensionList = JSON.parseArray(property, CourseDimensionDto.class).stream().filter(e -> courseDimensionMap.containsKey(e.getCode()))
                                        .flatMap(e -> {
                                            DimensionDto dimensionDto = new DimensionDto();
                                            dimensionDto.setDimensionId(courseDimensionMap.get(e.getCode()).getId());
                                            dimensionDto.setDimensionCode(e.getCode());
                                            dimensionDto.setDimensionName(e.getName());
                                            return Stream.of(dimensionDto);
                                        }).collect(Collectors.toList());

                                List<CourseTargetWebDto> courseTargetResultList = this.buildByDimensionList(
                                        obeCourseTargetList, dimensionList);
                                if (CollectionUtils.isNotEmpty(courseTargetResultList)) {
                                    cell.setCourseTargetName(courseTargetResultList.get(0).getTargetName());
                                }
                                cell.setTargetList(courseTargetResultList);

                            }
                            cell.setMainNumber(mainNumber);
                            cell.setSubNumber(subNumberIndex.getAndIncrement());
                            cell.setScore(score);
                            result.add(cell);
                        }
                    }
                }
            }
        }
        return result;
    }

    @Override
    public void settingExpectValue(ObeCourseTargetExpectValueParam obeCourseTargetExpectValueParam, SysUser requestUser) {
        Long obeCourseOutlineId = obeCourseTargetExpectValueParam.getObeCourseOutlineId();
        Double expectValue = obeCourseTargetExpectValueParam.getExpectValue();
        UpdateWrapper<ObeCourseTarget> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(ObeCourseTarget::getObeCourseOutlineId, obeCourseOutlineId).set(ObeCourseTarget::getExpectValue, expectValue)
                .set(ObeCourseTarget::getUpdateId, requestUser.getId()).set(ObeCourseTarget::getUpdateTime, System.currentTimeMillis());
        this.update(updateWrapper);
    }

    /**
     * 根据知识点查询对应的课程目标
     *
     * @param obeCourseTargetDatasource 课程目标数据源
     * @param dimensionDtoList          知识点集合
     * @return 结果
     */
    private List<CourseTargetWebDto> buildByDimensionList(List<ObeCourseTarget> obeCourseTargetDatasource,
            List<DimensionDto> dimensionDtoList) {
        List<CourseTargetWebDto> result = new ArrayList<>();
        for (ObeCourseTarget obeCourseTarget : obeCourseTargetDatasource) {
            Long courseTargetId = obeCourseTarget.getId();
            String targetName = obeCourseTarget.getTargetName();
            // 指标点id
            Long obeCultureProgramRequirementId = obeCourseTarget.getObeCultureProgramRequirementId();

            List<Long> dimensionIdList = obeCourseRequirementDimensionService.list(new QueryWrapper<ObeCourseRequirementDimension>().lambda()
                            .eq(ObeCourseRequirementDimension::getObeCourseOutlineId, obeCourseTarget.getObeCourseOutlineId())
                            .eq(ObeCourseRequirementDimension::getObeCultureProgramRequirementId, obeCultureProgramRequirementId)).stream()
                    .map(ObeCourseRequirementDimension::getObeCourseDimensionId).distinct().collect(Collectors.toList());

            List<DimensionDto> dimensionList = dimensionDtoList.stream().filter(e -> dimensionIdList.contains(e.getDimensionId())).collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(dimensionList)) {
                CourseTargetWebDto courseTargetWebDto = new CourseTargetWebDto();
                courseTargetWebDto.setTargetName(targetName);
                courseTargetWebDto.setTargetId(courseTargetId);
                courseTargetWebDto.setDimensionList(dimensionList);
                result.add(courseTargetWebDto);
            }
        }
        if (result.size() > 1) {
            // 一个试题只能存在于一个目标下
            return new ArrayList<>();
        }
        return result;
    }

    /**
     * 查询预期值
     *
     * @param obeCourseOutlineId 课程大纲id
     * @return 预期值
     */
    private Double findExpectValueByCourseOutlineId(Long obeCourseOutlineId) {
        ObeCourseTarget obeCourseTarget = this.getOne(new QueryWrapper<ObeCourseTarget>().lambda().eq(ObeCourseTarget::getObeCourseOutlineId, obeCourseOutlineId).last(SystemConstant.LIMIT1));
        return Objects.nonNull(obeCourseTarget) ? obeCourseTarget.getExpectValue() : null;
    }
}
