package com.qmth.jkserver.controller.api;

import com.qmth.jkserver.common.LockService;
import com.qmth.jkserver.constant.SystemConstant;
import com.qmth.jkserver.core.exception.ApiException;
import com.qmth.jkserver.core.exception.JkServerException;
import com.qmth.jkserver.core.kj.IKjValidateAndStore;
import com.qmth.jkserver.core.kj.validate.ExamRoomSolfegeKjValidateAndStore;
import com.qmth.jkserver.core.kj.validate.NormalKjValidateAndStore;
import com.qmth.jkserver.core.kj.validate.StudentSolfegeKjValidateAndStore;
import com.qmth.jkserver.core.kj.validate.UtestKjValidateAndStore;
import com.qmth.jkserver.core.upload.RemoteNormalUtestKjFileUploader;
import com.qmth.jkserver.core.upload.RemoteSolfegeKjFileUploader;
import com.qmth.jkserver.enums.ExamFinishStatusEnum;
import com.qmth.jkserver.enums.ExamStatus;
import com.qmth.jkserver.enums.ProgressType;
import com.qmth.jkserver.model.*;
import com.qmth.jkserver.service.ExamKjHZService;
import com.qmth.jkserver.service.ExamRoomMonitorInfoService;
import com.qmth.jkserver.service.ExamStudentService;
import com.qmth.jkserver.service.JkExamPlanService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * 考试结果上传相关接口
 */
@RestController
@RequestMapping("/api/jkdevice")
public class ExamKjController {

    private Logger logger = LoggerFactory.getLogger(ExamKjController.class);

    @Resource
    @Lazy
    private JkExamPlanService examPlanService;

    @Resource
    @Lazy
    private ExamStudentService examStudentService;

    @Resource
    @Lazy
    private ExamKjHZService examKjHZService;

    @Resource
    private LockService lockService;

    @Resource
    @Lazy
    private ExamRoomMonitorInfoService examRoomMonitorInfoService;

    /**
     * 优特机考 通用机考 考试结果上传接口
     *
     * @throws Exception
     */
    @RequestMapping("/normal_utest/uploadResult/{examCode}/{placeCode}/{roomCode}")
    public Object uploadResult(HttpServletRequest request, HttpServletResponse response,
                               @PathVariable(value = "examCode", required = true) String examCode,
                               @PathVariable(value = "placeCode", required = true) String placeCode,
                               @PathVariable(value = "roomCode", required = true) String roomCode
    ) throws Exception {
        ExamPlan examPlan = examPlanService.findByExamCode(examCode);
        if (StringUtils.isEmpty(examCode) || examPlan == null) {
            throw ApiException.EXAM_CODE_INVALID;
        }
        if (!ExamStatus.PUBLISHED.equals(examPlan.getExamStatus())) {
            throw ApiException.EXAM_PLAN_UN_PUBLISHED;
        }
        //设置分布式锁超时时间30分钟
        String lockKey = examCode + placeCode + roomCode;
        boolean a = lockService.lock(lockKey, lockKey, 1800000);
        if (!a) {
            throw JkServerException.ANSWER_UPLOAD_CONFILCT;
        } else {
            logger.info("[Normal/Utest]加锁成功,examCode:" + examCode + ",placeCode:" + placeCode +
                    ",roomCode:" + roomCode);
        }
        Attachment attachment = null;
        try {
            RemoteNormalUtestKjFileUploader normalUtestKjFileUploader = new RemoteNormalUtestKjFileUploader(request, examCode);
            attachment = normalUtestKjFileUploader.execute();
            logger.info("@@考试答案文件上传读写完毕");
            //记录上传历史
            KjUploadHistory history = new KjUploadHistory();
            history.setId(SystemConstant.getDbUuid());
            history.setPlaceCode(placeCode);
            history.setRoomCode(roomCode);
//			history.setFile(attachment);
            history.setAttachmentId(attachment.getId());
            history.setExamCode(examCode);
            examKjHZService.saveHistory(history);
            if (attachment == null) {
                throw ApiException.FILE_UPLOAD_ERROR;
            } else {
                IKjValidateAndStore kjValidateStore = null;
                switch (examPlan.getExamType()) {
                    case NORMAL:
                        kjValidateStore = new NormalKjValidateAndStore(examPlan.getExamCode(), attachment.getId(), placeCode, roomCode);
                        break;
                    case UTEST:
                        kjValidateStore = new UtestKjValidateAndStore(examPlan.getExamCode(), attachment.getId(), placeCode, roomCode);
                        break;
                    default:
                        throw new ApiException(ApiException.SYSTEM_EXCEPTION.getCode(), "此接口仅仅只支持通用机考以及优特机考的考试结果上传,不支持其它类型");
                }
                kjValidateStore.execute(ProgressType.REMOTE);
                System.out.println("##考试答案文件处理完毕");
                return true;
            }
        } finally {
            //释放锁
            if (a) {
                lockService.unlock(lockKey, lockKey);
                logger.info("[Normal/Utest]锁已释放,examCode:" + examCode + ",placeCode:" + placeCode +
                        ",roomCode:" + roomCode);
            }
        }
    }

    /**
     * 视唱机考数据提交接口
     *
     * @throws Exception
     */
    @RequestMapping("/solfege/submitAnswer")
    public Object submitSolfegeKj(HttpServletRequest request, HttpServletResponse response
    ) throws Exception {
        String examCode = request.getHeader("examCode");
        if (StringUtils.isEmpty(examCode)) {
            throw ApiException.EXAM_CODE_INVALID;
        }
        ExamPlan examPlan = examPlanService.findByExamCode(examCode);
        if (examPlan == null) {
            throw ApiException.EXAM_CODE_INVALID;
        }
        if (!ExamStatus.PUBLISHED.equals(examPlan.getExamStatus())) {
            throw ApiException.EXAM_PLAN_UN_PUBLISHED;
        }
        String md5 = request.getHeader("md5");
        if (StringUtils.isEmpty(md5)) {
            throw ApiException.PARAM_MD5_MISSING;
        }
        String ticketNumber = request.getHeader("ticketNumber");
        if (StringUtils.isEmpty(ticketNumber)) {
            throw ApiException.PARAM_TICKET_NUMBER_IS_MISSING;
        }
        ExamStudent examStudent = examStudentService.findSolfegeStudent(examCode, ticketNumber);
        if (examStudent == null) {
            throw new JkServerException("无法获取到视唱的考务考生,考试识别码:" + examCode + ",准考证号：" + ticketNumber);
        }
        //加锁
        String lockKey = examCode + ticketNumber + "-solfege-answer";
        boolean a = lockService.lock(lockKey, lockKey, 1800000);
        if (!a) {
            throw JkServerException.STUDENT_ANSWER_UPLOAD_CONFILCT;
        } else {
            logger.info("[Solfege]加锁成功,考试识别码:" + examCode +
                    ",准考证号:" + ticketNumber);
        }
        try {
            RemoteSolfegeKjFileUploader remoteSolfegeKjFileUploader = new RemoteSolfegeKjFileUploader(
                    request, examCode, "zip");
            Attachment attachment = remoteSolfegeKjFileUploader.execute();
            //记录上传历史
            KjUploadHistory history = new KjUploadHistory();
            history.setId(SystemConstant.getDbUuid());
            history.setExamCode(examCode);
//			history.setStudent(examStudent);
//			history.setFile(attachment);
            history.setStudentId(examStudent.getId());
            history.setAttachmentId(attachment.getId());
            examKjHZService.saveHistory(history);
            StudentSolfegeKjValidateAndStore kjValidateAndStore = new StudentSolfegeKjValidateAndStore(examPlan,
                    examStudent, attachment);
            kjValidateAndStore.execute();
        } finally {
            if (a) {
                lockService.unlock(lockKey, lockKey);
                logger.info("[Solfege]锁已释放,考试识别码:" + examCode + ",准考证号:" + ticketNumber);
            }
        }
        return true;
    }

    /**
     * 视唱机考考务数据提交接口
     *
     * @throws Exception
     */
    @RequestMapping("/solfege/submitKwFile")
    public Object submitKwFile(HttpServletRequest request, HttpServletResponse response
    ) throws Exception {
        String examCode = request.getHeader("examCode");
        if (StringUtils.isEmpty(examCode)) {
            throw ApiException.EXAM_CODE_INVALID;
        }
        ExamPlan examPlan = examPlanService.findByExamCode(examCode);
        if (examPlan == null) {
            throw ApiException.EXAM_CODE_INVALID;
        }
        if (!ExamStatus.PUBLISHED.equals(examPlan.getExamStatus())) {
            throw ApiException.EXAM_PLAN_UN_PUBLISHED;
        }
        String md5 = request.getHeader("md5");
        if (StringUtils.isEmpty(md5)) {
            throw ApiException.PARAM_MD5_MISSING;
        }
        String placeCode = request.getHeader("placeCode");
        if (StringUtils.isEmpty(placeCode)) {
            throw JkServerException.withFieldValidateError("placeCode is null");
        }
        String roomCode = request.getHeader("roomCode");
        if (StringUtils.isEmpty(roomCode)) {
            throw JkServerException.withFieldValidateError("roomCode is null");
        }
        //加锁
        String lockKey = examCode + placeCode + roomCode + "-solfege-kw";
        boolean a = lockService.lock(lockKey, lockKey, 1800000);
        if (!a) {
            throw JkServerException.ANSWER_UPLOAD_CONFILCT;
        } else {
            logger.info("[Solfege]加锁成功,考试识别码:" + examCode +
                    ",考点代码:" + placeCode + ",roomCode:" + roomCode);
        }
        RemoteSolfegeKjFileUploader remoteSolfegeKjFileUploader = new RemoteSolfegeKjFileUploader(
                request, examCode, "qm");
        Attachment attachment = remoteSolfegeKjFileUploader.execute();
        //记录上传历史
        KjUploadHistory history = new KjUploadHistory();
        history.setId(SystemConstant.getDbUuid());
        history.setExamCode(examCode);
        history.setPlaceCode(placeCode);
        history.setRoomCode(roomCode);
//        history.setFile(attachment);
        history.setAttachmentId(attachment.getId());
        examKjHZService.saveHistory(history);
        try {
            ExamRoomSolfegeKjValidateAndStore kjValidateAndStore = new ExamRoomSolfegeKjValidateAndStore(
                    examPlan, attachment, false, placeCode, roomCode);
            kjValidateAndStore.execute(ProgressType.REMOTE);
        } finally {
            if (a) {
                lockService.unlock(lockKey, lockKey);
                logger.info("[Solfege]锁已经释放,考试识别码:" + examCode +
                        ",考点代码:" + placeCode + ",roomCode:" + roomCode);
            }
        }
        return true;
    }

    /**
     * 监考端上传考场状态的接口
     *
     * @throws Exception
     */
    @RequestMapping("/upload_room_status")
    public Object uploadStudentStatus(HttpServletRequest request, HttpServletResponse response
    ) throws Exception {
        String examCode = request.getHeader("examCode");
        if (StringUtils.isEmpty(examCode)) {
            throw ApiException.EXAM_CODE_INVALID;
        }
        ExamPlan examPlan = examPlanService.findByExamCode(examCode);
        if (examPlan == null) {
            throw ApiException.EXAM_CODE_INVALID;
        }
        if (!ExamStatus.PUBLISHED.equals(examPlan.getExamStatus())) {
            throw ApiException.EXAM_PLAN_UN_PUBLISHED;
        }
        String placeCode = request.getHeader("placeCode");
        if (StringUtils.isEmpty(placeCode)) {
            throw JkServerException.withFieldValidateError("placeCode is null");
        }
        String roomCode = request.getHeader("roomCode");
        if (StringUtils.isEmpty(roomCode)) {
            throw JkServerException.withFieldValidateError("roomCode is null");
        }
        String json = request.getParameter("json");
        JSONArray jsonArray = new JSONArray(json);
        List<ExamRoomMonitorInfo> saveList = new ArrayList<ExamRoomMonitorInfo>();
        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            ExamRoomMonitorInfo examRoomMonitorInfo = new ExamRoomMonitorInfo();
            examRoomMonitorInfo.setId(SystemConstant.getDbUuid());
            examRoomMonitorInfo.setExamCode(examCode);
            examRoomMonitorInfo.setPlaceCode(placeCode);
            examRoomMonitorInfo.setRoomCode(roomCode);
            examRoomMonitorInfo.setCourseCode(jsonObject.getString("courseCode"));
            examRoomMonitorInfo.setLoginCount(Integer.parseInt(jsonObject.getString("loginCount")));
            examRoomMonitorInfo.setContactErrorCount(Integer.parseInt(jsonObject.getString("contactErrorCount")));
            examRoomMonitorInfo.setCreateTime(System.currentTimeMillis());
            saveList.add(examRoomMonitorInfo);
        }
        examRoomMonitorInfoService.remove(examCode, placeCode, roomCode);
        examRoomMonitorInfoService.saveOrUpdateBatch(saveList);
        return true;
    }

    @ApiOperation(value = "推送考试状态接口")
    @RequestMapping(value = "/exam_status/push", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "获取检录状态接口", response = Object.class)})
    public Object getExamStudentRegistration(@ApiParam(value = "考试识别码", required = true) @RequestParam String examCode,
                                             @ApiParam(value = "科目编码", required = true) @RequestParam String courseCode,
                                             @ApiParam(value = "准考证号", required = true) @RequestParam String ticketNumber,
                                             @ApiParam(value = "考试状态", required = true) @RequestParam ExamFinishStatusEnum examStatus) {

        return examStudentService.updateExamStudentExamStatus(examCode, courseCode, ticketNumber, examStatus);
    }
}
