package com.qmth.themis.business.templete.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.gson.Gson;
import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dto.ExamStudentImportDto;
import com.qmth.themis.business.dto.RoomCodeImportDto;
import com.qmth.themis.business.entity.*;
import com.qmth.themis.business.enums.ExamModeEnum;
import com.qmth.themis.business.enums.RoleEnum;
import com.qmth.themis.business.enums.TaskStatusEnum;
import com.qmth.themis.business.service.*;
import com.qmth.themis.business.templete.service.TempleteLogicService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;

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

/**
 * @Description: 导入导出模版处理逻辑 impl
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020/7/31
 */
@Service
public class TempleteLogicServiceImpl implements TempleteLogicService {

    @Resource
    TEExamStudentService teExamStudentService;

    @Resource
    TEStudentService teStudentService;

    @Resource
    TBExamInvigilateUserService tbExamInvigilateUserService;

    @Resource
    TBUserService tbUserService;

    @Resource
    TBUserRoleService tbUserRoleService;

    @Resource
    TEExamCourseService teExamCourseService;

    /**
     * 考生导入逻辑
     *
     * @param finalList
     * @param map
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> execImportExamStudentLogic(List<LinkedMultiValueMap<Integer, Object>> finalList, Map<String, Object> map) {
        Long orgId = Long.parseLong(String.valueOf(map.get("orgId")));
        Long examId = Long.parseLong(String.valueOf(map.get("examId")));
        Long createId = Long.parseLong(String.valueOf(map.get("createId")));
        List<String> txtList = (List<String>) map.get("txtList");
        TBTaskHistory tbTaskHistory = (TBTaskHistory) map.get("tbTaskHistory");
        String timeFormat = String.valueOf(map.get("timeFormat"));
        List<TEExamStudent> teExamStudentList = new ArrayList<>();
        List<TEStudent> teStudentList = new ArrayList<>();
        List<TBExamInvigilateUser> tbExamInvigilateUserList = new ArrayList<>();
        Gson gson = new Gson();
        Set<String> roomCodeAndNameSet = new HashSet<>();
        Map<String, TEExamActivity> teExamActivityMap = (Map<String, TEExamActivity>) map.get("teExamActivityMap");
        Map<String, String> courseCodeMap = (Map<String, String>) map.get("courseCodeMap");
        QueryWrapper<TEExamCourse> teExamCourseQueryWrapper = new QueryWrapper<>();
        Set<String> courseCodeSet = courseCodeMap.keySet().stream().collect(Collectors.toSet());
        teExamCourseQueryWrapper.lambda().in(TEExamCourse::getCourseCode, courseCodeSet).eq(TEExamCourse::getExamId, examId);
        List<TEExamCourse> teExamCourseList = teExamCourseService.list(teExamCourseQueryWrapper);
        if (Objects.nonNull(teExamCourseList) && teExamCourseList.size() > 0) {
            teExamCourseList.forEach(s -> {
                courseCodeMap.remove(s.getCourseCode());
            });
        }
        List<TEExamCourse> teExamCourses = new ArrayList<>();
        courseCodeMap.forEach((k, v) -> {
            TEExamCourse teExamCourse = new TEExamCourse(examId, k, v, createId);
            teExamCourses.add(teExamCourse);
        });
        if (teExamCourses.size() > 0) {
            teExamCourseService.saveBatch(teExamCourses);
        }
        TEExamActivity teExamActivity = null;
        ExamModeEnum modeEnum = ExamModeEnum.valueOf(String.valueOf(map.get("mode")));
        if (Objects.equals(modeEnum, ExamModeEnum.ANYTIME)) {
            Iterator iterator = teExamActivityMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Map> entry = (Map.Entry<String, Map>) iterator.next();
                Map m = entry.getValue();
                teExamActivity = gson.fromJson(gson.toJson(m), TEExamActivity.class);
            }
        }
        //保存用户
        for (int i = 0; i < finalList.size(); i++) {
            LinkedMultiValueMap<Integer, Object> finalMap = finalList.get(i);
            List<Object> examStudentImportDtoList = finalMap.get(i);
            int min = 0;
            int y = 0;
            int max = SystemConstant.MAX_IMPORT_SIZE, size = examStudentImportDtoList.size();
            if (max >= size) {
                max = size;
            }
            while (max <= size) {
                List subList = examStudentImportDtoList.subList(min, max);
                for (; y < subList.size(); y++) {
                    ExamStudentImportDto examStudentImportDto = (ExamStudentImportDto) subList.get(y);
                    if (Objects.equals(modeEnum, ExamModeEnum.TOGETHER)) {
                        Map m = (Map) teExamActivityMap.get(examStudentImportDto.getExamActivityCode());
                        teExamActivity = gson.fromJson(gson.toJson(m), TEExamActivity.class);
                    }
                    //先根据证件号+科目代码查询考生是否存在，存在则更新，不存在则插入
                    QueryWrapper<TEExamStudent> teExamStudentQueryWrapper = new QueryWrapper<>();
                    teExamStudentQueryWrapper.lambda().eq(TEExamStudent::getIdentity, examStudentImportDto.getIdentity())
                            .eq(TEExamStudent::getCourseCode, examStudentImportDto.getCourseCode())
                            .eq(TEExamStudent::getExamId, examId)
                            .eq(TEExamStudent::getExamActivityId, teExamActivity.getId());
                    TEExamStudent teExamStudent = teExamStudentService.getOne(teExamStudentQueryWrapper);
                    //如果为空则插入考生数据，插入考生前先插入学生档案数据
                    if (Objects.isNull(teExamStudent)) {
                        QueryWrapper<TEStudent> teStudentQueryWrapper = new QueryWrapper<>();
                        teStudentQueryWrapper.lambda().eq(TEStudent::getIdentity, examStudentImportDto.getIdentity()).eq(TEStudent::getOrgId, orgId);
                        TEStudent teStudent = teStudentService.getOne(teStudentQueryWrapper);
                        if (Objects.isNull(teStudent)) {//如果学生数据为空则插入学生数据
                            //先插入学生档案数据
                            teStudent = new TEStudent(orgId, examStudentImportDto.getIdentity(), examStudentImportDto.getName(), createId);
                            teStudentService.save(teStudent);
                            teStudentList.add(teStudent);
                        } else {
                            UpdateWrapper<TEStudent> teStudentUpdateWrapper = new UpdateWrapper<>();
                            teStudentUpdateWrapper.lambda().set(TEStudent::getName, examStudentImportDto.getName())
                                    .eq(TEStudent::getIdentity, examStudentImportDto.getIdentity());
                            teStudentService.update(teStudentUpdateWrapper);
                        }
                        teExamStudent = gson.fromJson(gson.toJson(examStudentImportDto), TEExamStudent.class);
                        teExamStudent.setExamId(examId);
                        teExamStudent.setExamActivityId(teExamActivity.getId());
                        teExamStudent.setStudentId(teStudent.getId());
                        teExamStudent.setCreateId(createId);
                        teExamStudent.setCourseCode(examStudentImportDto.getCourseCode());
                        teExamStudent.setCourseName(examStudentImportDto.getCourseName());
                        teExamStudent.setAlreadyExamCount(0);
                    } else {
                        teExamStudent.setUpdateId(createId);
                        teExamStudent.setName(examStudentImportDto.getName());
                        teExamStudent.setGrade(examStudentImportDto.getGrade());
                        teExamStudent.setClassNo(examStudentImportDto.getClassNo());
                        teExamStudent.setRoomCode(examStudentImportDto.getRoomCode());
                        teExamStudent.setRoomName(examStudentImportDto.getRoomName());
                        teExamStudent.setCourseCode(examStudentImportDto.getCourseCode());
                        teExamStudent.setCourseName(examStudentImportDto.getCourseName());
                        teExamStudent.setExamActivityId(teExamActivity.getId());
                        teExamStudent.setAlreadyExamCount(0);

                        UpdateWrapper<TEStudent> teStudentUpdateWrapper = new UpdateWrapper<>();
                        teStudentUpdateWrapper.lambda().set(TEStudent::getName, examStudentImportDto.getName())
                                .eq(TEStudent::getIdentity, examStudentImportDto.getIdentity());
                        teStudentService.update(teStudentUpdateWrapper);
                    }
                    UpdateWrapper<TEExamStudent> teExamStudentUpdateWrapper = new UpdateWrapper<>();
                    teExamStudentUpdateWrapper.lambda().set(TEExamStudent::getName, examStudentImportDto.getName())
                            .eq(TEExamStudent::getIdentity, examStudentImportDto.getIdentity());
                    teExamStudentService.update(teExamStudentUpdateWrapper);

                    ExamCourseCacheBean examCourseCacheBean = teExamCourseService.getExamCourseCacheBean(teExamStudent.getExamId(), teExamStudent.getCourseCode());
                    if (Objects.nonNull(examCourseCacheBean)) {
                        teExamStudent.setCourseName(examCourseCacheBean.getCourseName());
                    }
                    teExamStudentService.saveOrUpdate(teExamStudent);
                    roomCodeAndNameSet.add(examId + ":" + teExamStudent.getRoomCode() + ":" + teExamStudent.getRoomName());
                    teExamStudentList.add(teExamStudent);
                }
                txtList = this.importProgress(max, min, size, txtList, tbTaskHistory, timeFormat);
                map.put("min", min);
                map.put("y", y);
                if (max == size) {
                    break;
                }
                min = max;
                max += SystemConstant.MAX_IMPORT_SIZE;
                if (max >= size) {
                    max = size;
                }
            }
        }
        //考场创建
        if (Objects.nonNull(roomCodeAndNameSet) && roomCodeAndNameSet.size() > 0) {
            Map<String, TBExamInvigilateUser> tbExamInvigilateUserMap = (Map<String, TBExamInvigilateUser>) map.get("tbExamInvigilateUserMap");
            AtomicInteger count = new AtomicInteger(0);
            roomCodeAndNameSet.forEach(s -> {
                if (Objects.isNull(tbExamInvigilateUserMap) || (Objects.nonNull(tbExamInvigilateUserMap) && Objects.isNull(tbExamInvigilateUserMap.get(s)))) {
                    String[] strs = s.split(":");
                    TBExamInvigilateUser tbExamInvigilateUser = new TBExamInvigilateUser(Long.parseLong(strs[0]), orgId, strs[1], strs[2]);
                    tbExamInvigilateUserService.save(tbExamInvigilateUser);
                    tbExamInvigilateUserList.add(tbExamInvigilateUser);
                    count.getAndIncrement();
                }
            });
            if (count.get() > 0) {
                txtList.add(DateUtil.format(new Date(), timeFormat) + "->创建了" + count + "条考场数据");
            }
        }
        return map;
    }

    /**
     * 考场导入逻辑
     *
     * @param finalList
     * @param map
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> execImportRoomCodeLogic(List<LinkedMultiValueMap<Integer, Object>> finalList, Map<String, Object> map) {
        Long orgId = null;
        if (Objects.nonNull(map.get("orgId"))) {
            orgId = Long.parseLong(String.valueOf(map.get("orgId")));
        }
        Long createId = Long.parseLong(String.valueOf(map.get("createId")));
        List<String> txtList = (List<String>) map.get("txtList");
        TBTaskHistory tbTaskHistory = (TBTaskHistory) map.get("tbTaskHistory");
        String timeFormat = String.valueOf(map.get("timeFormat"));
        //保存用户
        for (int i = 0; i < finalList.size(); i++) {
            LinkedMultiValueMap<Integer, Object> finalMap = finalList.get(i);
            List<Object> examStudentDtoImportList = finalMap.get(i);
            int min = 0;
            int y = 0;
            int max = SystemConstant.MAX_IMPORT_SIZE, size = examStudentDtoImportList.size();
            if (max >= size) {
                max = size;
            }
            while (max <= size) {
                List subList = examStudentDtoImportList.subList(min, max);
                for (; y < subList.size(); y++) {
                    RoomCodeImportDto roomCodeImportDto = (RoomCodeImportDto) subList.get(y);
                    dataVerify(roomCodeImportDto.getTeacher1(), roomCodeImportDto.getRoomCode(), roomCodeImportDto.getRoomName(), orgId, createId);
                    dataVerify(roomCodeImportDto.getTeacher2(), roomCodeImportDto.getRoomCode(), roomCodeImportDto.getRoomName(), orgId, createId);
                    dataVerify(roomCodeImportDto.getTeacher3(), roomCodeImportDto.getRoomCode(), roomCodeImportDto.getRoomName(), orgId, createId);
                }
                txtList = this.importProgress(max, min, size, txtList, tbTaskHistory, timeFormat);
                if (max == size) {
                    break;
                }
                min = max;
                max += SystemConstant.MAX_IMPORT_SIZE;
                if (max >= size) {
                    max = size;
                }
            }
        }
        return map;
    }

    /**
     * 考场导出逻辑
     *
     * @param map
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> execExportRoomCodeLogic(Map<String, Object> map) {
        List<String> txtList = (List<String>) map.get("txtList");
        TBTaskHistory tbTaskHistory = (TBTaskHistory) map.get("tbTaskHistory");
        Integer max = Integer.parseInt(String.valueOf(map.get("max")));
        Integer min = Integer.parseInt(String.valueOf(map.get("min")));
        Integer size = Integer.parseInt(String.valueOf(map.get("size")));
        String timeFormat = String.valueOf(map.get("timeFormat"));
        this.exportProgress(max, min, size, txtList, tbTaskHistory, timeFormat);
        return map;
    }

    /**
     * 查询监考帐号是否存在
     *
     * @param userName
     * @param roomCode
     * @param roomName
     * @param orgId
     * @param createId
     */
    public void dataVerify(String userName, String roomCode, String roomName, Long orgId, Long createId) {
        if (Objects.nonNull(userName)) {
            //先查询监考帐号是否存在
            QueryWrapper<TBUser> tbUserQueryWrapper = new QueryWrapper<>();
            tbUserQueryWrapper.lambda().eq(TBUser::getLoginName, userName).eq(TBUser::getOrgId, orgId);
            TBUser tbUser = tbUserService.getOne(tbUserQueryWrapper);
            if (Objects.isNull(tbUser)) {
                //新增用户
                tbUser = new TBUser(orgId, userName, userName, createId);
                tbUserService.save(tbUser);

                TBUserRole tbUserRole = new TBUserRole(tbUser.getId(), RoleEnum.INVIGILATE.name());
                tbUserRoleService.save(tbUserRole);
            }
            QueryWrapper<TBExamInvigilateUser> tbExamInvigilateUserQueryWrapper = new QueryWrapper<>();
            tbExamInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getOrgId, orgId)
                    .eq(TBExamInvigilateUser::getUserId, tbUser.getId())
                    .eq(TBExamInvigilateUser::getRoomCode, roomCode)
                    .eq(TBExamInvigilateUser::getRoomName, roomName);
            TBExamInvigilateUser tbExamInvigilateUser = tbExamInvigilateUserService.getOne(tbExamInvigilateUserQueryWrapper);
            if (Objects.isNull(tbExamInvigilateUser)) {//新增考场
                tbExamInvigilateUser = new TBExamInvigilateUser(orgId, tbUser.getId(), roomCode, roomName);
            }
            tbExamInvigilateUserService.saveOrUpdate(tbExamInvigilateUser);
        }
    }

    /**
     * 导入换算进度
     *
     * @param max
     * @param min
     * @param size
     * @param txtList
     * @param tbTaskHistory
     * @param timeFormat
     * @return
     */
    public List<String> importProgress(int max, int min, int size, List<String> txtList, TBTaskHistory tbTaskHistory, String timeFormat) {
        BigDecimal bigDecimal = new BigDecimal(100);
        BigDecimal progress = new BigDecimal(Double.valueOf(new BigDecimal(max).divide(new BigDecimal(size), 2, BigDecimal.ROUND_HALF_UP).multiply(bigDecimal).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())).setScale(0, BigDecimal.ROUND_HALF_UP);
        if (progress.intValue() == 100) {
            tbTaskHistory.setStatus(TaskStatusEnum.FINISH);
            tbTaskHistory.setSummary("共处理了" + size + "条数据");
            tbTaskHistory.setFinishTime(System.currentTimeMillis());
            txtList.add(DateUtil.format(new Date(), timeFormat) + "->数据处理完毕，" + tbTaskHistory.getSummary());
        } else {
            tbTaskHistory.setStatus(TaskStatusEnum.RUNNING);
            tbTaskHistory.setSummary("正在处理第" + min + "条至" + max + "条数据");
            txtList.add(DateUtil.format(new Date(), timeFormat) + "->数据处理中，" + tbTaskHistory.getSummary());
        }
        tbTaskHistory.setProgress(progress.doubleValue());
        return txtList;
    }

    /**
     * 导出换算进度
     *
     * @param max
     * @param min
     * @param size
     * @param txtList
     * @param tbTaskHistory
     * @param timeFormat
     * @return
     */
    public List<String> exportProgress(int max, int min, int size, List<String> txtList, TBTaskHistory tbTaskHistory, String timeFormat) {
        BigDecimal bigDecimal = new BigDecimal(100);
        BigDecimal progress = new BigDecimal(Double.valueOf(new BigDecimal(max).divide(new BigDecimal(size), 2, BigDecimal.ROUND_HALF_UP).multiply(bigDecimal).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())).setScale(0, BigDecimal.ROUND_HALF_UP);
        if (progress.intValue() == 100) {
            tbTaskHistory.setStatus(TaskStatusEnum.FINISH);
            tbTaskHistory.setSummary("共导出了" + size + "条数据");
            tbTaskHistory.setFinishTime(System.currentTimeMillis());
            txtList.add(DateUtil.format(new Date(), timeFormat) + "->数据导出完毕，" + tbTaskHistory.getSummary());
        } else {
            tbTaskHistory.setStatus(TaskStatusEnum.RUNNING);
            tbTaskHistory.setSummary("正在导出第" + min + "条至" + max + "条数据");
            txtList.add(DateUtil.format(new Date(), timeFormat) + "->数据导出中，" + tbTaskHistory.getSummary());
        }
        tbTaskHistory.setProgress(progress.doubleValue());
        return txtList;
    }
}
