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

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.distributed.print.business.bean.dto.CourseDimensionImportDto;
import com.qmth.distributed.print.business.bean.dto.CourseDimensionMd5Dto;
import com.qmth.distributed.print.business.entity.CourseDimension;
import com.qmth.distributed.print.business.entity.TeachCourse;
import com.qmth.distributed.print.business.enums.CourseDimensionCodeEnum;
import com.qmth.distributed.print.business.enums.CourseDimensionSourceEnum;
import com.qmth.distributed.print.business.enums.CourseSettingTypeEnum;
import com.qmth.distributed.print.business.mapper.CourseDimensionMapper;
import com.qmth.distributed.print.business.service.BasicExamService;
import com.qmth.distributed.print.business.service.CourseDimensionService;
import com.qmth.distributed.print.business.service.TeachCourseService;
import com.qmth.teachcloud.common.bean.result.ExcelResult;
import com.qmth.teachcloud.common.bean.tiku.TikuCourseProperty;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicExam;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.kit.TikuUtils;
import com.qmth.teachcloud.common.util.ConvertUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

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-27
 */
@Service
public class CourseDimensionServiceImpl extends ServiceImpl<CourseDimensionMapper, CourseDimension> implements CourseDimensionService {

    @Resource
    TeachCourseService teachCourseService;

    @Resource
    BasicExamService basicExamService;

    @Resource
    TikuUtils tikuUtils;

    @Transactional
    @Override
    public void importCourseDimension(SysUser requestUser, MultipartFile file, Long teachCourseId) throws Exception {
        Long requestUserId = requestUser.getId();
        Long schoolId = requestUser.getSchoolId();

        TeachCourse teachCourse = teachCourseService.getById(teachCourseId);
        if (Objects.isNull(teachCourse)) {
            throw ExceptionResultEnum.ERROR.exception("教学课程不存在");
        }
        Long examId = teachCourse.getExamId();
        String courseCode = teachCourse.getCourseCode();

        BasicExam basicExam = basicExamService.getById(examId);
        if (Objects.isNull(basicExam)) {
            throw ExceptionResultEnum.ERROR.exception("考试不存在");
        }
        Long semesterId = SystemConstant.convertIdToLong(basicExam.getSemesterId());

        ExcelResult<CourseDimensionImportDto> excelResult = ConvertUtil.analyzeExcel(file.getInputStream(),
                CourseDimensionImportDto.class, false, 1);
        List<CourseDimensionImportDto> courseDimensionImportDtoList = excelResult.getDatasource();
        boolean success = excelResult.isSuccess();
        if (!success) {
            throw ExceptionResultEnum.ERROR.exception(excelResult.getErrorMsg());
        }

        // 处理要新增的考察点
        Map<String, List<String>> dimensionMap = new LinkedHashMap<>();
        for (CourseDimensionImportDto courseDimensionImportDto : courseDimensionImportDtoList) {
            String firstDimensionName = courseDimensionImportDto.getFirstDimensionName();
            if (!SystemConstant.strNotNull(firstDimensionName)) {
                throw ExceptionResultEnum.ERROR.exception("excel中存在没有填写的一级知识点");
            }
            String secondDimensionName = courseDimensionImportDto.getSecondDimensionName();

            if (dimensionMap.containsKey(firstDimensionName)) {
                if (SystemConstant.strNotNull(secondDimensionName)) {
                    List<String> sl = dimensionMap.get(firstDimensionName);
                    if (!sl.contains(secondDimensionName)) {
                        sl.add(secondDimensionName);
                        dimensionMap.put(firstDimensionName, sl);
                    }
                }
            } else {
                List<String> sl = new ArrayList<>();
                if (SystemConstant.strNotNull(secondDimensionName)) {
                    sl.add(secondDimensionName);
                }
                dimensionMap.put(firstDimensionName, sl);
            }
        }
        CourseDimension temp = new CourseDimension();
        temp.setTeachCourseId(teachCourseId);
        temp.setSchoolId(schoolId);
        temp.setSemesterId(semesterId);
        temp.setExamId(examId);
        temp.setCourseCode(courseCode);
        temp.setUserId(teachCourse.getUserId());
        temp.setSource(CourseDimensionSourceEnum.IMPORT);

        List<CourseDimension> willSaveDimensions = new ArrayList<>();

        AtomicInteger firstNumber = new AtomicInteger(0);
        for (String firstDimensionName : dimensionMap.keySet()) {
            CourseDimension first = new CourseDimension();
            int index = firstNumber.incrementAndGet();
            BeanUtils.copyProperties(temp, first);
            String firstCode = CourseDimensionCodeEnum.getCodeByIndex(index);
            first.setCode(firstCode);
            first.setName(firstDimensionName);
            first.setNumber(index);
            first.insertInfo(requestUserId);
            first.setParentId(0L);
            willSaveDimensions.add(first);

            List<String> secondDimensionList = dimensionMap.get(firstDimensionName);
            Long firstId = first.getId();
            for (int i = 0; i < secondDimensionList.size(); i++) {
                CourseDimension second = new CourseDimension();
                int secondIndex = i + 1;
                BeanUtils.copyProperties(temp, second);
                String secondCode = firstCode + secondIndex;
                second.setCode(secondCode);
                second.setName(secondDimensionList.get(i));
                second.setNumber(secondIndex);
                second.insertInfo(requestUserId);
                second.setParentId(firstId);
                willSaveDimensions.add(second);
            }
        }
        List<CourseDimension> dbList = this.list(
                new QueryWrapper<CourseDimension>().lambda().eq(CourseDimension::getTeachCourseId, teachCourseId));
        String dbMd5 = this.buildCourseDimensionMd5(dbList);
        String willAddMd5 = this.buildCourseDimensionMd5(willSaveDimensions);
        if (!willAddMd5.equals(dbMd5)) {
            // 删除课程设置
            teachCourseService.clearCourseSetting(teachCourseId, CourseSettingTypeEnum.COURSE_DIMENSION);
            this.saveBatch(willSaveDimensions);
        }
    }

    @Transactional
    @Override
    public void syncTikuCourseProperties(Long teachCourseId) {
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        Long requestUserId = requestUser.getId();
        TeachCourse teachCourse = teachCourseService.getById(teachCourseId);
        if (Objects.isNull(teachCourse)) {
            throw ExceptionResultEnum.ERROR.exception("教学课程不存在");
        }
        Long examId = teachCourse.getExamId();
        String courseCode = teachCourse.getCourseCode();
        Long schoolId = teachCourse.getSchoolId();
        BasicExam basicExam = basicExamService.getById(examId);
        if (Objects.isNull(basicExam)) {
            throw ExceptionResultEnum.ERROR.exception("考试不存在");
        }
        Long semesterId = SystemConstant.convertIdToLong(basicExam.getSemesterId());

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

        if (courseDimensionList.stream().noneMatch(e -> CourseDimensionSourceEnum.IMPORT.equals(e.getSource()))) {
            // 表里没有导入的知识点记录,从题库获取
            List<TikuCourseProperty> tikuDimensionList = tikuUtils.listCourseProperty(teachCourse.getSchoolId(),
                    courseCode);
            if (CollectionUtils.isNotEmpty(tikuDimensionList)) {
                CourseDimension temp = new CourseDimension();
                temp.setTeachCourseId(teachCourseId);
                temp.setSchoolId(schoolId);
                temp.setSemesterId(semesterId);
                temp.setExamId(examId);
                temp.setCourseCode(courseCode);
                temp.setUserId(teachCourse.getUserId());
                temp.setSource(CourseDimensionSourceEnum.UNION_QUESTION);
                List<CourseDimension> willAddList = new ArrayList<>();

                for (TikuCourseProperty first : tikuDimensionList) {
                    Long fParentId = first.getParentId();
                    if (fParentId > 0) {
                        throw ExceptionResultEnum.ERROR.exception("题库一级知识点父id异常");
                    }
                    String fName = first.getName();
                    String fCode = first.getCode();
                    int fNumber = Integer.parseInt(first.getNumber());

                    CourseDimension willAddFirst = new CourseDimension();
                    BeanUtils.copyProperties(temp, willAddFirst);
                    willAddFirst.setCode(fCode);
                    willAddFirst.setName(fName);
                    willAddFirst.setNumber(fNumber);
                    willAddFirst.insertInfo(requestUserId);
                    willAddFirst.setParentId(0L);
                    willAddList.add(willAddFirst);

                    List<TikuCourseProperty> secondList = first.getPropertyList();
                    for (TikuCourseProperty second : secondList) {
                        Long sParentId = willAddFirst.getId();
                        String sName = second.getName();
                        String sCode = second.getCode();
                        int sNumber = Integer.parseInt(second.getNumber());

                        CourseDimension willAddSecond = new CourseDimension();
                        BeanUtils.copyProperties(temp, willAddSecond);
                        willAddSecond.setCode(sCode);
                        willAddSecond.setName(sName);
                        willAddSecond.setNumber(sNumber);
                        willAddSecond.insertInfo(requestUserId);
                        willAddSecond.setParentId(sParentId);
                        willAddList.add(willAddSecond);
                    }
                }

                if (CollectionUtils.isNotEmpty(willAddList)) {
                    String dbMd5 = this.buildCourseDimensionMd5(courseDimensionList.stream().filter(e -> CourseDimensionSourceEnum.UNION_QUESTION.equals(e.getSource()))
                            .collect(Collectors.toList()));
                    String willAddMd5 = this.buildCourseDimensionMd5(willAddList);
                    if (!willAddMd5.equals(dbMd5)) {
                        // 如果题库知识点和之前的题库知识点不一致，删除原先的并新增
                        teachCourseService.clearCourseSetting(teachCourseId, CourseSettingTypeEnum.COURSE_DIMENSION);
                        this.saveBatch(willAddList);
                    }
                }
            }
        }
    }

    /**
     * 构建知识点md5
     *
     * @param courseDimensionList 课程知识点集合
     * @return MD5
     */
    private String buildCourseDimensionMd5(List<CourseDimension> courseDimensionList) {
        List<CourseDimensionMd5Dto> md5List = courseDimensionList.stream().flatMap(e -> {
            CourseDimensionMd5Dto dto = new CourseDimensionMd5Dto();
            dto.setCode(e.getCode());
            dto.setName(e.getName());
            dto.setNumber(e.getNumber());
            dto.setSource(e.getSource());
            return Stream.of(dto);
        }).sorted(Comparator.comparing(CourseDimensionMd5Dto::getCode)).collect(Collectors.toList());
        System.out.println(JSON.toJSONString(md5List));
        return DigestUtils.md5Hex(JSON.toJSONString(md5List));
    }
}
