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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import cn.com.qmth.stmms.api.exception.ApiException;
import cn.com.qmth.stmms.biz.exam.model.AnswerCard;
import cn.com.qmth.stmms.biz.exam.model.AnswerCardSubject;
import cn.com.qmth.stmms.biz.exam.model.Exam;
import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.service.AnswerCardService;
import cn.com.qmth.stmms.biz.exam.service.ExamService;
import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
import cn.com.qmth.stmms.biz.file.service.FileService;
import cn.com.qmth.stmms.common.annotation.RoleRequire;
import cn.com.qmth.stmms.common.domain.ApiUser;
import cn.com.qmth.stmms.common.enums.CardSource;
import cn.com.qmth.stmms.common.enums.ExamStatus;
import cn.com.qmth.stmms.common.enums.ExamType;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.utils.RequestUtils;

@Controller("cardController")
@RequestMapping("/api/card")
public class CardController extends BaseApiController {

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

    @Autowired
    private FileService fileService;

    @Autowired
    private ExamService examService;

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private AnswerCardService answerCardService;

    private Exam validateExam(ApiUser au, Integer examId, ExamType... types) {
        Exam exam = examService.findById(examId);
        if (exam == null || !validateSchool(au.getSchoolId(), exam.getSchoolId())
                || exam.getStatus() != ExamStatus.START) {
            throw ApiException.EXAM_NOT_ACCESSIBLED;
        }
        if (types != null && types.length > 0 && !Arrays.asList(types).contains(exam.getType())) {
            throw ApiException.QUERY_PARAM_ERROR.replaceMessage("exam type invalid");
        }
        return exam;
    }

    private ExamSubject validateExamSubject(Integer examId, String subjectCode) {
        ExamSubject subject = subjectService.find(examId, subjectCode);
        if (subject == null) {
            throw ApiException.QUERY_PARAM_ERROR.appendMessage(": subjectCode error");
        }
        return subject;
    }

    @RequestMapping(value = "/answer/save", method = RequestMethod.POST)
    @RoleRequire({ Role.SCHOOL_ADMIN })
    @ResponseBody
    public JSONObject answerCardSave(HttpServletRequest request, @RequestParam Integer examId,
            @RequestParam(required = false) Integer number, @RequestParam(required = false) String subjectCode,
            @RequestParam String source, @RequestParam Integer paperCount, @RequestParam Boolean singlePage,
            @RequestParam Boolean needAdapte, @RequestParam(required = false) String parameter,
            @RequestParam(required = false) Integer dpi, @RequestParam(required = false) String remark,
            @RequestParam String md5, @RequestParam String sliceConfig, @RequestParam MultipartFile file) {
        ApiUser au = RequestUtils.getApiUser(request);
        subjectCode = StringUtils.trimToNull(subjectCode);
        validateExam(au, examId, ExamType.SCAN_IMAGE);
        if (subjectCode != null) {
            validateExamSubject(examId, subjectCode);
        }
        try {
            if (number != null) {
                fileService.uploadAnswerCard(file.getInputStream(), md5, examId, number);
            } else {
                number = answerCardService.findMaxNumberByExamId(examId) + 1;
                fileService.uploadAnswerCard(file.getInputStream(), md5, examId, number);
            }
            AnswerCard card = answerCardService.findByExamIdAndNumber(examId, number);
            if (card == null) {
                card = new AnswerCard();
                card.setExamId(examId);
                card.setNumber(number);
            }
            card.setDpi(dpi);
            card.setSliceConfig(sliceConfig);
            card.setMd5(md5);
            card.setNeedAdapte(needAdapte);
            card.setPaperCount(paperCount);
            card.setParameter(parameter);
            card.setRemark(remark);
            card.setSinglePage(singlePage);
            card.setSource(CardSource.CLIENT);
            card.setUpdateTime(new Date());
            answerCardService.save(card, subjectCode);
            JSONObject result = new JSONObject();
            result.accumulate("number", number);
            result.accumulate("updateTime", System.currentTimeMillis());
            return result;
        } catch (Exception e) {
            log.error("card upload error", e);
            throw ApiException.FILE_UPLOAD_ERROR.replaceMessage("card upload error: " + e.getMessage());
        }
    }

    @RequestMapping(value = "/answer/query", method = RequestMethod.POST)
    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SCAN_ADMIN })
    @ResponseBody
    public JSONArray answerQuery(HttpServletRequest request, @RequestParam Integer examId,
            @RequestParam(required = false) Integer number) {
        ApiUser au = RequestUtils.getApiUser(request);
        validateExam(au, examId, ExamType.SCAN_IMAGE);
        JSONArray array = new JSONArray();
        List<AnswerCard> cards = new ArrayList<AnswerCard>();
        if (number == null) {
            cards = answerCardService.findByExamId(examId);
        } else {
            cards.add(answerCardService.findByExamIdAndNumber(examId, number));
        }
        for (AnswerCard answerCard : cards) {
            JSONObject result = new JSONObject();
            result.accumulate("examId", answerCard.getExamId());
            result.accumulate("number", answerCard.getNumber());
            result.accumulate("code", StringUtils.trimToEmpty(answerCard.getCode()));
            result.accumulate("dpi", answerCard.getDpi() == null ? 0 : answerCard.getDpi());
            List<AnswerCardSubject> subjects = answerCardService.getSubjectByExamIdAndNumber(answerCard.getExamId(),
                    answerCard.getNumber());
            JSONArray subjectList = new JSONArray();
            for (AnswerCardSubject a : subjects) {
                subjectList.add(a.getSubjectCode());
            }
            result.accumulate("subjectList", subjectList);
            result.accumulate("paperCount", answerCard.getPaperCount() == null ? "" : answerCard.getPaperCount());
            result.accumulate("path", fileService.getAnswerCardUri(answerCard.getExamId(), answerCard.getNumber()));
            result.accumulate("md5", answerCard.getMd5());
            result.accumulate("source", answerCard.getSource().toString());
            result.accumulate("parameter", StringUtils.trimToEmpty(answerCard.getParameter()));
            result.accumulate("singlePage", answerCard.getSinglePage());
            result.accumulate("remark", StringUtils.trimToEmpty(answerCard.getRemark()));
            result.accumulate("updateTime", answerCard.getUpdateTime().getTime());
            result.accumulate("sliceConfig", StringUtils.trimToEmpty(answerCard.getSliceConfig()));
            array.add(result);
        }
        return array;
    }

    @RequestMapping(value = "/answer/delete", method = RequestMethod.POST)
    @RoleRequire({ Role.SCHOOL_ADMIN })
    @ResponseBody
    public JSONObject answerDelete(HttpServletRequest request, @RequestParam Integer examId,
            @RequestParam Integer number) {
        ApiUser au = RequestUtils.getApiUser(request);
        validateExam(au, examId, ExamType.SCAN_IMAGE);
        AnswerCard card = answerCardService.findByExamIdAndNumber(examId, number);
        if (card == null) {
            throw ApiException.QUERY_PARAM_ERROR.appendMessage(": number error");
        }
        answerCardService.delete(card);
        JSONObject result = new JSONObject();
        result.accumulate("updateTime", System.currentTimeMillis());
        return result;
    }

}
