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

import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang.StringUtils;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.qmth.boot.tools.io.ZipWriter;

import cn.com.qmth.stmms.admin.dto.ExamStudentDTO;
import cn.com.qmth.stmms.admin.dto.ScoreEditDTO;
import cn.com.qmth.stmms.admin.dto.StudentScoreDetail;
import cn.com.qmth.stmms.admin.dto.StudentScoreExportDTO;
import cn.com.qmth.stmms.admin.utils.ExportStudentExcel;
import cn.com.qmth.stmms.admin.utils.ExportStudentScoreExcel;
import cn.com.qmth.stmms.biz.exam.model.Exam;
import cn.com.qmth.stmms.biz.exam.model.ExamPackage;
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.query.ExamStudentSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamPackageService;
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.file.service.FileService;
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.WebUser;
import cn.com.qmth.stmms.common.enums.LogType;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.utils.Encodes;
import cn.com.qmth.stmms.common.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.RequestUtils;
import net.sf.json.JSONObject;

@Controller
@RequestMapping("/admin/exam/score")
public class ScoreController extends BaseExamController {

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private ExamStudentService studentService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private ExamPackageService packageService;

    @Autowired
    private ExamService examService;

    @Autowired
    private FileService fileService;

    public static final String UN_SELECTIVE_SCORE = "-1";

    @Logging(menu = "成绩查询", type = LogType.QUERY)
    @RequestMapping
    public ModelAndView list(HttpServletRequest request, ExamStudentSearchQuery query,
            @RequestParam(defaultValue = "0") Integer filter) {
        WebUser wu = RequestUtils.getWebUser(request);
        ModelAndView view = new ModelAndView("modules/exam/scoreList");
        int examId = getSessionExamId(request);
        query.setExamId(examId);
        if (filter == 1) {
            query.setObjectiveScore(0d);
            query.setSubjectiveScoreGt(0d);
        } else if (filter == 2) {
            query.setObjectiveScoreGt(0d);
            query.setSubjectiveScore(0d);
        }
        if ((wu.isSubjectHeader() || wu.isSchoolViewer()) && StringUtils.isBlank(query.getSubjectCode())) {
            String subjectCodeIn = StringUtils.join(wu.getSubjectCodeSet(), ",");
            query.setSubjectCodeIn(subjectCodeIn);
        }
        query.setRole(wu.getRole());
        query.setUserId(wu.getId());
        query = studentService.findByQueryPlus(query);
        for (ExamStudent student : query.getResult()) {
            buildSheetUrl(student);
            buildPackageUrl(student);
            buildAnswerUrl(student);
        }
        String logMessage = getLogMessage(query, filter);
        RequestUtils.setLog(request, logMessage);
        Exam exam = examService.findById(examId);
        String exportMessage = StringUtils.isNotBlank(query.getSubjectCode()) ? subjectService.enableExport(exam,
                query.getSubjectCode()) : null;
        if (exportMessage != null) {
            view.addObject("exportMessage", exportMessage);
            view.addObject("enableExport", false);
        } else {
            view.addObject("enableExport", true);
        }
        view.addObject("subjectList", getExamSubject(examId, wu));
        view.addObject("examType", exam.getType());
        view.addObject("query", query);
        view.addObject("filter", filter);
        view.addObject("fileServer", fileService.getFileServer());
        return view;
    }

    private String getLogMessage(ExamStudentSearchQuery query, Integer filter) {
        StringBuilder builder = new StringBuilder();
        if (StringUtils.isNotBlank(query.getName())) {
            builder.append("姓名:").append(query.getName()).append(";");
        }
        if (StringUtils.isNotBlank(query.getExamNumber())) {
            builder.append("准考证号:").append(query.getExamNumber()).append(";");
        }
        if (StringUtils.isNotBlank(query.getStudentCode())) {
            builder.append("学号:").append(query.getStudentCode()).append(";");
        }
        if (StringUtils.isNotBlank(query.getSubjectCode())) {
            builder.append("科目代码:").append(query.getSubjectCode()).append(";");
        }
        if (filter == 1) {
            builder.append("客观0分，主观有分").append(";");
        }
        if (filter == 2) {
            builder.append("客观有分，主观0分").append(";");
        }
        if (query.getAbsent() != null) {
            builder.append("缺考:").append(query.getAbsent() ? "缺考" : "正常").append(";");
        }
        if (query.getUpload() != null) {
            builder.append("上传:").append(query.getUpload() ? "已上传" : "未上传").append(";");
        }
        if (query.getBreach() != null) {
            builder.append("缺考:").append(query.getBreach() ? "违纪" : "正常").append(";");
        }
        if (StringUtils.isNotBlank(query.getExamSite())) {
            builder.append("考点:").append(query.getExamSite()).append(";");
        }
        if (StringUtils.isNotBlank(query.getExamRoom())) {
            builder.append("考场:").append(query.getExamRoom()).append(";");
        }
        if (StringUtils.isNotBlank(query.getCollege())) {
            builder.append("电厂:").append(query.getCollege()).append(";");
        }
        if (StringUtils.isNotBlank(query.getClassName())) {
            builder.append("机组:").append(query.getClassName()).append(";");
        }
        if (StringUtils.isNotBlank(query.getTeacher())) {
            builder.append("总评:").append(query.getTeacher()).append(";");
        }
        if (query.getStartScore() != null) {
            builder.append("总分从").append(query.getStartScore()).append("到").append(query.getEndScore()).append(";");
        }
        return builder.toString();
    }

    @Logging(menu = "分数详情", type = LogType.QUERY)
    @RequestMapping("/detail")
    public ModelAndView detail(HttpServletRequest request, @RequestParam String examNumber,
            @RequestParam String queryString) {
        int examId = getSessionExamId(request);
        ExamStudent student = studentService.findByExamIdAndExamNumber(examId, examNumber);
        if (student != null) {
            buildSheetUrl(student);
            buildPackageUrl(student);
            buildAnswerUrl(student);
            ModelAndView view = new ModelAndView("modules/exam/scoreDetail");
            view.addObject("student", student);
            view.addObject("scoreList", buildScoreList(student));
            view.addObject("fileServer", fileService.getFileServer());
            view.addObject("queryString", StringUtils.trimToEmpty(queryString));
            return view;
        } else {
            return new ModelAndView("redirect:/admin/exam/score");
        }
    }

    @Logging(menu = "修改分数详情", type = LogType.UPDATE)
    @RequestMapping("/edit")
    @ResponseBody
    @RoleRequire(Role.SCHOOL_ADMIN)
    public JSONObject edit(HttpServletRequest request, ScoreEditDTO dto) {
        JSONObject result = new JSONObject();
        int examId = getSessionExamId(request);
        ExamStudent student = studentService.findByExamIdAndExamNumber(examId, dto.getExamNumber());
        if (student != null) {
            BigDecimal oScore = BigDecimal.ZERO;
            List<ScoreItem> oList = dto.getObjectiveScoreItems();
            for (ScoreItem item : oList) {
                oScore = oScore.add(BigDecimal.valueOf(item.getScore()));
            }
            student.setObjectiveScore(oScore.doubleValue());
            student.setScoreList(oList, true);

            BigDecimal sScore = BigDecimal.ZERO;
            List<ScoreItem> sList = dto.getSubjectiveScoreItems();
            for (ScoreItem item : sList) {
                sScore = sScore.add(BigDecimal.valueOf(item.getScore()));
            }
            student.setSubjectiveScore(sScore.doubleValue());
            student.setScoreList(sList, false);

            studentService.save(student);
            result.accumulate("success", true);
        } else {
            result.accumulate("success", false);
            result.accumulate("message", "找不到对应的考生");
        }
        return result;
    }

    @Logging(menu = "导出成绩", type = LogType.EXPORT)
    @RequestMapping("/export")
    public String export(ExamStudentSearchQuery query, HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirectAttributes) {
        WebUser wu = RequestUtils.getWebUser(request);
        Exam exam = examService.findById(getSessionExamId(request));
        if (exam == null || !exam.getSchoolId().equals(wu.getUser().getSchoolId())) {
            addMessage(redirectAttributes, "请选择正确的考试");
            return "redirect:/admin/exam/score";
        }
        String fileName = "成绩单.xlsx";
        query.setExamId(exam.getId());
        Set<String> subjectSet = new HashSet<>();
        List<String> error = new ArrayList<String>();
        // 单科目导出
        if (StringUtils.isNotBlank(query.getSubjectCode())) {
            String exportMessage = subjectService.enableExport(exam, query.getSubjectCode());
            // 判断不允许导出则直接返回
            if (exportMessage != null) {
                addMessage(redirectAttributes, "该科目不能导出成绩 " + exportMessage);
                return "redirect:/admin/exam/score";
            }
            subjectSet.add(query.getSubjectCode());
        }
        // 全体科目导出
        else {
            List<ExamSubject> list = subjectService.list(exam.getId());
            if (wu.isSubjectHeader() || wu.isSchoolViewer()) {
                list = getExamSubject(exam.getId(), wu);
            }
            for (ExamSubject subject : list) {
                // 遍历所有科目，判断是否允许导出
                String meaages = subjectService.enableExport(exam, subject.getCode());
                if (meaages == null) {
                    subjectSet.add(subject.getCode());
                } else {
                    error.add(meaages);
                }
            }
            if (list.size() != subjectSet.size()) {
                fileName = "成绩单(未导出全量数据).xlsx";
            }
        }
        try {
            List<ExamStudentDTO> list = new LinkedList<>();
            // 可导出科目不为空时，才能执行查询操作
            if (!subjectSet.isEmpty()) {
                String subjectCodeIn = StringUtils.join(subjectSet, ",");
                query.setSubjectCodeIn(subjectCodeIn);
                query.setPageNumber(1);
                query.setPageSize(Integer.MAX_VALUE);
                query.setRole(wu.getRole());
                query.setUserId(wu.getId());
                query = studentService.findByQueryPlus(query);
                for (ExamStudent student : query.getResult()) {
                    if (!student.isUpload() || student.isBreach() || student.isAbsent()) {
                        student.setObjectiveScore(0d);
                        student.setSubjectiveScore(0d);
                    }
                    if (student.getSubjectiveScoreList() != null) {
                        student.setSubjectiveScoreList(student.getSubjectiveScoreList()
                                .replace(UN_SELECTIVE_SCORE, "/"));
                    }
                    list.add(new ExamStudentDTO(student));
                }
            }
            if (StringUtils.isNotBlank(query.getSubjectCode())) {
                List<String> headerList = getOptionHeader(exam.getId(), query.getSubjectCode());
                ExportStudentExcel excel = new ExportStudentExcel("成绩单", headerList, ExamStudentDTO.class);
                excel.setDataList(list, true);
                excel.write(response, fileName).dispose();
                return null;
            } else {
                response.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode("成绩单.zip"));
                ZipWriter writer = ZipWriter.create(response.getOutputStream());
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                new ExportExcel("成绩单", ExamStudentDTO.class).setDataList(list).write(os);
                byte[] value = os.toByteArray();
                writer.write(new ByteArrayInputStream(value), fileName);
                if (!error.isEmpty()) {
                    writer.write(StringUtils.join(error, ";").getBytes(), "error.txt");
                }
                writer.close();
                return null;
            }
        } catch (Exception e) {
            addMessage(redirectAttributes, "导出成绩失败！" + e.getMessage());
            return "redirect:/admin/exam/score";
        }
    }
    
    @Logging(menu = "导出成绩2", type = LogType.EXPORT)
    @RequestMapping("/export2")
    public String export2(ExamStudentSearchQuery query, HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirectAttributes) {
        WebUser wu = RequestUtils.getWebUser(request);
        Exam exam = examService.findById(getSessionExamId(request));
        if (exam == null || !exam.getSchoolId().equals(wu.getUser().getSchoolId())) {
            addMessage(redirectAttributes, "请选择正确的考试");
            return "redirect:/admin/exam/score";
        }
        String fileName = "成绩单.xlsx";
        query.setExamId(exam.getId());
        Set<String> subjectSet = new HashSet<>();
        List<String> error = new ArrayList<String>();
        // 单科目导出
        if (StringUtils.isNotBlank(query.getSubjectCode())) {
            String exportMessage = subjectService.enableExport(exam, query.getSubjectCode());
            // 判断不允许导出则直接返回
            if (exportMessage != null) {
                addMessage(redirectAttributes, "该科目不能导出成绩 " + exportMessage);
                return "redirect:/admin/exam/score";
            }
            subjectSet.add(query.getSubjectCode());
        }else {// 全体科目导出
            List<ExamSubject> list = subjectService.list(exam.getId());
            if (wu.isSubjectHeader() || wu.isSchoolViewer()) {
                list = getExamSubject(exam.getId(), wu);
            }
            for (ExamSubject subject : list) {
                // 遍历所有科目，判断是否允许导出
                String meaages = subjectService.enableExport(exam, subject.getCode());
                if (meaages == null) {
                    subjectSet.add(subject.getCode());
                } else {
                    error.add(meaages);
                }
            }
            if (list.size() != subjectSet.size()) {
                fileName = "成绩单(未导出全量数据).xlsx";
            }
        }
        try {
            List<ExamStudentDTO> list = new LinkedList<>();
            // 可导出科目不为空时，才能执行查询操作
            if (!subjectSet.isEmpty()) {
                String subjectCodeIn = StringUtils.join(subjectSet, ",");
                query.setSubjectCodeIn(subjectCodeIn);
                query.setPageNumber(1);
                query.setPageSize(Integer.MAX_VALUE);
                query.setRole(wu.getRole());
                query.setUserId(wu.getId());
                query = studentService.findByQueryPlus(query);
                for (ExamStudent student : query.getResult()) {
                    if (!student.isUpload() || student.isBreach() || student.isAbsent()) {
                        student.setObjectiveScore(0d);
                        student.setSubjectiveScore(0d);
                    }
                    if (student.getSubjectiveScoreList() != null) {
                        student.setSubjectiveScoreList(student.getSubjectiveScoreList()
                                .replace(UN_SELECTIVE_SCORE, "/"));
                    }
                    list.add(new ExamStudentDTO(student));
                }
            }
            response.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode("成绩单.zip"));
            ZipWriter writer = ZipWriter.create(response.getOutputStream());
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            List<String> headerList = getStudentScoreExportHeader(list);
            List<StudentScoreExportDTO> ret=getStudentScoreExportData(list);
            ExportStudentScoreExcel excel = new ExportStudentScoreExcel("成绩单", headerList, StudentScoreExportDTO.class);
            excel.setDataList(ret);
            excel.write(os);
            byte[] value = os.toByteArray();
            writer.write(new ByteArrayInputStream(value), fileName);
            if (!error.isEmpty()) {
                writer.write(StringUtils.join(error, "\r\n").getBytes(), "error.txt");
            }
            writer.close();
            return null;
        } catch (Exception e) {
            addMessage(redirectAttributes, "导出成绩失败！" + e.getMessage());
            return "redirect:/admin/exam/score";
        }
    }
    private List<StudentScoreExportDTO> getStudentScoreExportData(List<ExamStudentDTO> list) {
    	List<StudentScoreExportDTO> ret=new ArrayList<>();
    	Map<String,StudentScoreExportDTO> map=new HashMap<>();
    	if(CollectionUtils.isNotEmpty(list)) {
    		for(ExamStudentDTO dto:list) {
    			StudentScoreExportDTO ssd=map.get(dto.getStudentCode());
    			if(ssd==null) {
    				ssd=new StudentScoreExportDTO();
    				ssd.setStudentCode(dto.getStudentCode());
    				ssd.setName(dto.getName());
    				map.put(dto.getStudentCode(),ssd);
    				ret.add(ssd);
    			}
    			String subjectName=dto.getSubjectName()+"("+dto.getSubjectCode()+")";
    			ssd.getScoreDetail().add(new StudentScoreDetail(subjectName, fomatScore(dto.getTotalScore())));
    		}
    	}
		return ret;
	}
    private String fomatScore(String s) {
    	if(StringUtils.isBlank(s)||"-".equals(s)) {
    		return s;
    	}
    	BigDecimal b = new BigDecimal(s);
        return b.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
    }
    private List<String> getStudentScoreExportHeader(List<ExamStudentDTO> list) {
    	List<String> ret=new ArrayList<>();
    	Set<String> set=new LinkedHashSet<>();
    	if(CollectionUtils.isNotEmpty(list)) {
    		for(ExamStudentDTO dto:list) {
    			String subjectName=dto.getSubjectName()+"("+dto.getSubjectCode()+")";
    			set.add(subjectName);
    		}
    		ret.addAll(set);
    	}
		return ret;
	}

	private List<String> getOptionHeader(int examId, String subjectCode) {
        List<String> headerList = new ArrayList<String>();
        List<ExamQuestion> oQuestions = questionService.findByExamAndSubjectAndObjectiveGroupByNumber(examId,
                subjectCode, true);
        List<ExamQuestion> sQestions = questionService.findByExamAndSubjectAndObjective(examId, subjectCode, false);
        for (ExamQuestion examQuestion : oQuestions) {
            headerList.add(getTitle(examQuestion) + "选项");
            headerList.add(getTitle(examQuestion) + "得分");
        }
        for (ExamQuestion examQuestion : sQestions) {
            headerList.add(getTitle(examQuestion));
        }
        return headerList;
    }

    private String getTitle(ExamQuestion examQuestion) {
        return examQuestion.getMainTitle() + " " + examQuestion.getMainNumber() + "-" + examQuestion.getSubNumber();
    }

    @RequestMapping("/enableExport")
    @ResponseBody
    public JSONObject query(HttpServletRequest request, @RequestParam String subjectCode) {
        JSONObject obj = new JSONObject();
        int examId = getSessionExamId(request);
        Exam exam = examService.findById(examId);
        String exportMessage = subjectService.enableExport(exam, subjectCode);
        if (exportMessage != null) {
            obj.accumulate("enableExport", false);
            obj.accumulate("exportMessage", exportMessage);
        } else {
            obj.accumulate("enableExport", true);
        }
        return obj;
    }

    private List<ScoreItem> buildScoreList(ExamStudent student) {
        List<ScoreItem> scoreList = new LinkedList<ScoreItem>();

        List<ExamQuestion> oList = questionService.findByExamAndSubjectAndObjectiveAndPaperType(student.getExamId(),
                student.getSubjectCode(), true, student.getPaperType());
        List<ScoreItem> list1 = student.getScoreList(true);
        int index = 0;
        for (ExamQuestion question : oList) {
            try {
                ScoreItem item = list1.get(index);
                item.setTitle(question.getMainTitle() + "-" + question.getSubNumber());
                item.setMainNumber(question.getMainNumber());
                item.setSubNumber(question.getSubNumber());
            } catch (Exception e) {
            }
            index++;
        }
        scoreList.addAll(list1);

        List<ExamQuestion> sList = questionService.findByExamAndSubjectAndObjective(student.getExamId(),
                student.getSubjectCode(), false);
        List<ScoreItem> list2 = student.getScoreList(false);
        index = 0;
        for (ExamQuestion question : sList) {
            try {
                ScoreItem item = list2.get(index);
                item.setTitle(question.getMainTitle() + "-" + question.getSubNumber());
                item.setMainNumber(question.getMainNumber());
                item.setSubNumber(question.getSubNumber());
            } catch (Exception e) {
            }
            index++;
        }
        scoreList.addAll(list2);

        return scoreList;
    }

    private void buildSheetUrl(ExamStudent student) {
        // 改为内部原图浏览地址，直接附带标记内容
        // student.setSheetUrls(PictureUrlBuilder
        // .getInnerSheetUrls(student.getExamId(), student.getExamNumber(),
        // student.getSheetCount()));
        student.setSheetUrls(fileService.getSheetUris(student.getExamId(), student.getExamNumber(), 1,
                student.getSheetCount()));
    }

    private void buildPackageUrl(ExamStudent student) {
        if (StringUtils.isNotBlank(student.getPackageCode())) {
            ExamPackage ep = packageService.find(student.getExamId(), student.getPackageCode());
            if (ep != null && ep.getPicCount() > 0) {
                student.setPackageUrls(fileService.getPackageUris(ep.getExamId(), ep.getCode(), 1, ep.getPicCount()));
            }
        }
    }

    private void buildAnswerUrl(ExamStudent student) {
        ExamSubject subject = subjectService.find(student.getExamId(), student.getSubjectCode());
        if (subject != null && subject.getAnswerFileType() != null) {
            student.setAnswerUrl(fileService.getAnswerUri(subject.getExamId(), subject.getCode(),
                    subject.getAnswerFileType()));
        }
        if (subject != null) {
            student.setSubjectRemark(StringUtils.trimToEmpty(subject.getRemark()));
        }
    }

}
