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

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import cn.com.qmth.stmms.biz.common.BaseQueryService;
import cn.com.qmth.stmms.biz.exam.dao.SubjectiveScoreDao;
import cn.com.qmth.stmms.biz.exam.model.SubjectiveScore;
import cn.com.qmth.stmms.biz.exam.query.SubjectiveScoreSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
import cn.com.qmth.stmms.biz.exam.service.SubjectiveScoreService;
import cn.com.qmth.stmms.biz.utils.QuestionNumberComparator;

@Service
public class SubjectiveScoreServiceImpl extends BaseQueryService<SubjectiveScore> implements SubjectiveScoreService {

    @Autowired
    private SubjectiveScoreDao scoreDao;

    @Autowired
    private MarkGroupService groupService;

    @Override
    public List<Integer> findStudentIdByQuery(final SubjectiveScoreSearchQuery query) {
        Page<SubjectiveScore> result = scoreDao.findAll(buildSpecification(query), query);
        fillResult(result, query);
        List<Integer> ids = new ArrayList<Integer>();
        for (SubjectiveScore subjectiveScore : result) {
            ids.add(subjectiveScore.getStudentId());
        }
        return ids;
    }

    private Specification<SubjectiveScore> buildSpecification(final SubjectiveScoreSearchQuery query) {
        return new Specification<SubjectiveScore>() {

            @Override
            public Predicate toPredicate(Root<SubjectiveScore> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<Predicate>();
                if (query.getExamId() > 0) {
                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
                }
                if (StringUtils.isNotBlank(query.getSubjectCode())) {
                    predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
                }
                if (query.getMainNumber() != null) {
                    predicates.add(cb.equal(root.get("pk").get("mainNumber"), query.getMainNumber()));
                }
                // if (query.getGroupNumber() != null) {
                // predicates.add(cb.equal(root.get("groupNumber"),
                // query.getGroupNumber()));
                // } else {
                // List<MarkGroup> groups =
                // groupService.findByExamAndSubjectAndStatus(query.getExamId(),
                // query.getSubjectCode(), MarkStatus.FORMAL);
                // List<Integer> list = new ArrayList<Integer>();
                // for (MarkGroup markGroup : groups) {
                // list.add(markGroup.getNumber());
                // }
                // predicates.add(root.get("groupNumber").in(list));
                // }
                // if (query.getGroupStartScore() != null) {
                // Predicate predicate =
                // cb.greaterThan(root.get("groupScore").as(Double.class),
                // query.getGroupStartScore());
                // predicates.add(predicate);
                // }
                // if (query.getGroupEndScore() != null) {
                // Predicate predicate = cb
                // .lessThan(root.get("groupScore").as(Double.class),
                // query.getGroupEndScore());
                // predicates.add(predicate);
                // }
                if (query.getMainStartScore() != null) {
                    Predicate predicate = cb.greaterThanOrEqualTo(root.get("mainScore").as(Double.class),
                            query.getMainStartScore());
                    predicates.add(predicate);
                }
                if (query.getMainEndScore() != null) {
                    Predicate predicate = cb.lessThanOrEqualTo(root.get("mainScore").as(Double.class),
                            query.getMainEndScore());
                    predicates.add(predicate);
                }
                if (query.getScore() != null) {
                    predicates.add(cb.equal(root.get("score"), query.getScore()));
                }
                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }
        };
    }

    @Override
    public List<SubjectiveScore> findByStudentIdAndGroupNumber(Integer studentId, Integer groupNumber) {
        List<SubjectiveScore> list = scoreDao.findByStudentIdAndGroupNumber(studentId, groupNumber);
        sort(list);
        return list;
    }

    private void sort(List<SubjectiveScore> list) {
        list.sort((o1, o2) -> QuestionNumberComparator.instance.compare(o1, o2));
        // list.sort((o1, o2) -> {
        // int i = o1.getMainNumber() - o2.getMainNumber();
        // if (i == 0) {
        // if (o1.getSubNumber().contains("-")) {
        // String[] o1s = o1.getSubNumber().split("-");
        // String[] o2s = o2.getSubNumber().split("-");
        // int j = Integer.parseUnsignedInt(o1s[0]) -
        // Integer.parseUnsignedInt(o2s[0]);
        // if (j == 0) {
        // return Integer.parseUnsignedInt(o1s[1]) -
        // Integer.parseUnsignedInt(o2s[1]);
        // } else {
        // return j;
        // }
        // } else {
        // return Integer.parseUnsignedInt(o1.getSubNumber()) -
        // Integer.parseUnsignedInt(o2.getSubNumber());
        // }
        // }
        // return i;
        // });
    }

    @Override
    public Set<Integer> findMainNumberByStudentIdAndUncalculate(Integer studentId, Boolean uncalculate) {
        Set<Integer> mainNumbers = new HashSet<Integer>();
        List<SubjectiveScore> list = scoreDao.findByStudentIdAndUncalculate(studentId, uncalculate);
        for (SubjectiveScore subjectiveScore : list) {
            mainNumbers.add(subjectiveScore.getMainNumber());
        }
        return mainNumbers;
    }

    @Override
    public List<SubjectiveScore> findByStudentId(Integer studentId) {
        List<SubjectiveScore> list = scoreDao.findByStudentId(studentId);
        sort(list);
        return list;
    }
}
