package cn.com.qmth.stmms.biz.exam.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.com.qmth.stmms.biz.common.BaseQueryService;
import cn.com.qmth.stmms.biz.exam.bean.ScoreVerifyVo;
import cn.com.qmth.stmms.biz.exam.dao.ScoreVerifyDao;
import cn.com.qmth.stmms.biz.exam.enums.ScoreVerifyRule;
import cn.com.qmth.stmms.biz.exam.enums.ScoreVerifyRuleCompare;
import cn.com.qmth.stmms.biz.exam.model.ScoreVerify;
import cn.com.qmth.stmms.biz.exam.query.ScoreVerifyQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
import cn.com.qmth.stmms.biz.exam.service.ScoreVerifyService;
import cn.com.qmth.stmms.biz.exception.StatusException;
import cn.com.qmth.stmms.biz.file.service.FileService;
import cn.com.qmth.stmms.biz.utils.Calculator;

@Service
public class ScoreVerifyServiceImpl extends BaseQueryService<ScoreVerify> implements ScoreVerifyService {
    public static final String UN_SELECTIVE_SCORE = "-1";
	@PersistenceContext
	private EntityManager entityManager;

	@Autowired
	private ScoreVerifyDao scoreVerifyDao;

	@Autowired
	private ExamStudentService examStudentService;

	@Autowired
	private FileService fileService;

	private void buildSheetUrl(ScoreVerifyVo student) {
		student.setSheetUrls(
				fileService.getSheetUris(student.getExamId(), student.getExamNumber(), 1, student.getSheetCount()));
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<ScoreVerifyVo> findByQuery(ScoreVerifyQuery req) {
		int offset = (req.getPageNumber() - 1) * req.getPageSize();
		StringBuilder sql = new StringBuilder();
		sql.append(
				" select t.sheet_count sheetCount,t.exam_number examNumber,t.exam_id examId,t.id studentId,t.student_code studentCode,t.name studentName,t.subject_code subjectCode,t.subject_name subjectName, ");
		sql.append(
				" t.is_upload upload,t.is_breach breach,t.is_absent absent,t.subjective_score subjectiveScore,t.subjective_score_list subjectiveScoreList,t.objective_score objectiveScore, ");
		sql.append(" u.name scoreVerifyUserName,t.score_verify_time scoreVerifyTime,sub.total_score subjectScore");
		sql.append(" from eb_score_verify r inner join eb_exam_student t on r.student_id=t.id ");
		sql.append(" left join eb_exam_subject sub on t.exam_id=sub.exam_id and t.subject_code=sub.code");
		sql.append(" left join b_user u on t.score_verify_user=u.id where r.exam_id=" + req.getExamId()+" and r.user_id="+req.getUserId());
		sql.append(" order by t.student_code,t.subject_code ");
		sql.append(" limit " + offset + "," + req.getPageSize());
		Query query = entityManager.createNativeQuery(sql.toString());
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(ScoreVerifyVo.class));
		List<ScoreVerifyVo> ret = query.getResultList();
		if (ret != null && !ret.isEmpty()) {
			for (ScoreVerifyVo vo : ret) {
				buildSheetUrl(vo);
				if (vo.getSubjectiveScoreList() != null) {
					vo.setSubjectiveScoreList(vo.getSubjectiveScoreList().replace(UN_SELECTIVE_SCORE, "/"));
	            }
			}
		}
		return ret;
	}

	@Override
	public Integer needVerifyCount(Integer examId, Integer userId) {
		StringBuilder sql = new StringBuilder();
		sql.append("select count(1) ");
		sql.append(
				"from eb_score_verify t inner join eb_exam_student s on t.student_id=s.id  where t.exam_id=" + examId+" and t.user_id="+userId + " and t.viewed =0 ");
		Query query = entityManager.createNativeQuery(sql.toString());
		return Integer.valueOf(query.getResultList().get(0).toString());
	}

	@Override
	public Integer countByQuery(Integer examId, Integer userId) {
		StringBuilder sql = new StringBuilder();
		sql.append("select count(1) ");
		sql.append("from eb_score_verify t inner join eb_exam_student s on t.student_id=s.id where t.exam_id=" + examId+" and t.user_id="+userId);
		Query query = entityManager.createNativeQuery(sql.toString());
		return Integer.valueOf(query.getResultList().get(0).toString());
	}

	@SuppressWarnings("unchecked")
	@Override
	public Boolean existByExamIdAndUserId(Integer examId, Integer userId) {
		StringBuilder sql = new StringBuilder();
		sql.append(" select r.id from eb_score_verify r inner join eb_exam_student s on r.student_id=s.id where r.exam_id=" + examId+" and r.user_id="+userId);
		sql.append(" limit 1");
		Query query = entityManager.createNativeQuery(sql.toString());
		List<ScoreVerify> ret = query.getResultList();
		if(ret!=null&&ret.size()>0) {
			return true;
		}
		return false;
	}

	@Transactional
	@Override
	public void createQuery(ScoreVerifyQuery req) {
		if (StringUtils.isBlank(req.getStudentCode())
				&& StringUtils.isBlank(req.getStudentName()) && req.getRule() == null) {
			throw new StatusException("请选择至少一个条件");
		}
		if (ScoreVerifyRule.RULE2.equals(req.getRule())
				|| ScoreVerifyRule.RULE3.equals(req.getRule())) {
			if (req.getRuleCompare() == null) {
				throw new StatusException("请选择分数匹配条件");
			}
			if (req.getCompareScore() == null) {
				throw new StatusException("请填写匹配分值");
			}
		}
		List<ScoreVerifyVo> allStudents = getAllStudent(req);
		if (allStudents == null || allStudents.size() == 0) {
			throw new StatusException("没有满足条件的数据");
		}
		List<ScoreVerify> details = createByQuery(allStudents, req);
		if (details == null || details.size() == 0) {
			throw new StatusException("没有满足条件的数据");
		}
		scoreVerifyDao.save(details);
	}

	@SuppressWarnings("unchecked")
	private List<ScoreVerifyVo> getAllStudent(ScoreVerifyQuery req) {
		StringBuilder sql = new StringBuilder();
		sql.append(
				"select t.id studentId,t.student_code studentCode,t.subjective_score subjectiveScore,t.objective_score objectiveScore from eb_exam_student t  ");
		sql.append("where exam_id=" + req.getExamId());
		if (StringUtils.isNotBlank(req.getStudentCode())) {
			sql.append(" and t.student_code='" + req.getStudentCode() + "'");
		}
		if (StringUtils.isNotBlank(req.getStudentName())) {
			sql.append(" and t.name='" + req.getStudentName() + "'");
		}
		Query query = entityManager.createNativeQuery(sql.toString());
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(ScoreVerifyVo.class));
		List<ScoreVerifyVo> ret = query.getResultList();
		return ret;
	}

	private List<ScoreVerify> createByQuery(List<ScoreVerifyVo> vos, ScoreVerifyQuery req) {
		List<ScoreVerify> ret = new ArrayList<>();
		if (vos != null & vos.size() > 0) {
			Map<String, List<ScoreVerifyVo>> voMap = new HashMap<>();
			for (ScoreVerifyVo vo : vos) {
				List<ScoreVerifyVo> tem = voMap.get(vo.getStudentCode());
				if (tem == null) {
					tem = new ArrayList<>();
					voMap.put(vo.getStudentCode(), tem);
				}
				tem.add(vo);
			}
			for (List<ScoreVerifyVo> temVos : voMap.values()) {
				if (checkInQuery(temVos, req)) {
					ret.addAll(of(req, temVos));
				}
			}
		}
		return ret;
	}

	private List<ScoreVerify> of(ScoreVerifyQuery req, List<ScoreVerifyVo> vos) {
		List<ScoreVerify> ret = new ArrayList<>();
		for (ScoreVerifyVo vo : vos) {
			ScoreVerify sv = new ScoreVerify();
			sv.setExamId(req.getExamId());
			sv.setUserId(req.getUserId());
			sv.setCreateTime(new Date());
			sv.setStudentId(vo.getStudentId());
			ret.add(sv);
		}
		return ret;
	}

	private boolean checkInQuery(List<ScoreVerifyVo> vos, ScoreVerifyQuery req) {
		ScoreVerifyRule rule = req.getRule();
		if (rule == null) {
			return true;
		}
		if (rule != null && vos.size() == 1) {
			return false;
		}
		// 两个条件,满足各自条件的list
		List<ScoreVerifyVo> group1 = new ArrayList<>();
		List<ScoreVerifyVo> group2 = new ArrayList<>();
		if (ScoreVerifyRule.RULE1.equals(rule)) {
			for (ScoreVerifyVo vo : vos) {
				double totalScore = Calculator.add(vo.getObjectiveScore(), vo.getSubjectiveScore());
				if (totalScore > 0) {
					group1.add(vo);
				}
				if (totalScore == 0) {
					group2.add(vo);
				}
			}
		} else if (ScoreVerifyRule.RULE2.equals(rule)) {
			for (ScoreVerifyVo vo : vos) {
				double totalScore = Calculator.add(vo.getObjectiveScore(), vo.getSubjectiveScore());
				if (totalScore <= 5) {
					group1.add(vo);
				}
				if (ScoreVerifyRuleCompare.EQUALS.equals(req.getRuleCompare())
						&& totalScore == req.getCompareScore()) {
					group2.add(vo);
				} else if (ScoreVerifyRuleCompare.GT.equals(req.getRuleCompare())
						&& totalScore > req.getCompareScore()) {
					group2.add(vo);
				} else if (ScoreVerifyRuleCompare.LT.equals(req.getRuleCompare())
						&& totalScore < req.getCompareScore()) {
					group2.add(vo);
				}
			}
		} else if (ScoreVerifyRule.RULE3.equals(rule)) {
			for (ScoreVerifyVo vo : vos) {
				double totalScore = Calculator.add(vo.getObjectiveScore(), vo.getSubjectiveScore());
				if (totalScore <= 10) {
					group1.add(vo);
				}
				if (ScoreVerifyRuleCompare.EQUALS.equals(req.getRuleCompare())
						&& totalScore == req.getCompareScore()) {
					group2.add(vo);
				} else if (ScoreVerifyRuleCompare.GT.equals(req.getRuleCompare())
						&& totalScore > req.getCompareScore()) {
					group2.add(vo);
				} else if (ScoreVerifyRuleCompare.LT.equals(req.getRuleCompare())
						&& totalScore < req.getCompareScore()) {
					group2.add(vo);
				}
			}
		}

		if (group1.size() > 0 && group2.size() > 0) {
			if (group1.size() >= 2 || group2.size() >= 2) {
				// 两个list都有值，且至少有一个数量大于2的一定满足
				return true;
			}
			if (group1.size() == 1 && group2.size() == 1
					&& !group1.get(0).getStudentId().equals(group2.get(0).getStudentId())) {
				// 都只有一条的时候，id不同则通过
				return true;
			}
		}
		return false;
	}

	@Transactional
	@Override
	public void reset(Integer examId, Integer userId) {
		scoreVerifyDao.deleteByExamIdAndUserId(examId, userId);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<ScoreVerifyVo> findFlagged(Integer examId, Integer userId) {
		StringBuilder sql = new StringBuilder();
		sql.append(
				" select t.sheet_count sheetCount,t.exam_number examNumber,t.exam_id examId,t.id studentId,t.student_code studentCode,t.name studentName,t.subject_code subjectCode,t.subject_name subjectName, ");
		sql.append(
				" t.is_upload upload,t.is_absent absent,t.subjective_score subjectiveScore,t.subjective_score_list subjectiveScoreList,t.objective_score objectiveScore, ");
		sql.append(" u.name scoreVerifyUserName,t.score_verify_time scoreVerifyTime ");
		sql.append(" from eb_score_verify r inner join eb_exam_student t on r.student_id=t.id ");
		sql.append(" left join b_user u on t.score_verify_user=u.id where  r.exam_id=" + examId+" and r.user_id="+userId
				+ " and t.score_verify_flagged =1 ");
		sql.append(" order by t.student_code,t.subject_code ");
		Query query = entityManager.createNativeQuery(sql.toString());
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(ScoreVerifyVo.class));
		List<ScoreVerifyVo> ret = query.getResultList();
		if (ret != null && !ret.isEmpty()) {
			for (ScoreVerifyVo vo : ret) {
				buildSheetUrl(vo);
			}
		}
		return ret;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<ScoreVerifyVo> needVerify(Integer examId, Integer userId) {
		StringBuilder sql = new StringBuilder();
		sql.append(
				" select t.sheet_count sheetCount,t.exam_number examNumber,t.exam_id examId,t.id studentId,t.student_code studentCode,t.name studentName,t.subject_code subjectCode,t.subject_name subjectName, ");
		sql.append(
				" t.is_upload upload,t.is_absent absent,t.subjective_score subjectiveScore,t.subjective_score_list subjectiveScoreList,t.objective_score objectiveScore, ");
		sql.append(" u.name scoreVerifyUserName,t.score_verify_time scoreVerifyTime ");
		sql.append(" from eb_score_verify r inner join eb_exam_student t on r.student_id=t.id ");
		sql.append(" left join b_user u on t.score_verify_user=u.id where  r.exam_id=" + examId+" and r.user_id="+userId
				+ " and r.viewed =0 ");
		sql.append(" order by t.student_code,t.subject_code ");
		Query query = entityManager.createNativeQuery(sql.toString());
		query.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(ScoreVerifyVo.class));
		List<ScoreVerifyVo> ret = query.getResultList();
		if (ret != null && !ret.isEmpty()) {
			for (ScoreVerifyVo vo : ret) {
				buildSheetUrl(vo);
			}
		}
		return ret;
	}

	@Transactional
	@Override
	public void tag(Integer examId, Integer userId, Integer studentId, boolean isTag) {
		ScoreVerify sd = scoreVerifyDao.findByExamIdAndUserIdAndStudentId(examId, userId, studentId);
		sd.setFlagged(isTag);
		sd.setVerifyTime(new Date());
		scoreVerifyDao.save(sd);
		examStudentService.scoreVerifyTag(userId, studentId, isTag);
	}
	
	@Transactional
	@Override
	public void view(Integer examId, Integer userId, Integer studentId) {
		ScoreVerify sd = scoreVerifyDao.findByExamIdAndUserIdAndStudentId(examId, userId, studentId);
		sd.setViewed(true);
		scoreVerifyDao.save(sd);
		examStudentService.scoreVerifyView(userId, studentId);
	}

	@Override
	public ScoreVerify findByExamIdAndUserIdAndStudentId(Integer examId, Integer userId, Integer studentId) {
		return scoreVerifyDao.findByExamIdAndUserIdAndStudentId(examId, userId, studentId);
	}
}
