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

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.qmth.distributed.print.business.bean.dto.excel.GradePaperDimensionAbilityDto;
import com.qmth.distributed.print.business.bean.dto.excel.GradePaperDimensionKnowledgeDto;
import com.qmth.distributed.print.business.bean.dto.open.PaperDimension;
import com.qmth.distributed.print.business.bean.params.analyze.GradePaperDimensionDatasource;
import com.qmth.distributed.print.business.bean.params.analyze.GradePaperDimensionParam;
import com.qmth.distributed.print.business.bean.result.analyze.GradePaperDimensionResult;
import com.qmth.distributed.print.business.bean.result.analyze.SecondDimensionResult;
import com.qmth.distributed.print.business.entity.GradePaperDimension;
import com.qmth.teachcloud.common.enums.DimensionEnum;
import com.qmth.distributed.print.business.mapper.GradePaperDimensionMapper;
import com.qmth.distributed.print.business.service.GradeBatchPaperService;
import com.qmth.distributed.print.business.service.GradePaperDimensionService;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.util.ExcelUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 分析-考察点维度表 服务实现类
 * </p>
 *
 * @author wangliang
 * @since 2022-05-20
 */
@Service
public class GradePaperDimensionServiceImpl extends ServiceImpl<GradePaperDimensionMapper, GradePaperDimension> implements GradePaperDimensionService {
    @Resource
    private GradeBatchPaperService gradeBatchPaperService;

    @Override
    public List<GradePaperDimensionResult> findGradePaperDimensionList(String paperNumber, String paperType, SysUser requestUser) {
        return this.baseMapper.findGradePaperDimensionList(paperNumber, paperType, requestUser.getSchoolId());
    }

    @Override
    public void saveGradePaperDimensionBatch(GradePaperDimensionParam gradePaperDimensionParam, SysUser requestUser) {
        String paperNumber = gradePaperDimensionParam.getPaperNumber();
        String paperType = gradePaperDimensionParam.getPaperType();
        String paperName = gradePaperDimensionParam.getPaperName();
        DimensionEnum dimensionType = gradePaperDimensionParam.getDimensionType();
        List<GradePaperDimensionDatasource> datasource = gradePaperDimensionParam.getDatasource();
        gradeBatchPaperService.checkOperateAuth(requestUser.getSchoolId(), paperNumber, paperType);
        List<GradePaperDimension> gradePaperDimensionList = this.checkAndBuildGradePaperDimensionList(datasource, paperNumber, paperType, paperName, dimensionType, requestUser);
        this.remove(new QueryWrapper<GradePaperDimension>().lambda()
                .eq(GradePaperDimension::getSchoolId, requestUser.getSchoolId())
                .eq(GradePaperDimension::getPaperNumber, paperNumber)
                .eq(GradePaperDimension::getPaperType, paperType)
                .eq(GradePaperDimension::getDimensionType, dimensionType));
        this.saveBatch(gradePaperDimensionList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importGradePaperKnowledgeDimension(MultipartFile file, String paperNumber, String paperType, String paperName, SysUser requestUser) throws IOException, NoSuchFieldException {
        if (Objects.isNull(file)) {
            throw ExceptionResultEnum.ERROR.exception("找不到附件");
        }

        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(GradePaperDimensionKnowledgeDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            if (finalExcelErrorList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
            }
            return finalExcelList;
        });
        List<GradePaperDimensionDatasource> gradePaperDimensionDatasourceList = new ArrayList<>();

        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> importList = map.get(i);

                for (int y = 0; y < Objects.requireNonNull(importList).size(); y++) {
                    if (importList.get(y) instanceof GradePaperDimensionKnowledgeDto) {
                        GradePaperDimensionKnowledgeDto gradePaperDimensionKnowledgeDto = (GradePaperDimensionKnowledgeDto) importList.get(y);

                        GradePaperDimensionDatasource gradePaperDimensionDatasource = new GradePaperDimensionDatasource();
                        gradePaperDimensionDatasource.setCodePrimary(gradePaperDimensionKnowledgeDto.getCodePrimary());
                        gradePaperDimensionDatasource.setNamePrimary(gradePaperDimensionKnowledgeDto.getNamePrimary());
                        gradePaperDimensionDatasource.setCodeSecond(gradePaperDimensionKnowledgeDto.getCodeSecond());
                        gradePaperDimensionDatasource.setNameSecond(gradePaperDimensionKnowledgeDto.getNameSecond());
                        gradePaperDimensionDatasourceList.add(gradePaperDimensionDatasource);
                    }
                }
            }
        }
        GradePaperDimensionParam gradePaperDimensionParam = new GradePaperDimensionParam();
        gradePaperDimensionParam.setDatasource(gradePaperDimensionDatasourceList);
        gradePaperDimensionParam.setPaperNumber(paperNumber);
        gradePaperDimensionParam.setPaperType(paperType);
        gradePaperDimensionParam.setPaperName(paperName);
        gradePaperDimensionParam.setDimensionType(DimensionEnum.KNOWLEDGE);
        this.saveGradePaperDimensionBatch(gradePaperDimensionParam, requestUser);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importGradePaperAbilityDimension(MultipartFile file, String paperNumber, String paperType, String paperName, SysUser requestUser) throws IOException, NoSuchFieldException {
        if (Objects.isNull(file)) {
            throw ExceptionResultEnum.ERROR.exception("找不到附件");
        }

        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(GradePaperDimensionAbilityDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            if (finalExcelErrorList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
            }
            return finalExcelList;
        });
        List<GradePaperDimensionDatasource> gradePaperDimensionDatasourceList = new ArrayList<>();

        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> importList = map.get(i);

                for (int y = 0; y < Objects.requireNonNull(importList).size(); y++) {
                    if (importList.get(y) instanceof GradePaperDimensionAbilityDto) {
                        GradePaperDimensionAbilityDto gradePaperDimensionAbilityDto = (GradePaperDimensionAbilityDto) importList.get(y);

                        GradePaperDimensionDatasource gradePaperDimensionDatasource = new GradePaperDimensionDatasource();
                        gradePaperDimensionDatasource.setCodePrimary(gradePaperDimensionAbilityDto.getCodePrimary());
                        gradePaperDimensionDatasource.setNamePrimary(gradePaperDimensionAbilityDto.getNamePrimary());
                        gradePaperDimensionDatasource.setInterpretation(gradePaperDimensionAbilityDto.getInterpret());
                        gradePaperDimensionDatasourceList.add(gradePaperDimensionDatasource);
                    }
                }
            }
        }
        GradePaperDimensionParam gradePaperDimensionParam = new GradePaperDimensionParam();
        gradePaperDimensionParam.setDatasource(gradePaperDimensionDatasourceList);
        gradePaperDimensionParam.setPaperNumber(paperNumber);
        gradePaperDimensionParam.setPaperType(paperType);
        gradePaperDimensionParam.setPaperName(paperName);
        gradePaperDimensionParam.setDimensionType(DimensionEnum.ABILITY);
        this.saveGradePaperDimensionBatch(gradePaperDimensionParam, requestUser);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void exportGradePaperDimensionTemplate(String courseCode, String courseName, DimensionEnum dimensionType) throws Exception {
        switch (dimensionType) {
            case KNOWLEDGE:
                List<GradePaperDimensionKnowledgeDto> kDatasource = new ArrayList<>();
                GradePaperDimensionKnowledgeDto kCell = new GradePaperDimensionKnowledgeDto();
                kCell.setCourseCode(courseCode);
                kCell.setCourseName(courseName);
                kDatasource.add(kCell);
                ExcelUtil.excelExport(courseName + "-知识维度导入模板", GradePaperDimensionKnowledgeDto.class, kDatasource, ServletUtil.getResponse());
                break;
            case ABILITY:
                List<GradePaperDimensionAbilityDto> aDatasource = new ArrayList<>();
                GradePaperDimensionAbilityDto aCell = new GradePaperDimensionAbilityDto();
                aCell.setCourseCode(courseCode);
                aCell.setCourseName(courseName);
                aDatasource.add(aCell);
                ExcelUtil.excelExport(courseName + "-能力维度导入模板", GradePaperDimensionAbilityDto.class, aDatasource, ServletUtil.getResponse());
                break;
        }
    }

    @Override
    public List<SecondDimensionResult> findSecondDimensionList(String paperNumber, String paperType, DimensionEnum dimensionType, SysUser requestUser) {
        return this.list(new QueryWrapper<GradePaperDimension>()
                        .lambda()
                        .eq(GradePaperDimension::getSchoolId, requestUser.getSchoolId())
                        .eq(GradePaperDimension::getPaperNumber, paperNumber)
                        .eq(GradePaperDimension::getPaperType, paperType)
                        .eq(GradePaperDimension::getDimensionType, dimensionType))
                .stream()
                .distinct()
                .flatMap(e -> {
                    SecondDimensionResult cell = new SecondDimensionResult();
                    cell.setCode(e.getCodeSecond());
                    cell.setName(e.getNameSecond());
                    cell.setType(e.getDimensionType());
                    return Stream.of(cell);
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<PaperDimension> findBySchoolIdAndPaperNumberAndPaperType(Long schoolId, String paperNumber, String paperType) {
        return this.baseMapper.findBySchoolIdAndPaperNumberAndPaperType(schoolId, paperNumber, paperType);
    }

    /**
     * 检查并构建维度新增参数集合
     * <p>
     * 1.一级维度编号必须为大写A-Z
     * 2.一级维度编号和名称在数据集中必须对应一致
     * 3.二级维度编号必须首字符和一级维度编号一致，后续字符为正整数
     * 4.二级维度编号在数据集中唯一
     * </p>
     *
     * @param gradePaperDimensionDatasourceList 分析试卷维度集合
     * @param paperNumber                       试卷编号
     * @param paperType                         试卷类型
     * @param paperName                         试卷名称
     * @param dimensionType                     维度类型
     * @param requestUser                       请求用户
     * @return 构建好的维度预新增对象集合
     */
    private List<GradePaperDimension> checkAndBuildGradePaperDimensionList(List<GradePaperDimensionDatasource> gradePaperDimensionDatasourceList, String paperNumber, String paperType, String paperName, DimensionEnum dimensionType, SysUser requestUser) {
        // TODO: 2022/6/15 校验如果试卷结构不为空，判断试卷结构中是不是存在
        Map<String, String> checkPrimaryCodeNameMap = new HashMap<>();
        List<GradePaperDimension> gradePaperDimensionList = new ArrayList<>();

        for (GradePaperDimensionDatasource gradePaperDimensionDatasource : gradePaperDimensionDatasourceList) {
            String codePrimary = gradePaperDimensionDatasource.getCodePrimary();
            String namePrimary = gradePaperDimensionDatasource.getNamePrimary();
            String codeSecond = gradePaperDimensionDatasource.getCodeSecond();
            String nameSecond = gradePaperDimensionDatasource.getNameSecond();
            String interpretation = gradePaperDimensionDatasource.getInterpretation();

            if (SystemConstant.isOneNull(paperNumber, paperType, dimensionType, codePrimary, namePrimary)) {
                throw ExceptionResultEnum.PARAMS_ERROR.exception();
            }

            // 一级维度编号必须为大写A-Z
            if (!codePrimary.matches(SystemConstant.REGULAR_EXPRESSION_OF_CODE_PRIMARY_DIMENSION)) {
                throw ExceptionResultEnum.ERROR.exception("一级维度编号必须为大写A-Z");
            }
            // 一级维度编号和名称在数据集中必须对应一致
            if (checkPrimaryCodeNameMap.containsKey(codePrimary) && !checkPrimaryCodeNameMap.get(codePrimary).equals(namePrimary)) {
                throw ExceptionResultEnum.ERROR.exception("一级维度编号和名称不对应");
            }
            checkPrimaryCodeNameMap.put(codePrimary, namePrimary);
            //
            if (SystemConstant.strNotNull(codeSecond)) {
                if (!codeSecond.matches(SystemConstant.REGULAR_EXPRESSION_OF_CODE_SECOND_DIMENSION)) {
                    throw ExceptionResultEnum.ERROR.exception("二级维度编号格式不正确");
                }
                if (!codePrimary.equals(codeSecond.substring(0, 1))) {
                    throw ExceptionResultEnum.ERROR.exception("二级维度编号和一级维度编号不对应");
                }

            }
            GradePaperDimension gradePaperDimension = new GradePaperDimension();
            gradePaperDimension.setSchoolId(requestUser.getSchoolId());
            gradePaperDimension.setPaperNumber(paperNumber);
            gradePaperDimension.setPaperType(paperType);
            gradePaperDimension.setPaperName(paperName);
            gradePaperDimension.setDimensionType(dimensionType);
            gradePaperDimension.setCodePrimary(codePrimary);
            gradePaperDimension.setNamePrimary(namePrimary);
            if (SystemConstant.strNotNull(codeSecond)) {
                gradePaperDimension.setCodeSecond(codeSecond);
                gradePaperDimension.setNameSecond(nameSecond);
            }
            if (SystemConstant.strNotNull(interpretation)) {
                gradePaperDimension.setInterpretation(interpretation);
            }
            gradePaperDimension.insertInfo(requestUser.getId());
            gradePaperDimensionList.add(gradePaperDimension);
        }
        return gradePaperDimensionList;
    }
}
