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

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.com.qmth.stmms.biz.distributpaper.dao.TryHistoryDao;
import cn.com.qmth.stmms.biz.distributpaper.dao.TryLibraryDao;
import cn.com.qmth.stmms.biz.distributpaper.model.TryHistory;
import cn.com.qmth.stmms.biz.distributpaper.model.TryLibrary;
import cn.com.qmth.stmms.biz.distributpaper.query.TryHistorySearchQuery;
import cn.com.qmth.stmms.biz.distributpaper.service.TryHistoryService;
import cn.com.qmth.stmms.biz.exam.model.Marker;
import cn.com.qmth.stmms.biz.exam.service.MarkerService;

@Service
public class TryHistoryServiceImpl implements TryHistoryService {

    @Autowired
    private TryLibraryDao tryLibraryDao;

    @Autowired
    private TryHistoryDao tryHistoryDao;

    @Autowired
    private MarkerService markerService;

    @Transactional
    public TryHistory save(TryHistory tryHistory) {
        return tryHistoryDao.save(tryHistory);
    }

    public TryHistory findById(Integer id) {
        return tryHistoryDao.findOne(id);
    }

    @Transactional
    public void deleteById(Integer id) {
        tryHistoryDao.delete(id);
    }

    @Transactional
    public void delete(TryHistory tryHistory) {
        tryHistoryDao.delete(tryHistory);
    }

    public List<TryHistory> getHistoryByScorer(Integer examId, Integer subjectId, Integer blockId, Integer scorer) {
        List<TryLibrary> libList = tryLibraryDao.findByExamIdAndBlockId(examId, blockId);
        if (libList.size() > 0) {
            TryLibrary lib = libList.get(0);
            return tryHistoryDao.findByLibraryIdAndScorer(lib.getId(), scorer);
        } else {
            return null;
        }
    }

    @Override
    public List<TryHistory> findByLibraryId(int libraryId) {
        List<TryHistory> list = tryHistoryDao.findByLibraryId(libraryId, new Sort(Direction.DESC, "scoreTime"));
        for (TryHistory history : list) {
            buildTryHistory(history);
        }
        return list;
    }

    @Override
    public TryHistory findLastByLibraryId(int libraryId) {
        TryHistorySearchQuery query = new TryHistorySearchQuery();
        query.setLibraryId(libraryId);
        query.setSort(new Sort(Direction.DESC, "scoreTime"));
        query.setPageNumber(1);
        query.setPageSize(1);
        query = findByQuery(query);
        if (query.getCurrentCount() > 0) {
            return query.getResult().get(0);
        } else {
            return null;
        }
    }

    public TryHistorySearchQuery findByQuery(final TryHistorySearchQuery query) {
        Page<TryHistory> result = tryHistoryDao.findAll(new Specification<TryHistory>() {

            @Override
            public Predicate toPredicate(Root<TryHistory> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<Predicate>();
                EntityType<TryHistory> ci_ = root.getModel();
                if (query.getLibraryId() != null) {
                    predicates.add(cb.equal(root.get("libraryId"), query.getLibraryId()));
                }
                if (query.getStatus() != null) {
                    predicates.add(cb.equal(root.get("status"), query.getStatus()));
                }
                if (query.getPaperNumber() != null) {
                    predicates.add(cb.equal(root.get("paperNumber"), query.getPaperNumber()));
                }
                if (query.getBlockId() != null) {
                    predicates.add(cb.equal(root.get("blockId"), query.getBlockId()));
                }
                if (query.getIsChecked() != null) {
                    predicates.add(cb.equal(root.get("isChecked"), query.getIsChecked()));
                }
                // 发放时间处理
                Predicate issueDate;

                if (query.getStartTime() != null && query.getEndTime() != null) {
                    Expression<Date> start = cb.literal(query.getStartTime());
                    Expression<Date> end = cb.literal(query.getEndTime());
                    issueDate = cb.between(root.get(ci_.getSingularAttribute("scoreTime", Date.class)), start, end);
                    predicates.add(issueDate);
                }

                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }
        }, query);

        query.setResult(result.getContent());
        query.setTotalCount(result.getTotalElements());
        query.setTotalPage(result.getTotalPages());
        List<TryHistory> list = query.getResult();
        for (TryHistory history : list) {
            buildTryHistory(history);
        }
        return query;
    }

    private TryHistory buildTryHistory(TryHistory tryHistory) {
        Marker marker = markerService.findById(tryHistory.getScorer());
        tryHistory.setMarker(marker);
        return tryHistory;
    }

}
