package com.qmth.exam.reserve.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.qmth.boot.core.exception.StatusException;
import com.qmth.boot.tools.excel.model.DataMap;
import com.qmth.exam.reserve.bean.studentimport.StudentImportInfo;
import com.qmth.exam.reserve.cache.impl.ApplyTaskCacheService;
import com.qmth.exam.reserve.entity.CategoryEntity;
import com.qmth.exam.reserve.entity.StudentCourseEntity;
import com.qmth.exam.reserve.entity.StudentEntity;
import com.qmth.exam.reserve.entity.StudentImportTaskEntity;
import com.qmth.exam.reserve.enums.CategoryLevel;
import com.qmth.exam.reserve.enums.ImportStatus;
import com.qmth.exam.reserve.service.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class StudentImportAsyncServiceImpl implements StudentImportAsyncService {

    private final static Logger log = LoggerFactory.getLogger(StudentImportAsyncServiceImpl.class);

    private static final String[] EXCEL_HEADER = new String[] { "学号", "姓名", "证件号", "所属教学点代码", "所属教学点名称", "科目名称", "科目代码" };

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private StudentService studentService;

    @Autowired
    private StudentImportTaskService importTaskService;

    @Autowired
    private ApplyTaskCacheService cacheService;

    @Autowired
    private StudentCourseService studentCourseService;

    @Async
    @Transactional
    @Override
    public void asyncImportStudent(StudentImportTaskEntity task, Long orgId, List<DataMap> lineList) {
        Map<String, CategoryEntity> teachingCache = getTeachingCache();
        List<StudentImportInfo> studentList = new ArrayList<>();
        List<Map<String, Object>> failRecords = new ArrayList<>();
        for (int i = 0; i < lineList.size(); i++) {
            DataMap line = lineList.get(i);
            StringBuilder msg = new StringBuilder();
            StudentImportInfo student = new StudentImportInfo();
            String studentCode = trimAndNullIfBlank(line.get(EXCEL_HEADER[0]));
            if (StringUtils.isBlank(studentCode)) {
                msg.append(" 学号不能为空");
            } else if (studentCode.length() > 20) {
                msg.append(" 学号的长度不能超过20位");
            } else {
                student.setStudentCode(studentCode);
            }
            String name = trimAndNullIfBlank(line.get(EXCEL_HEADER[1]));
            if (StringUtils.isBlank(name)) {
                msg.append(" 姓名不能为空");
            } else if (name.length() > 50) {
                msg.append(" 考生姓名的长度不能超过50位");
            } else {
                student.setName(name);
            }

            String identityNumber = trimAndNullIfBlank(line.get(EXCEL_HEADER[2]));
            if (StringUtils.isBlank(identityNumber)) {
                msg.append(" 证件号不能为空");
            } else if (identityNumber.length() < 6 || identityNumber.length() > 20) {
                msg.append(" 证件号不正确");
            } else {
                student.setIdentityNumber(identityNumber);
                String password = identityNumber.substring(identityNumber.length() - 6);
                student.setPassword(DigestUtils.sha256Hex(password).toUpperCase());
            }

            String teachingCode = trimAndNullIfBlank(line.get(EXCEL_HEADER[3]));
            if (StringUtils.isBlank(teachingCode)) {
                msg.append(" 教学点代码不能为空");
            }
            CategoryEntity category = teachingCache.get(teachingCode);
            if (category == null) {
                msg.append(" 教学点不存在");
            }

            String teachingName = trimAndNullIfBlank(line.get(EXCEL_HEADER[4]));
            if (StringUtils.isBlank(teachingName)) {
                msg.append(" 教学点名称不能为空");
            }
            if (category != null && !category.getName().equals(teachingName)) {
                msg.append(" 教学点名称错误");
            }
            if (category != null && category.getName().equals(teachingName)) {
                student.setCategoryId(category.getId());
                student.setOrgId(orgId);
                student.setApplyTaskId(task.getApplyTaskId());
            }

            String courseName = trimAndNullIfBlank(line.get(EXCEL_HEADER[5]));
            if (StringUtils.isBlank(courseName)) {
                msg.append(" 科目名称不能为空");
            } else if (courseName.length() > 50) {
                msg.append(" 科目名称的长度不能超过50");
            } else {
                student.setCourseName(courseName);
            }

            String courseCode = trimAndNullIfBlank(line.get(EXCEL_HEADER[6]));
            if (StringUtils.isBlank(courseCode)) {
                msg.append(" 科目代码不能为空");
            } else if (courseCode.length() > 20) {
                msg.append(" 科目代码的长度不能超过20");
            } else {
                student.setCourseCode(courseCode);
            }

            if (msg.length() > 0) {
                failRecords.add(newError(i + 1, msg.toString()));
            } else {
                studentList.add(student);
            }

            //只要有错误，就跳出循环
            if (CollectionUtils.isNotEmpty(failRecords)) {
                break;
            }
        }

        if (CollectionUtils.isNotEmpty(failRecords)) {
            updateStudentImportTask(task, ImportStatus.FAILURE.toString(), failRecords);
            return;
        }

        //更新和保存考生以及考生的考试科目
        long start = System.currentTimeMillis();
        for (int i = 0; i < studentList.size(); i++) {
            StudentImportInfo studentInfo = studentList.get(i);
            try {
                //考生信息
                StudentEntity studentEntity = new StudentEntity();
                BeanUtils.copyProperties(studentInfo, studentEntity);

                //考生的考试科目
                StudentCourseEntity studentCourseEntity = new StudentCourseEntity();
                studentCourseEntity.setCourseCode(studentInfo.getCourseCode());
                studentCourseEntity.setCourseName(studentInfo.getCourseName());

                LambdaQueryWrapper<StudentEntity> wrapper = new LambdaQueryWrapper<StudentEntity>()
                        .eq(StudentEntity::getStudentCode, studentEntity.getStudentCode())
                        .eq(StudentEntity::getApplyTaskId, studentEntity.getApplyTaskId());
                StudentEntity existStudent = studentService.getOne(wrapper);

                LambdaQueryWrapper<StudentCourseEntity> studentCourseQueryWrapper = new LambdaQueryWrapper<>();
                studentCourseQueryWrapper.eq(StudentCourseEntity::getCourseCode, studentCourseEntity.getCourseCode());

                Long studentId;
                if (existStudent != null) {
                    studentId = existStudent.getId();
                    existStudent.setName(studentEntity.getName());
                    existStudent.setIdentityNumber(studentEntity.getIdentityNumber());
                    existStudent.setCategoryId(studentEntity.getCategoryId());
                    studentService.updateById(existStudent);

                    studentCourseQueryWrapper.eq(StudentCourseEntity::getStudentId, studentId);
                    StudentCourseEntity existStudentCourse = studentCourseService.getOne(studentCourseQueryWrapper);

                    //更新考生的考试科目
                    if(existStudentCourse != null) {
                        existStudentCourse.setCourseName(studentCourseEntity.getCourseName());
                        studentCourseService.updateById(existStudentCourse);
                    } else {
                        studentCourseEntity.setStudentId(existStudent.getId());
                        studentCourseService.save(studentCourseEntity);
                    }
                } else {
                    studentEntity.setApplyFinished(Boolean.FALSE);
                    studentEntity.setApplyNumber(0);
                    studentEntity.setPhotoPath(studentEntity.getIdentityNumber()+".jpg");
                    studentService.save(studentEntity);

                    studentId = studentEntity.getId();

                    //保存考生科目
                    studentCourseEntity.setStudentId(studentId);
                    studentCourseService.save(studentCourseEntity);
                }

                //更新考生的预约次数
                studentService.updateStudentApplyNumber(studentId);

                // 清空缓存
                cacheService.clearStudentApplyNumberCache(studentId);

            } catch (StatusException e) {
                failRecords.add(newError(i + 1, e.getMessage()));
            } catch (Exception e) {
                failRecords.add(newError(i + 1, " 系统异常"));
                log.error("导入异常", e);
                updateStudentImportTask(task, ImportStatus.FAILURE.toString(), failRecords);
                return;
            }
        }
        long end = System.currentTimeMillis();
        log.warn("[导入考生]耗时:{}ms", end - start);

        //更新成功标志
        task.setMessage(failRecords.isEmpty() ? null : failRecords.toString());
        task.setStatus(ImportStatus.SUCCESS.toString());
        importTaskService.saveOrUpdate(task);
    }

    private void updateStudentImportTask(StudentImportTaskEntity task, String status,
            List<Map<String, Object>> failRecords) {
        task.setMessage(failRecords.isEmpty() ? null : failRecords.toString());
        task.setStatus(status);
        importTaskService.saveOrUpdate(task);
    }

    private String trimAndNullIfBlank(String s) {
        if (StringUtils.isBlank(s)) {
            return null;
        }
        return s.trim();
    }

    private Map<String, Object> newError(int lineNum, String msg) {
        Map<String, Object> map = new HashMap<>();
        map.put("lineNum", lineNum);
        map.put("msg", msg);
        return map;
    }

    private Map<String, CategoryEntity> getTeachingCache() {
        LambdaQueryWrapper<CategoryEntity> lm = new LambdaQueryWrapper<>();
        lm.eq(CategoryEntity::getEnable, Boolean.TRUE);
        lm.eq(CategoryEntity::getLevel, CategoryLevel.TEACHING.getValue());
        List<CategoryEntity> categoryList = categoryService.list(lm);
        return categoryList.stream().collect(Collectors.toMap(CategoryEntity::getCode, Function.identity()));
    }

}
