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.CourseDimensionOccupiedDto;
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.CourseTargetParam;
import com.qmth.distributed.print.business.bean.result.CourseDimensionTree;
import com.qmth.distributed.print.business.bean.result.CourseTargetResult;
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.CourseTargetMapper;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.base.BaseEntity;
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.*;
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 CourseTargetServiceImpl extends ServiceImpl<CourseTargetMapper, CourseTarget> implements CourseTargetService {

    @Resource
    private TeachCourseService teachCourseService;

    @Resource
    private CourseDimensionService courseDimensionService;

    @Resource
    private ExamTaskPaperDataService examTaskPaperDataService;

    @Override
    public List<CourseTargetResult> findCourseTargetList(Long teachCourseId) {
        TeachCourse teachCourse = teachCourseService.getById(teachCourseId);
        if (Objects.isNull(teachCourse)) {
            throw ExceptionResultEnum.ERROR.exception("教学课程不存在");
        }
        List<CourseTarget> courseTargetList = this.list(
                new QueryWrapper<CourseTarget>().lambda().eq(CourseTarget::getTeachCourseId, teachCourse.getId()).orderByAsc(CourseTarget::getId));

        List<CourseDimension> courseDimensionList = courseDimensionService.list(
                new QueryWrapper<CourseDimension>().lambda().eq(CourseDimension::getTeachCourseId, teachCourseId));

        Map<Long, CourseDimension> courseDimensionMap = courseDimensionList.stream()
                .collect(Collectors.toMap(CourseDimension::getId, e -> e));

        return courseTargetList.stream().flatMap(e -> {
            CourseTargetResult cell = new CourseTargetResult();
            cell.setId(e.getId());
            cell.setTargetName(e.getTargetName());
            cell.setDegreeRequirement(e.getDegreeRequirement());
            cell.setTotalWeight(e.getTotalWeight());
            String targetContent = e.getTargetContent();
            List<Long> dimensionIdList = JSON.parseArray(targetContent, Long.class);
            List<CourseDimensionDto> dimensionList = new ArrayList<>();
            if (SystemConstant.strNotNull(targetContent)) {
                dimensionIdList.forEach(d -> {
                    CourseDimensionDto courseDimensionDto = new CourseDimensionDto();
                    CourseDimension courseDimension = courseDimensionMap.get(d);
                    courseDimensionDto.setId(d);
                    courseDimensionDto.setCode(courseDimension.getCode());
                    courseDimensionDto.setName(courseDimension.getName());
                    dimensionList.add(courseDimensionDto);
                });
            }
            cell.setDimensionList(dimensionList);
            return Stream.of(cell);
        }).collect(Collectors.toList());
    }

    @Override
    public List<CourseDimensionTree> findDimensionTree(Long teachCourseId) {
        TeachCourse teachCourse = teachCourseService.getById(teachCourseId);
        if (Objects.isNull(teachCourse)) {
            throw ExceptionResultEnum.ERROR.exception("教学课程不存在");
        }

        // 课程目标
        List<CourseTarget> courseTargetList = this.list(
                new QueryWrapper<CourseTarget>().lambda().eq(CourseTarget::getTeachCourseId, teachCourse.getId()));

        // 课程目标id - 该目标包含的所有知识点id集合
        Map<Long, List<Long>> targetDimensionMap = courseTargetList.stream()
                .collect(Collectors.toMap(BaseEntity::getId, v -> {
                    List<Long> dimensionList = new ArrayList<>();
                    String targetContent = v.getTargetContent();
                    if (SystemConstant.strNotNull(targetContent)) {
                        dimensionList = JSON.parseArray(targetContent, Long.class);
                    }
                    return dimensionList;
                }));

        // 课程知识点
        List<CourseDimension> courseDimensionList = courseDimensionService.list(
                new QueryWrapper<CourseDimension>().lambda().eq(CourseDimension::getTeachCourseId, teachCourseId));

        List<CourseDimension> firstDimensionList = courseDimensionList.stream().filter(e -> e.getParentId() == 0).sorted(Comparator.comparingInt(CourseDimension::getNumber)).collect(Collectors.toList());

        List<CourseDimensionTree> treeList = new ArrayList<>();
        for (CourseDimension first : firstDimensionList) {
            Long id = first.getId();
            String code = first.getCode();
            String name = first.getName();
            CourseDimensionOccupiedDto occupied = this.buildCourseDimensionOccupiedDto(targetDimensionMap, id);
            List<CourseDimensionTree> children = new ArrayList<>();

            List<CourseDimension> secondDimensionList = courseDimensionList.stream().filter(e -> id.equals(e.getParentId())).sorted(Comparator.comparingInt(CourseDimension::getNumber))
                    .collect(Collectors.toList());
            for (CourseDimension child : secondDimensionList) {
                Long childId = child.getId();
                String childCode = child.getCode();
                String childName = child.getName();
                CourseDimensionOccupiedDto childOccupied = this.buildCourseDimensionOccupiedDto(targetDimensionMap,
                        childId);

                CourseDimensionTree tree = new CourseDimensionTree(childId, childCode, childName, childOccupied, new ArrayList<>());
                children.add(tree);
            }
            CourseDimensionTree tree = new CourseDimensionTree(id, code, name, occupied, children);
            treeList.add(tree);
        }
        return treeList;
    }

    @Transactional
    @Override
    public void saveCourseTarget(CourseTargetParam courseTargetParam, SysUser requestUser) {
        Long requestUserId = requestUser.getId();
        Long id = courseTargetParam.getId();
        Long teachCourseId = courseTargetParam.getTeachCourseId();
        TeachCourse teachCourse = teachCourseService.getById(teachCourseId);
        if (Objects.isNull(teachCourse)) {
            throw ExceptionResultEnum.ERROR.exception("教学课程不存在");
        }

        Long examId = teachCourse.getExamId();
        String courseCode = teachCourse.getCourseCode();
        String targetName = courseTargetParam.getTargetName();
        String degreeRequirement = courseTargetParam.getDegreeRequirement();
        List<Long> dimensionIdList = courseTargetParam.getDimensionIdList();

        // 知识点检查
        Map<Long, CourseDimension> courseDimensionMap = courseDimensionService.list(
                new QueryWrapper<CourseDimension>().lambda().eq(CourseDimension::getTeachCourseId, teachCourseId)).stream().collect(Collectors.toMap(BaseEntity::getId,
                v -> v));

        QueryWrapper<CourseTarget> courseTargetQueryWrapper = new QueryWrapper<>();
        if (Objects.isNull(id)) {
            courseTargetQueryWrapper.lambda().eq(CourseTarget::getTeachCourseId, teachCourseId);
        } else {
            courseTargetQueryWrapper.lambda().ne(CourseTarget::getId, id);
        }
        List<CourseTarget> courseTargetResultList = this.list(courseTargetQueryWrapper);

        // 占用的知识点id
        List<Long> occupiedIdList = courseTargetResultList.stream().flatMap(e -> {
            List<Long> idList = new ArrayList<>();
            String content = e.getTargetContent();
            if (SystemConstant.strNotNull(content)) {
                idList = JSON.parseArray(content, Long.class);
            }
            return idList.stream();
        }).collect(Collectors.toList());
        for (Long dimensionId : dimensionIdList) {
            if (!courseDimensionMap.containsKey(dimensionId)) {
                throw ExceptionResultEnum.ERROR.exception("知识点不存在");
            }
            if (occupiedIdList.contains(dimensionId)) {
                throw ExceptionResultEnum.ERROR.exception(String.format("知识点[%s]已经被别的课程目标占用",
                        courseDimensionMap.get(dimensionId).getName() + "(" + courseDimensionMap.get(dimensionId).getCode() + ")"));
            }
        }

        CourseTarget checkTargetName = this.getOne(
                new QueryWrapper<CourseTarget>().lambda().eq(CourseTarget::getTeachCourseId, teachCourseId).eq(CourseTarget::getTargetName, targetName).last(SystemConstant.LIMIT1));
        if (Objects.nonNull(checkTargetName) && !checkTargetName.getId().equals(id)) {
            throw ExceptionResultEnum.ERROR.exception("课程目标名称重复");
        }
        CourseTarget courseTarget = new CourseTarget();
        courseTarget.setTeachCourseId(teachCourseId);
        courseTarget.setSchoolId(requestUser.getSchoolId());
        courseTarget.setExamId(examId);
        courseTarget.setCourseCode(courseCode);
        courseTarget.setUserId(requestUserId);
        courseTarget.setTargetName(targetName);
        courseTarget.setDegreeRequirement(degreeRequirement);
        courseTarget.setTargetContent(JSON.toJSONString(dimensionIdList));

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

            CourseTarget db = this.getById(id);
            String dbContent = db.getTargetContent();
            if (SystemConstant.strNotNull(dbContent)) {
                List<Long> dbDimensionList = JSON.parseArray(dbContent, Long.class);
                if (!dimensionIdList.containsAll(dbDimensionList) || !dbDimensionList.containsAll(dimensionIdList)) {
                    // 关联知识点变化 重设知识点，权重md5更新
                    teachCourseUpdateWrapper.lambda().set(TeachCourse::getDimensionSign, SystemConstant.getDbUuid())
                            .set(TeachCourse::getWeightSettingSign, SystemConstant.getDbUuid());
                    teachCourseService.update(teachCourseUpdateWrapper);
                }
            }
            // 目标描述变了 更新权重设置标识
            if (!courseTarget.getTargetName().equals(db.getTargetName()) || !Objects.equals(courseTarget.getDegreeRequirement(),
                    db.getDegreeRequirement())) {
                teachCourseUpdateWrapper.lambda().set(TeachCourse::getWeightSettingSign, SystemConstant.getDbUuid());
                teachCourseService.update(teachCourseUpdateWrapper);
            }

            courseTarget.setId(id);
            courseTarget.updateInfo(requestUserId);
        } else {
            // 新增 (清空权重设置)
            teachCourseService.update(
                    new UpdateWrapper<TeachCourse>().lambda().eq(TeachCourse::getId, courseTarget.getTeachCourseId()).set(TeachCourse::getDimensionSign, SystemConstant.getDbUuid()));
            teachCourseService.clearCourseSetting(teachCourseId, CourseSettingTypeEnum.COURSE_TARGET);
            courseTarget.insertInfo(requestUserId);
        }
        this.saveOrUpdate(courseTarget);
    }

    @Transactional
    @Override
    public void deleteCourseTarget(Long id) {
        CourseTarget courseTarget = this.getById(id);
        if (Objects.nonNull(courseTarget)) {
            teachCourseService.update(
                    new UpdateWrapper<TeachCourse>().lambda().eq(TeachCourse::getId, courseTarget.getTeachCourseId()).set(TeachCourse::getDimensionSign, SystemConstant.getDbUuid()));
            teachCourseService.clearCourseSetting(courseTarget.getTeachCourseId(), CourseSettingTypeEnum.COURSE_TARGET);
            this.removeById(id);
        }
    }

    @Override
    public List<PaperStructDimensionResult> findTikuPaperStruct(Long teachCourseId, String paperNumber) {
        TeachCourse teachCourse = teachCourseService.getById(teachCourseId);
        if (Objects.isNull(teachCourse)) {
            throw ExceptionResultEnum.ERROR.exception("教学课程不存在");
        }
        List<PaperStructDimensionResult> result = new ArrayList<>();

        List<CourseTarget> courseTargetList = this.list(
                new QueryWrapper<CourseTarget>().lambda().eq(CourseTarget::getTeachCourseId, teachCourse.getId()));
        List<CourseDimension> courseDimensionList = courseDimensionService.list(
                new QueryWrapper<CourseDimension>().lambda().eq(CourseDimension::getTeachCourseId, teachCourse.getId())
                        .eq(CourseDimension::getSource, CourseDimensionSourceEnum.UNION_QUESTION));
        Map<String, CourseDimension> courseDimensionMap = courseDimensionList.stream()
                .collect(Collectors.toMap(CourseDimension::getCode, e -> e));

        ExamTaskPaperData examTaskPaperData = examTaskPaperDataService.getOne(
                new QueryWrapper<ExamTaskPaperData>().lambda().eq(ExamTaskPaperData::getExamId, teachCourse.getExamId())
                        .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(
                                            courseTargetList, 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(
                                        courseTargetList, 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;
    }

    /**
     * 构建知识点占用情况对象
     *
     * @param targetDimensionMap 目标知识点map
     * @param courseDimensionId  课程知识点id
     * @return 占用情况
     */
    private CourseDimensionOccupiedDto buildCourseDimensionOccupiedDto(Map<Long, List<Long>> targetDimensionMap,
            Long courseDimensionId) {
        CourseDimensionOccupiedDto dto = new CourseDimensionOccupiedDto();
        for (Long targetId : targetDimensionMap.keySet()) {
            List<Long> dimensionList = targetDimensionMap.get(targetId);
            if (dimensionList.contains(courseDimensionId)) {
                dto.setCourseTargetId(targetId);
                dto.setStatus(true);
                return dto;
            }
        }
        dto.setStatus(false);
        return dto;
    }

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

            String content = courseTarget.getTargetContent();
            List<Long> dimensionIdList = JSON.parseArray(content, Long.class);
            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;
    }
}
