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.apache.commons.lang3.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 org.springframework.transaction.annotation.Transactional;

import cn.com.qmth.stmms.biz.distributpaper.dao.FormallyLibraryDao;
import cn.com.qmth.stmms.biz.distributpaper.dao.ProblemHistoryDao;
import cn.com.qmth.stmms.biz.distributpaper.dao.ProblemLibraryDao;
import cn.com.qmth.stmms.biz.distributpaper.dao.TryLibraryDao;
import cn.com.qmth.stmms.biz.distributpaper.model.FormallyLibrary;
import cn.com.qmth.stmms.biz.distributpaper.model.ProblemHistory;
import cn.com.qmth.stmms.biz.distributpaper.model.ProblemLibrary;
import cn.com.qmth.stmms.biz.distributpaper.model.TryLibrary;
import cn.com.qmth.stmms.biz.distributpaper.service.ProblemLibraryService;
import cn.com.qmth.stmms.biz.exam.model.Marker;
import cn.com.qmth.stmms.biz.exam.model.SubjectiveBlock;
import cn.com.qmth.stmms.biz.exam.service.MarkerService;
import cn.com.qmth.stmms.biz.exam.service.SubjectiveBlockService;
import cn.com.qmth.stmms.biz.subjectheader.query.ProblemLibrarySearchQuery;
import cn.com.qmth.stmms.common.enums.LibraryStatus;

@Service
public class ProblemLibraryServiceImpl implements ProblemLibraryService {

    @Autowired
    private ProblemLibraryDao problemLibraryDao;

    @Autowired
    private ProblemHistoryDao problemHistoryDao;

    @Autowired
    private MarkerService markerService;

    @Autowired
    private SubjectiveBlockService subjectiveBlockService;

    @Autowired
    private TryLibraryDao tryLibraryDao;

    @Autowired
    private FormallyLibraryDao formallyLibraryDao;

    @Transactional
    public ProblemLibrary save(ProblemLibrary problemLibrary) {
        problemLibraryDao.save(problemLibrary);
        return buildProblemLibrary(problemLibrary);
    }

    public ProblemLibrary findById(Integer id) {
        ProblemLibrary problemLibrary = problemLibraryDao.findOne(id);
        return buildProblemLibrary(problemLibrary);
    }

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

    @Transactional
    public void delete(ProblemLibrary problemLibrary) {
        problemLibraryDao.delete(problemLibrary);
    }

    public ProblemLibrarySearchQuery findByQuery(final ProblemLibrarySearchQuery query) {
        Page<ProblemLibrary> result = problemLibraryDao.findAll(new Specification<ProblemLibrary>() {

            @Override
            public Predicate toPredicate(Root<ProblemLibrary> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<Predicate>();
                EntityType<ProblemLibrary> ci_ = root.getModel();

                if (query.getExamId() != null) {
                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
                }

                if (StringUtils.isNotEmpty(query.getSubjectCode())) {
                    predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
                }

                if (query.getSubmitter() != null) {
                    predicates.add(cb.equal(root.get("submitter"), query.getSubmitter()));
                }
                if (query.getReason() != null) {
                    predicates.add(cb.equal(root.get("reason"), query.getReason()));
                }
                if (query.getStatus() != null) {
                    predicates.add(cb.equal(root.get("status").as(LibraryStatus.class),
                            LibraryStatus.findByValue(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()));
                }
                // 发放时间处理
                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("submitTime", Date.class)), start, end);
                    predicates.add(issueDate);
                }

                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }
        }, query);
        for (ProblemLibrary problemLibrary : result) {
            buildProblemLibrary(problemLibrary);
        }
        query.setResult(result.getContent());
        query.setTotalCount(result.getTotalElements());
        query.setTotalPage(result.getTotalPages());
        return query;
    }

    private ProblemLibrary buildProblemLibrary(ProblemLibrary problemLibrary) {
        if (problemLibrary.getSubmitter() != null) {
            int markerId = problemLibrary.getSubmitter();
            Marker marker = markerService.findById(markerId);
            problemLibrary.setMarker(marker);
        }
        if (problemLibrary.getBlockId() != null) {
            SubjectiveBlock block = subjectiveBlockService.findBlockById(problemLibrary.getBlockId());
            if (block != null) {
                problemLibrary.setSubjectiveBlock(block);

                // if (problemLibrary.getType() == LibraryType.TRY) {
                // TryLibrary library =
                // tryLibraryDao.findOne(problemLibrary.getLibraryId());
                // problemLibrary.setPictureConfig(block.getPictureConfig());
                // problemLibrary.setPictureUrls(PictureUrlBuilder.getSliceUrls(library.getExamId(),
                // library.getCampusCode(), block.getSubjectCode(),
                // library.getExamNumber(),
                // library.getPicCount()));
                // } else {
                // FormallyLibrary library =
                // formallyLibraryDao.findOne(problemLibrary.getLibraryId());
                // problemLibrary.setPictureConfig(block.getPictureConfig());
                // problemLibrary.setPictureUrls(PictureUrlBuilder.getSliceUrls(library.getExamId(),
                // library.getCampusCode(), block.getSubjectCode(),
                // library.getExamNumber(),
                // library.getPicCount()));
                // }
            }
        }
        return problemLibrary;
    }

    @Override
    public void saveMark(ProblemHistory problemHistory) {
        ProblemLibrary library = problemLibraryDao.findOne(problemHistory.getLibraryId());
        if (library.getType().getValue() == 1) {
            TryLibrary tryLibrary = tryLibraryDao.findOne(library.getLibraryId());
            tryLibrary.setStatus(LibraryStatus.MARKED);
            tryLibraryDao.save(tryLibrary);
        }

        if (library.getType().getValue() == 2) {
            FormallyLibrary formallyLibrary = formallyLibraryDao.findOne(library.getLibraryId());
            formallyLibrary.setStatus(LibraryStatus.MARKED);
            formallyLibraryDao.save(formallyLibrary);
        }

        library.setStatus(LibraryStatus.MARKED);
        problemLibraryDao.save(library);

        long spent = new Date().getTime() - problemHistory.getSpent();
        problemHistory.setSpent(spent);
        problemHistory.setStatus(LibraryStatus.MARKED);
        problemHistory.setSubmitTime(new Date());
        problemHistoryDao.save(problemHistory);

    }

    @Override
    public int findUntreated(Integer examId, String subjectCode) {
        int count = 0;
        List<FormallyLibrary> formallyList = formallyLibraryDao.findByExamIdAndSubjectCodeAndStatus(examId,
                subjectCode, LibraryStatus.EXCEPTION);
        for (FormallyLibrary formally : formallyList) {
            List<ProblemLibrary> markedList = problemLibraryDao.findByLibraryIdAndStatus(formally.getId(),
                    LibraryStatus.WAITING);
            if (markedList != null) {
                count += markedList.size();
            }
        }
        return count;
    }

    @Override
    public int findUntreatedByBlockId(Integer examId, Integer subjectiveBlockId) {
        int count = 0;
        List<FormallyLibrary> formallyList = formallyLibraryDao.findByExamIdAndBlockIdAndStatus(examId,
                subjectiveBlockId, LibraryStatus.EXCEPTION);
        for (FormallyLibrary formally : formallyList) {
            List<ProblemLibrary> markedList = problemLibraryDao.findByLibraryIdAndStatus(formally.getId(),
                    LibraryStatus.WAITING);
            if (markedList != null) {
                count += markedList.size();
            }
        }
        return count;
    }

}
