package cn.com.qmth.stmms.admin.thread;

import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.qmth.stmms.admin.utils.OnlineExamHttpUtil;
import cn.com.qmth.stmms.biz.exam.model.DataSync;
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.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
import cn.com.qmth.stmms.biz.exam.service.DataSyncService;
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.exam.service.ExamSubjectService;
import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
import cn.com.qmth.stmms.biz.file.enums.FormatType;
import cn.com.qmth.stmms.biz.file.service.FileService;
import cn.com.qmth.stmms.biz.lock.LockService;
import cn.com.qmth.stmms.common.enums.LockType;
import cn.com.qmth.stmms.common.enums.MarkMode;
import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
import cn.com.qmth.stmms.common.utils.BigDecimalUtils;

import com.aliyun.oss.common.utils.BinaryUtil;

public class OnlineExamThread implements Runnable {

    protected static Logger log = LoggerFactory.getLogger(OnlineExamThread.class);

    private DataSync dataSync;

    private ExamStudentService studentService;

    private ExamSubjectService subjectService;

    private ExamQuestionService questionService;

    private MarkGroupService groupService;

    private ExamService examService;

    private FileService fileService;

    private LockService lockService;

    private DataSyncService dataSyncService;

    private OnlineExamHttpUtil studentHttp;

    private OnlineExamHttpUtil subjectPaperHttp;

    public static final String PAPER_STRUCT = "paperStructList";

    public static final String ID = "id";

    public static final String EXAM_ID = "examId";

    public static final String PAPER_ID = "paperId";

    public static final String COURSE_CODE = "courseCode";

    public static final String COURSE_NAME = "courseName";

    public static final String ANSWERS = "answers";

    public static final String RECORDS = "records";

    public static final String START_ID = "examStudentIdGt";

    public static final String DEFAULT_NULL = "#";

    public static final String COUNT = "count";

    public static final String FILTER = "filter";

    public OnlineExamThread(DataSync dataSync, LockService lockService, DataSyncService dataSyncService,
            ExamService examService, ExamStudentService studentService, ExamSubjectService subjectService,
            ExamQuestionService questionService, MarkGroupService groupService, FileService fileService) {
        this.dataSync = dataSync;
        this.lockService = lockService;
        this.dataSyncService = dataSyncService;
        this.examService = examService;
        this.studentService = studentService;
        this.subjectService = subjectService;
        this.questionService = questionService;
        this.groupService = groupService;
        this.fileService = fileService;
        this.studentHttp = new OnlineExamHttpUtil(dataSync.getAccessKey(), dataSync.getAccessSecret(),
                dataSync.getStudentUrl());
        this.subjectPaperHttp = new OnlineExamHttpUtil(dataSync.getAccessKey(), dataSync.getAccessSecret(),
                dataSync.getSubjectPaperUrl());
    }

    @Override
    public void run() {
        log.info("start online data sync for examId=" + dataSync.getExamId());
        try {
            // 获取考试信息
            Exam exam = examService.findById(dataSync.getExamId());
            DataSync sync = dataSyncService.findByExamId(dataSync.getExamId());
            if (sync == null) {
                sync = dataSync;
                sync.setCreateTime(new Date());
                dataSyncService.save(sync);
            }
            Map<String, ExamSubject> subjectMap = new HashMap<String, ExamSubject>();
            Map<String, Object> datas = new HashMap<String, Object>();
            datas.put(EXAM_ID, dataSync.getCloudExamId());

            // 获取考生
            Long startId = 0L;
            if (sync.getNextId() != null) {
                startId = sync.getNextId();
            }
            while (startId != null) {
                datas.put(START_ID, startId);
                String studentResult = studentHttp.httpAction(null, datas);
                JSONArray studentArray = JSONArray.fromObject(studentResult);
                if (studentArray.size() == 0) {
                    startId = null;
                }
                for (int i = 0; i < studentArray.size(); i++) {
                    JSONObject student = studentArray.getJSONObject(i);
                    String subjectName = student.getString(COURSE_NAME);
                    JSONArray recordArray = student.getJSONArray(RECORDS);
                    List<ExamStudent> list = new ArrayList<ExamStudent>();
                    Date now = new Date();
                    for (int j = 0; j < recordArray.size(); j++) {
                        JSONObject record = recordArray.getJSONObject(j);
                        // 保存科目试卷
                        datas.put(ID, record.getString(PAPER_ID));
                        datas.put(FILTER, "subjective");
                        String paperResult = subjectPaperHttp.httpAction(null, datas);
                        JSONObject paperJson = JSONObject.fromObject(paperResult);
                        String subjectCode = paperJson.getString(ID);
                        this.saveSubject(subjectMap, exam.getId(), subjectCode, subjectName, paperResult);
                        // 保存考生数据
                        ExamStudent examStudent = getExamStudent(exam, student, subjectCode, record.getString(ID), now);
                        list.add(examStudent);
                        // 保存考生作答
                        String answerJson = record.getString(ANSWERS);
                        byte[] jsonData = answerJson.getBytes(StandardCharsets.UTF_8);
                        fileService.uploadJson(new ByteArrayInputStream(jsonData), BinaryUtil.encodeMD5(jsonData),
                                exam.getId(), examStudent.getSecretNumber());
                        studentService.save(examStudent);
                        subjectService.updateUploadCount(exam.getId(), subjectCode,
                                (int) studentService.countUploadedByExamIdAndSubjectCode(exam.getId(), subjectCode));
                    }
                    startId = student.getLong(ID);
                }
                sync.setUpdateTime(new Date());
                sync.setNextId(startId);
                dataSyncService.save(sync);
            }

            sync.setFinished(true);
            dataSyncService.save(sync);
        } catch (Exception e) {
            log.error("data sync exception for examId=" + dataSync.getExamId(), e);
        } finally {
            lockService.unlock(LockType.DATA_SYNC, dataSync.getExamId());
            log.info("finish data sync for examId=" + dataSync.getExamId());
        }
    }

    private ExamStudent getExamStudent(Exam exam, JSONObject student, String paperCode, String examNumber, Date now) {
        ExamStudent examStudent = new ExamStudent();
        examStudent.setExamId(exam.getId());
        examStudent.setStudentCode(student.getString("identity"));
        examStudent.setName(student.getString("name"));
        examStudent.setSubjectCode(paperCode);
        examStudent.setSubjectName(student.getString(COURSE_NAME));
        examStudent.setExamNumber(examNumber);
        examStudent.setSecretNumber(examNumber);
        examStudent.setCollege(DEFAULT_NULL);
        examStudent.setClassName(DEFAULT_NULL);
        examStudent.setTeacher(DEFAULT_NULL);
        examStudent.setCampusName(DEFAULT_NULL);
        examStudent.setPaperType(DEFAULT_NULL);
        examStudent.setSchoolId(exam.getSchoolId());
        examStudent.setAbsent(false);
        examStudent.setUpload(true);
        examStudent.setManualAbsent(false);
        examStudent.setBreach(false);
        examStudent.setException(false);
        examStudent.setSliceCount(0);
        examStudent.setSheetCount(0);
        examStudent.setObjectiveScore(0d);
        examStudent.setSubjectiveScore(0d);
        examStudent.setSubjectiveStatus(SubjectiveStatus.UNMARK);
        examStudent.setAnswers(null);
        examStudent.setBatchCode(null);
        examStudent.setUploadTime(now);
        examStudent.setInspectCount(0);
        return examStudent;
    }

    private ExamSubject saveSubject(Map<String, ExamSubject> subjectMap, Integer examId, String subjectCode,
            String subjectName, String paperResult) throws Exception {
        ExamSubject subject = subjectMap.get(subjectCode);
        if (subject != null) {
            return subject;
        }
        subject = subjectService.find(examId, subjectCode);
        if (subject != null) {
            subjectMap.put(subjectCode, subject);
            return subject;
        }
        // 保存paperjson
        byte[] paperData = paperResult.getBytes(StandardCharsets.UTF_8);
        fileService.uploadPaper(new ByteArrayInputStream(paperData), BinaryUtil.encodeMD5(paperData), examId,
                subjectCode, FormatType.JSON);
        // 保存subject
        subject = new ExamSubject();
        subject.setExamId(examId);
        subject.setCode(subjectCode);
        subject.setName(subjectName);
        subject.setPaperFileType(FormatType.JSON);
        subject.setAnswerFileType(FormatType.JSON);
        subject.setObjectiveScore(0d);
        subject.setSubjectiveScore(0d);
        subject.setTotalScore(0d);
        subject.setUploadCount(0);
        subject.setDisplayQuestionName(false);
        subject.setInspectRound(1);
        subject.setSelective(false);
        subjectService.save(subject);
        subjectMap.put(subjectCode, subject);
        // 保存question
        JSONObject paperJson = JSONObject.fromObject(paperResult);
        JSONArray questionArray = JSONArray.fromObject(paperJson.getString("details"));
        BigDecimal totalScore = BigDecimal.ZERO;
        List<ExamQuestion> list = new ArrayList<>();
        for (int i = 0; i < questionArray.size(); i++) {
            JSONObject questionJson = questionArray.getJSONObject(i);
            int mainNumber = questionJson.getInt("number");
            String mainTitle = questionJson.getString("name");
            JSONArray qArray = questionJson.getJSONArray("questions");
            for (int j = 0; j < qArray.size(); j++) {
                JSONObject sub = qArray.getJSONObject(j);
                if (sub.get("subQuestions") != null) {
                    JSONArray subJson = sub.getJSONArray("subQuestions");
                    for (int k = 0; k < subJson.size(); k++) {
                        JSONObject question = subJson.getJSONObject(k);
                        ExamQuestion q = new ExamQuestion();
                        q.setExamId(examId);
                        q.setSubjectCode(subjectCode);
                        q.setPaperType("#");
                        q.setObjective(false);
                        q.setMainNumber(mainNumber);
                        String subNumber = sub.getString("number") + "-" + question.getString("number");
                        q.setSubNumber(subNumber);
                        q.setMainTitle(mainTitle);
                        q.setGroupNumber(1);
                        double score = question.getDouble("score");
                        q.setTotalScore(score);
                        q.setIntervalScore(0.5);
                        totalScore = totalScore.add(BigDecimal.valueOf(score));
                        list.add(q);
                    }
                } else {
                    ExamQuestion q = new ExamQuestion();
                    q.setExamId(examId);
                    q.setSubjectCode(subjectCode);
                    q.setPaperType("#");
                    q.setObjective(false);
                    q.setMainNumber(mainNumber);
                    String subNumber = sub.getString("number");
                    q.setSubNumber(subNumber);
                    q.setMainTitle(mainTitle);
                    q.setGroupNumber(1);
                    double score = sub.getDouble("score");
                    q.setTotalScore(score);
                    q.setIntervalScore(0.5);
                    totalScore = totalScore.add(BigDecimal.valueOf(score));
                    list.add(q);
                }
            }
        }
        questionService.save(list);
        // 保存group
        MarkGroup group = new MarkGroup(examId, subjectCode, 1, null, totalScore.doubleValue(), 0d, null, null,
                MarkMode.COMMON.toString(), 0, false, false, null, false);
        groupService.save(group);

        subjectService.updateScore(examId, subjectCode, false, totalScore.doubleValue());
        return subject;
    }
}
