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

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import cn.com.qmth.stmms.admin.dto.SubjectiveQuestionDTO;
import cn.com.qmth.stmms.admin.thread.DataSyncThread;
import cn.com.qmth.stmms.admin.thread.OnlineExamThread;
import cn.com.qmth.stmms.admin.utils.HttpUtil;
import cn.com.qmth.stmms.biz.exam.model.DataSync;
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.service.FileService;
import cn.com.qmth.stmms.biz.lock.LockService;
import cn.com.qmth.stmms.common.annotation.Logging;
import cn.com.qmth.stmms.common.annotation.RoleRequire;
import cn.com.qmth.stmms.common.enums.ExamSource;
import cn.com.qmth.stmms.common.enums.LockType;
import cn.com.qmth.stmms.common.enums.LogType;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.RequestUtils;

@Controller
@RequestMapping("/admin/exam/data/sync")
public class DataSyncController extends BaseExamController {

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

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private ExamStudentService studentService;

    @Autowired
    private ExamQuestionService questionService;

    @Qualifier("task-executor")
    @Autowired
    private AsyncTaskExecutor taskExecutor;

    @Autowired
    private LockService lockService;

    @Autowired
    private ExamService examService;

    @Autowired
    private DataSyncService dataSyncService;

    @Autowired
    private FileService fileService;

    @Autowired
    private MarkGroupService groupService;

    @Value("${qmth.examcloud.host}")
    private String host;

    @Value("${qmth.examcloud.port}")
    private String port;

    @Value("${qmth.examcloud.rootOrgId}")
    private String rootOrgId;

    @Value("${qmth.examcloud.appId}")
    private String appId;

    @Value("${qmth.examcloud.secretKey}")
    private String secretKey;

    @Value("${qmth.examcloud.subject.uri}")
    private String subjectUri;

    @Value("${qmth.examcloud.subject.paper.uri}")
    private String subjectPaperUri;

    @Value("${qmth.examcloud.student.uri}")
    private String studentUri;

    @Value("${qmth.examcloud.pageSize}")
    private Integer pageSize;

    public static final String ERROR_CODE = "EX-101444";

    @RequestMapping()
    public ModelAndView index(HttpServletRequest request, @RequestParam Integer examId) {
        DataSync dataSync = dataSyncService.findByExamId(examId);
        if (dataSync == null) {
            dataSync = new DataSync();
            dataSync.setExamId(examId);
            dataSync.setRootOrgId(rootOrgId);
            dataSync.setStudentUrl(host + ":" + port + studentUri);
            dataSync.setSubjectUrl(host + ":" + port + subjectUri);
            dataSync.setSubjectPaperUrl(host + ":" + port + subjectPaperUri);
            dataSync.setAppId(appId);
            dataSync.setAccessKey(secretKey);
        }
        ModelAndView view = new ModelAndView("modules/exam/dataSync");
        view.addObject("running", lockService.isLocked(LockType.DATA_SYNC, examId));
        view.addObject("exam", examService.findById(examId));
        view.addObject("sourceList", ExamSource.values());
        view.addObject("dataSync", dataSync);
        return view;
    }

    @Logging(menu = "数据同步", type = LogType.UPDATE)
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String save(HttpServletRequest request, DataSync dataSync, RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        if (lockService.trylock(LockType.DATA_SYNC, examId)) {
            if (dataSync.getSource().equals(ExamSource.EXAM_CLOUD)) {
                DataSyncThread thread = new DataSyncThread(dataSync, pageSize, lockService, dataSyncService,
                        examService, studentService, subjectService, fileService);
                taskExecutor.submit(thread);
            } else if (dataSync.getSource().equals(ExamSource.ONLINE_EXAM)) {
                OnlineExamThread thread = new OnlineExamThread(dataSync, lockService, dataSyncService, examService,
                        studentService, subjectService, questionService, groupService, fileService);
                taskExecutor.submit(thread);
            }
        }
        dataSync = dataSyncService.findByExamId(examId);
        if (lockService.isLocked(LockType.DATA_SYNC, examId) || (dataSync != null && dataSync.isFinished())) {
            addMessage(redirectAttributes, "创建成功");
        } else {
            addMessage(redirectAttributes, "同步失败");
        }
        return "redirect:/admin/exam/list";
    }

    @Logging(menu = "导出多媒体试卷结构", type = LogType.EXPORT)
    @RequestMapping(value = "/export", method = RequestMethod.GET)
    @RoleRequire(Role.SCHOOL_ADMIN)
    public ModelAndView exportFile(@RequestParam Integer examId, HttpServletRequest request,
            HttpServletResponse response, RedirectAttributes redirectAttributes) {
        DataSync sync = dataSyncService.findByExamId(examId);
        try {
            List<SubjectiveQuestionDTO> list = getPaperStruct(sync);
            new ExportExcel("主观题数据", SubjectiveQuestionDTO.class, 2).setDataList(list).write(response, "主观题数据.xlsx")
                    .dispose();
            RequestUtils.setLog(request, "");
            return null;
        } catch (Exception e) {
            log.error("export sync subject:", e);
            addMessage(redirectAttributes, "导出数据失败！失败信息：" + e.getMessage());
        }
        return new ModelAndView("redirect:/admin/exam/data/sync?examId=" + examId);
    }

    private List<SubjectiveQuestionDTO> getPaperStruct(DataSync sync) throws Exception {
        List<SubjectiveQuestionDTO> list = new ArrayList<SubjectiveQuestionDTO>();

        HttpUtil subjectHttp = new HttpUtil(sync.getSubjectUrl(), sync.getAccessKey(), sync.getAppId(),
                sync.getRootOrgId());
        JSONObject datas = new JSONObject();
        datas.accumulate("examId", Long.parseLong(sync.getCloudExamId()));
        String subjectResult = subjectHttp.httpAction(null, datas.toString());
        JSONObject subjectJson = JSONObject.fromObject(subjectResult);

        // 考试返回错误，无法创建阅卷
        if (ERROR_CODE.equals(subjectJson.getString("code"))) {
            log.error("data sync exception for cloud examId=" + sync.getCloudExamId(), subjectJson.getString("desc"));
            throw new Exception(subjectJson.getString("desc"));
        }

        JSONArray subjectArray = subjectJson.getJSONArray("paperStructList");
        for (int i = 0; i < subjectArray.size(); i++) {
            JSONObject subject = subjectArray.getJSONObject(i);
            JSONArray questionArray = subject.getJSONArray("questions");
            for (int j = 0; j < questionArray.size(); j++) {
                JSONObject question = questionArray.getJSONObject(j);
                SubjectiveQuestionDTO questionDTO = new SubjectiveQuestionDTO();
                questionDTO.setSubjectCode(subject.getString("subjectCode"));
                questionDTO.setSubjectName(subject.getString("subjectName"));
                questionDTO.setMainNumber(question.getInt("mainNumber"));
                questionDTO.setTitle(question.getString("mainTitle"));
                questionDTO.setSubNumber(question.getString("subNumber"));
                questionDTO.setTotalScore(question.getDouble("totalScore"));
                list.add(questionDTO);
            }
        }
        return list;
    }
}
