package cn.com.qmth.stmms.api.controller;

import cn.com.qmth.stmms.api.dto.MenualAbsentDTO;
import cn.com.qmth.stmms.api.exception.ApiException;
import cn.com.qmth.stmms.api.utils.AESUtil;
import cn.com.qmth.stmms.biz.exam.model.Exam;
import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
import cn.com.qmth.stmms.biz.exam.service.ExamService;
import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
import cn.com.qmth.stmms.biz.file.service.FileService;
import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
import cn.com.qmth.stmms.biz.user.model.User;
import cn.com.qmth.stmms.biz.user.service.UserService;
import cn.com.qmth.stmms.biz.utils.ScoreItem;
import cn.com.qmth.stmms.common.annotation.Logging;
import cn.com.qmth.stmms.common.annotation.RoleRequire;
import cn.com.qmth.stmms.common.domain.ApiUser;
import cn.com.qmth.stmms.common.enums.ExamStatus;
import cn.com.qmth.stmms.common.enums.ExamType;
import cn.com.qmth.stmms.common.enums.LogType;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.utils.RequestUtils;

import com.google.common.base.Strings;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

import java.text.DecimalFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

@Controller("examStudentApiController")
@RequestMapping("/api")
public class ExamStudentController extends BaseApiController {

    protected static Logger logger = LoggerFactory.getLogger(ExamStudentController.class);

    @Autowired
    private ExamStudentService studentService;

    @Autowired
    private ExamService examService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private MarkLibraryService libraryService;

    @Autowired
    private UserService userService;

    @Autowired
    private FileService fileService;

    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SCANNER })
    @RequestMapping(value = "/student/check", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject checkStudent(HttpServletRequest request, @RequestBody ExamStudent examStudent) {
        JSONObject obj = new JSONObject();
        ExamStudent student = studentService.findByExamIdAndExamNumber(examStudent.getExamId(),
                examStudent.getExamNumber());
        if (student != null) {
            obj.accumulate("examId", examStudent.getExamId());
            obj.accumulate("campusCode", "0");
            obj.accumulate("campusName", StringUtils.trimToEmpty(student.getCampusName()));
            obj.accumulate("examNumber", student.getExamNumber());
            obj.accumulate("secretNumber", student.getSecretNumber());
            obj.accumulate("name", student.getName());
            obj.accumulate("studentId", String.valueOf(student.getId()));
            obj.accumulate("studentCode", student.getStudentCode());
            obj.accumulate("subjectCode", student.getSubjectCode());
            obj.accumulate("subjectName", student.getSubjectName());
            obj.accumulate("examSite", StringUtils.trimToEmpty(student.getExamSite()));
            obj.accumulate("college", StringUtils.trimToEmpty(student.getCollege()));
        } else {
            obj.accumulate("examId", examStudent.getExamId());
            obj.accumulate("campusCode", "");
            obj.accumulate("campusName", "");
            obj.accumulate("examNumber", examStudent.getExamNumber());
            obj.accumulate("name", "");
            obj.accumulate("studentId", "");
            obj.accumulate("studentCode", "");
            obj.accumulate("subjectCode", "");
            obj.accumulate("subjectName", "");
            obj.accumulate("examSite", "");
            obj.accumulate("college", "");
        }
        return obj;
    }

    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SCANNER })
    @RequestMapping("/exam/students/count")
    @ResponseBody
    public long getStudentCount(HttpServletRequest request, ExamStudentSearchQuery query) {
        ApiUser user = RequestUtils.getApiUser(request);
        Exam exam = query.getExamId() != null ? examService.findById(query.getExamId()) : null;
        if (exam != null && exam.getSchoolId().equals(user.getSchoolId())) {
            return studentService.countByQuery(query);
        }
        return 0;
    }

    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SCANNER })
    @RequestMapping("/exam/students")
    @ResponseBody
    public JSONArray getStudent(HttpServletRequest request, ExamStudentSearchQuery query,
            @RequestParam(required = false) Boolean withScoreDetail,
            @RequestParam(required = false) Boolean withMarkTrack,
            @RequestParam(required = false) Boolean withGroupScoreTrack,
            @RequestParam(required = false) Boolean withSheetUrl, @RequestParam(required = false) Boolean sliceConfigFix) {
        ApiUser user = RequestUtils.getApiUser(request);
        JSONArray array = new JSONArray();
        if (query.getExamId() == null) {
            return array;
        }
        Exam exam = examService.findById(query.getExamId());
        if (exam != null && exam.getSchoolId().equals(user.getSchoolId())) {
            DecimalFormat format = new DecimalFormat("####.###");
            studentService.findByQuery(query);
            for (ExamStudent student : query.getResult()) {
                JSONObject obj = new JSONObject();
                obj.accumulate("id", student.getId());
                obj.accumulate("schoolId", student.getSchoolId());
                obj.accumulate("examNumber", student.getExamNumber());
                obj.accumulate("secretNumber", student.getSecretNumber());
                obj.accumulate("campusCode", "0");
                obj.accumulate("campusName", StringUtils.trimToEmpty(student.getCampusName()));
                obj.accumulate("subjectCode", student.getSubjectCode());
                obj.accumulate("subjectName", student.getSubjectName());
                obj.accumulate("name", student.getName());
                obj.accumulate("studentCode", student.getStudentCode());
                obj.accumulate("packageCode", StringUtils.trimToEmpty(student.getPackageCode()));
                obj.accumulate("paperType", StringUtils.trimToEmpty(student.getPaperType()));
                obj.accumulate("batchCode", StringUtils.trimToEmpty(student.getBatchCode()));
                obj.accumulate("sheetCount", student.getSheetCount() != null ? student.getSheetCount() : 0);
                obj.accumulate("sliceCount", student.getSliceCount() != null ? student.getSliceCount() : 0);
                obj.accumulate("answers", StringUtils.trimToEmpty(student.getAnswers()));
                obj.accumulate("upload", student.isUpload());
                obj.accumulate("absent", student.isAbsent());
                obj.accumulate("manualAbsent", student.isManualAbsent());
                obj.accumulate("breach", student.isBreach());
                obj.accumulate("objectiveScore",
                        student.getObjectiveScore() == null ? "" : format.format(student.getObjectiveScore()));
                obj.accumulate("subjectiveScore",
                        student.getSubjectiveScore() == null ? "" : format.format(student.getSubjectiveScore()));
                obj.accumulate("subjectiveStatus", student.getSubjectiveStatus().toString());
                obj.accumulate("examSite", StringUtils.trimToEmpty(student.getExamSite()));
                obj.accumulate("examRoom", StringUtils.trimToEmpty(student.getExamRoom()));
                obj.accumulate("remark", StringUtils.trimToEmpty(student.getRemark()));
                obj.accumulate("college", StringUtils.trimToEmpty(student.getCollege()));
                obj.accumulate("className", StringUtils.trimToEmpty(student.getClassName()));
                obj.accumulate("teacher", StringUtils.trimToEmpty(student.getTeacher()));
                if (student.getInspectorId() != null) {
                    obj.accumulate("inspector", getInspector(student.getInspectorId()));
                }

                try {
                    if (withScoreDetail != null && withScoreDetail.booleanValue()) {
                        // 构造客观题得分明细
                        JSONArray objective = new JSONArray();
                        List<ScoreItem> scoreList = student.getScoreList(true);
                        List<ExamQuestion> questionList = questionService.findByExamAndSubjectAndObjectiveAndPaperType(
                                student.getExamId(), student.getSubjectCode(), true, student.getPaperType());
                        int i = 0;
                        for (ScoreItem item : scoreList) {
                            i++;
                            if (questionList.size() < i) {
                                break;
                            }
                            ExamQuestion question = questionList.get(i - 1);
                            if (question.getTotalScore() == null || question.getTotalScore() == 0) {
                                continue;
                            }
                            JSONObject detail = new JSONObject();
                            detail.accumulate("mainNumber", question.getMainNumber());
                            detail.accumulate("subNumber", question.getSubNumber());
                            detail.accumulate("score", item.getScore());
                            detail.accumulate("answer", item.getAnswer());
                            objective.add(detail);
                        }
                        obj.accumulate("objectiveScoreDetail", objective);

                        // 构造主观题得分明细
                        JSONArray subjective = new JSONArray();
                        scoreList = student.getScoreList(false);
                        questionList = questionService.findByExamAndSubjectAndObjective(student.getExamId(),
                                student.getSubjectCode(), false);
                        i = 0;
                        for (ScoreItem item : scoreList) {
                            i++;
                            if (questionList.size() < i) {
                                break;
                            }
                            ExamQuestion question = questionList.get(i - 1);
                            if (question.getTotalScore() == null || question.getTotalScore() == 0) {
                                continue;
                            }
                            JSONObject detail = new JSONObject();
                            detail.accumulate("mainNumber", question.getMainNumber());
                            detail.accumulate("subNumber", question.getSubNumber());
                            detail.accumulate("score", item.getScore());
                            detail.accumulate("marker", getMarkerNames(student, question.getGroupNumber()));
                            String header = getHeaderName(student, question.getGroupNumber());
                            if (header != null) {
                                detail.accumulate("header", header);
                            }
                            detail.accumulate("groupNumber", question.getGroupNumber());
                            detail.accumulate("mainTitle", question.getMainTitle());
                            subjective.add(detail);
                        }
                        obj.accumulate("subjectiveScoreDetail", subjective);
                    }
                    // 返回评卷标记
                    if (withMarkTrack != null && withMarkTrack.booleanValue()) {
                        obj.accumulate(
                                "tags",
                                studentService.buildSheetTags(student, withGroupScoreTrack != null
                                        && withGroupScoreTrack.booleanValue(),
                                        sliceConfigFix != null && sliceConfigFix.booleanValue()));
                    }
                    // 返回原图下载地址
                    if (withSheetUrl != null && withSheetUrl.booleanValue()) {
                        obj.accumulate(
                                "sheetUrls",
                                fileService
                                        .getSheetUris(student.getExamId(), student.getExamNumber(), 1,
                                                student.getSheetCount()).stream()
                                        .map(uri -> fileService.getFileServer().concat(uri))
                                        .collect(Collectors.toList()));
                    }
                    array.add(obj);
                } catch (Exception e) {
                    logger.error("student api error", e);
                }
            }
        }
        return array;
    }

    private String getInspector(Integer inspectorId) {
        JSONObject obj = new JSONObject();
        User inspector = userService.findById(inspectorId);
        obj.accumulate("loginName", inspector.getLoginName());
        obj.accumulate("name", inspector.getName());
        return obj.toString();
    }

    private String getMarkerNames(ExamStudent student, Integer groupNumber) {
        List<String> markerNames = new LinkedList<>();
        List<MarkLibrary> list = libraryService.findByStudentAndGroup(student.getId(), groupNumber);
        for (MarkLibrary library : list) {
            if (library.getMarkerId() == null) {
                continue;
            }
            User user = userService.findByMarkerId(library.getMarkerId());
            if (user != null) {
                markerNames.add(user.getName());
            }
        }
        return StringUtils.join(markerNames, ",");
    }

    private String getHeaderName(ExamStudent student, Integer groupNumber) {
        List<MarkLibrary> list = libraryService.findByStudentAndGroup(student.getId(), groupNumber);
        for (MarkLibrary library : list) {
            if (library.getHeaderId() == null) {
                continue;
            }
            User user = userService.findById(library.getHeaderId());
            if (user != null) {
                return user.getName();
            }
        }
        return null;
    }

    @RequestMapping(value = "/score/school/{schoolId}", method = RequestMethod.POST)
    @ResponseBody
    public String getScore(@PathVariable Integer schoolId, @RequestParam String studentCode,
            @RequestParam String subjectCode, @RequestParam(required = false, defaultValue = "true") boolean encrypt,
            @RequestParam(required = false) String examSeqCode) {
        JSONObject obj = new JSONObject();
        ExamStudent student = null;
        try {
            if (Strings.isNullOrEmpty(examSeqCode)) {
                student = studentService.findBySchoolIdAndSubjectCodeAndStudentCode(schoolId, subjectCode, studentCode);
            } else {
                student = studentService.findBySchoolIdAndSubjectCodeAndStudentCodeAndRemark(schoolId, subjectCode,
                        studentCode, examSeqCode);
            }
            if (student != null) {
                DecimalFormat df = new DecimalFormat("####.###");
                obj.accumulate("exist", true);
                obj.accumulate("objectiveScore", df.format(student.getObjectiveScore()));
                obj.accumulate("subjectiveScore", df.format(student.getSubjectiveScore()));
                obj.accumulate("totalScore", df.format(student.getTotalScore()));
            } else {
                obj.accumulate("exist", false);
                obj.accumulate("objectiveScore", 0);
                obj.accumulate("subjectiveScore", 0);
                obj.accumulate("totalScore", 0);
            }
            if (!Strings.isNullOrEmpty(examSeqCode)) {
                obj.accumulate("examSeqCode", examSeqCode);
            }
            obj.accumulate("studentCode", studentCode);
            obj.accumulate("subjectCode", subjectCode);
        } catch (Exception e) {
            e.printStackTrace();
            obj.accumulate("exception", "500");
        }
        String result = obj.toString();
        return encrypt ? AESUtil.encrypt(result) : result;
    }

    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SCANNER })
    @RequestMapping("/exam/students/slice")
    @ResponseBody
    public JSONArray getStudentsSlice(HttpServletRequest request, ExamStudentSearchQuery query,
            @RequestParam(required = false) Boolean withScoreDetail,
            @RequestParam(required = false) Boolean withMarkTrack,
            @RequestParam(required = false) Boolean withGroupScoreTrack,
            @RequestParam(required = false) Boolean withSliceUrl) {
        ApiUser user = RequestUtils.getApiUser(request);
        JSONArray array = new JSONArray();
        if (query.getExamId() == null) {
            return array;
        }
        Exam exam = examService.findById(query.getExamId());
        if (exam != null && exam.getSchoolId().equals(user.getSchoolId())) {
            DecimalFormat format = new DecimalFormat("####.###");
            studentService.findByQuery(query);
            for (ExamStudent student : query.getResult()) {
                JSONObject obj = new JSONObject();
                obj.accumulate("id", student.getId());
                obj.accumulate("schoolId", student.getSchoolId());
                obj.accumulate("examNumber", student.getExamNumber());
                obj.accumulate("campusCode", "0");
                obj.accumulate("campusName", StringUtils.trimToEmpty(student.getCampusName()));
                obj.accumulate("subjectCode", student.getSubjectCode());
                obj.accumulate("subjectName", student.getSubjectName());
                obj.accumulate("name", student.getName());
                obj.accumulate("studentCode", student.getStudentCode());
                obj.accumulate("packageCode", StringUtils.trimToEmpty(student.getPackageCode()));
                obj.accumulate("paperType", StringUtils.trimToEmpty(student.getPaperType()));
                obj.accumulate("batchCode", StringUtils.trimToEmpty(student.getBatchCode()));
                obj.accumulate("sheetCount", student.getSheetCount() != null ? student.getSheetCount() : 0);
                obj.accumulate("sliceCount", student.getSliceCount() != null ? student.getSliceCount() : 0);
                obj.accumulate("answers", StringUtils.trimToEmpty(student.getAnswers()));
                obj.accumulate("upload", student.isUpload());
                obj.accumulate("absent", student.isAbsent());
                obj.accumulate("manualAbsent", student.isManualAbsent());
                obj.accumulate("breach", student.isBreach());
                obj.accumulate("objectiveScore",
                        student.getObjectiveScore() == null ? "" : format.format(student.getObjectiveScore()));
                obj.accumulate("subjectiveScore",
                        student.getSubjectiveScore() == null ? "" : format.format(student.getSubjectiveScore()));
                obj.accumulate("subjectiveStatus", student.getSubjectiveStatus().toString());
                obj.accumulate("examSite", StringUtils.trimToEmpty(student.getExamSite()));
                obj.accumulate("examRoom", StringUtils.trimToEmpty(student.getExamRoom()));
                obj.accumulate("remark", StringUtils.trimToEmpty(student.getRemark()));
                obj.accumulate("college", StringUtils.trimToEmpty(student.getCollege()));
                obj.accumulate("className", StringUtils.trimToEmpty(student.getClassName()));
                obj.accumulate("teacher", StringUtils.trimToEmpty(student.getTeacher()));
                if (student.getInspectorId() != null) {
                    obj.accumulate("inspector", getInspector(student.getInspectorId()));
                }

                try {
                    if (withScoreDetail != null && withScoreDetail.booleanValue()) {
                        // 构造客观题得分明细
                        JSONArray objective = new JSONArray();
                        List<ScoreItem> scoreList = student.getScoreList(true);
                        List<ExamQuestion> questionList = questionService.findByExamAndSubjectAndObjectiveAndPaperType(
                                student.getExamId(), student.getSubjectCode(), true, student.getPaperType());
                        int i = 0;
                        for (ScoreItem item : scoreList) {
                            i++;
                            if (questionList.size() < i) {
                                break;
                            }
                            ExamQuestion question = questionList.get(i - 1);
                            if (question.getTotalScore() == null || question.getTotalScore() == 0) {
                                continue;
                            }
                            JSONObject detail = new JSONObject();
                            detail.accumulate("mainNumber", question.getMainNumber());
                            detail.accumulate("subNumber", question.getSubNumber());
                            detail.accumulate("score", item.getScore());
                            detail.accumulate("answer", item.getAnswer());
                            objective.add(detail);
                        }
                        obj.accumulate("objectiveScoreDetail", objective);

                        // 构造主观题得分明细
                        JSONArray subjective = new JSONArray();
                        scoreList = student.getScoreList(false);
                        questionList = questionService.findByExamAndSubjectAndObjective(student.getExamId(),
                                student.getSubjectCode(), false);
                        i = 0;
                        for (ScoreItem item : scoreList) {
                            i++;
                            if (questionList.size() < i) {
                                break;
                            }
                            ExamQuestion question = questionList.get(i - 1);
                            if (question.getTotalScore() == null || question.getTotalScore() == 0) {
                                continue;
                            }
                            JSONObject detail = new JSONObject();
                            detail.accumulate("mainNumber", question.getMainNumber());
                            detail.accumulate("subNumber", question.getSubNumber());
                            detail.accumulate("score", item.getScore());
                            detail.accumulate("marker", getMarkerNames(student, question.getGroupNumber()));
                            String header = getHeaderName(student, question.getGroupNumber());
                            if (header != null) {
                                detail.accumulate("header", header);
                            }
                            detail.accumulate("groupNumber", question.getGroupNumber());
                            detail.accumulate("mainTitle", question.getMainTitle());
                            subjective.add(detail);
                        }
                        obj.accumulate("subjectiveScoreDetail", subjective);
                    }
                    // 返回评卷标记
                    if (withMarkTrack != null && withMarkTrack.booleanValue()) {
                        obj.accumulate(
                                "tags",
                                studentService.buildSliceTags(student, withGroupScoreTrack != null
                                        && withGroupScoreTrack.booleanValue()));
                    }
                    // 返回原图下载地址
                    if (withSliceUrl != null && withSliceUrl.booleanValue()) {
                        obj.accumulate(
                                "sliceUrls",
                                fileService
                                        .getSliceUris(student.getExamId(), student.getSecretNumber(), 1,
                                                student.getSliceCount()).stream()
                                        .map(uri -> fileService.getFileServer().concat(uri))
                                        .collect(Collectors.toList()));
                    }
                    array.add(obj);
                } catch (Exception e) {
                    logger.error("student api error", e);
                }
            }
        }
        return array;
    }

    @Logging(menu = "扫描端-缺考名单上传", type = LogType.UPDATE)
    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SCAN_ADMIN, Role.SCANNER })
    @RequestMapping(value = "/student/manualAbsent/{examId}", method = RequestMethod.POST)
    @ResponseBody
    public Object updateManualAbsent(HttpServletRequest request, @PathVariable Integer examId,
            @RequestBody MenualAbsentDTO[] datas) {
        ApiUser user = RequestUtils.getApiUser(request);
        Exam exam = examService.findById(examId);
        JSONArray array = new JSONArray();
        // 判断上传权限
        if (exam == null || !exam.getSchoolId().equals(user.getSchoolId())
                || !ExamStatus.START.equals(exam.getStatus()) || !ExamType.SCAN_IMAGE.equals(exam.getType())) {
            throw ApiException.EXAM_NOT_ACCESSIBLED;
        }
        studentService.clearManualAbsent(examId);
        if (datas != null && datas.length > 0) {
            for (MenualAbsentDTO dto : datas) {
                ExamStudent student = studentService.findByExamIdAndExamNumber(examId, dto.getExamNumber());
                if (student != null) {
                    studentService.updateManualAbsent(examId, student.getExamNumber(), true);
                    JSONObject obj = new JSONObject();
                    obj.accumulate("examNumber", student.getExamNumber());
                    array.add(obj);
                }
            }
        }
        return array;
    }
}
