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

import java.util.ArrayList;
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.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.com.qmth.stmms.biz.distributpaper.model.FormallyHistory;
import cn.com.qmth.stmms.biz.distributpaper.model.FormallyLibrary;
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.service.FormallyHistoryService;
import cn.com.qmth.stmms.biz.distributpaper.service.FormallyLibraryService;
import cn.com.qmth.stmms.biz.distributpaper.service.TryHistoryService;
import cn.com.qmth.stmms.biz.distributpaper.service.TryLibraryService;
import cn.com.qmth.stmms.biz.exam.model.SubjectiveBlock;
import cn.com.qmth.stmms.biz.exam.service.SubjectiveBlockService;
import cn.com.qmth.stmms.biz.subjectheader.dao.ArbitrationLibraryDao;
import cn.com.qmth.stmms.biz.subjectheader.model.ArbitrationLibrary;
import cn.com.qmth.stmms.biz.subjectheader.query.ArbitrationLibrarySearchQuery;
import cn.com.qmth.stmms.biz.subjectheader.service.ArbitrationLibraryService;
import cn.com.qmth.stmms.common.enums.ClassType;
import cn.com.qmth.stmms.common.enums.LibraryStatus;
import cn.com.qmth.stmms.common.enums.LibraryType;

@Service
public class ArbitrationLibraryServiceImpl implements ArbitrationLibraryService {

    @Autowired
    private ArbitrationLibraryDao arbitrationLibraryDao;

    @Autowired
    private SubjectiveBlockService subjectiveBlockService;

    @Autowired
    private FormallyLibraryService formallyLibraryService;

    @Autowired
    private FormallyHistoryService formallyHistoryService;

    @Autowired
    private TryLibraryService tryLibraryService;

    @Autowired
    private TryHistoryService tryHistoryService;

    @Transactional
    public ArbitrationLibrary save(ArbitrationLibrary arbitrationLibrary) {
        arbitrationLibraryDao.save(arbitrationLibrary);
        return buildArbitrationLibrary(arbitrationLibrary);
    }

    public ArbitrationLibrary findById(Integer id) {
        ArbitrationLibrary arbitrationLibrary = arbitrationLibraryDao.findOne(id);
        return buildArbitrationLibrary(arbitrationLibrary);
    }

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

    @Transactional
    public void delete(ArbitrationLibrary arbitrationLibrary) {
        arbitrationLibraryDao.delete(arbitrationLibrary);
    }

    public ArbitrationLibrarySearchQuery findByQuery(final ArbitrationLibrarySearchQuery query) {
        Page<ArbitrationLibrary> result = arbitrationLibraryDao.findAll(new Specification<ArbitrationLibrary>() {

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

                if (query.getExamId() != null) {
                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
                }
                if (query.getSubjectId() != null) {
                    predicates.add(cb.equal(root.get("subjectId"), query.getSubjectId()));
                }
                if (query.getClassType() != null) {
                    predicates.add(cb.equal(root.get("classType").as(ClassType.class), query.getClassType()));
                }
                if (query.getType() != null) {
                    predicates.add(cb.equal(root.get("type").as(LibraryType.class), query.getType()));
                }
                if (query.getSecretNo() != null) {
                    predicates.add(cb.equal(root.get("secretNo"), query.getSecretNo()));
                }
                if (query.getStatus() != null) {
                    predicates.add(cb.equal(root.get("status").as(LibraryStatus.class), query.getStatus()));
                }
                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("occurTime", Date.class)), start, end);
                    predicates.add(issueDate);
                }

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

    private ArbitrationLibrary buildArbitrationLibrary(ArbitrationLibrary arbitrationLibrary) {
        if (arbitrationLibrary.getType().getValue() == 1) {
            SubjectiveBlock subjectiveBlock = subjectiveBlockService.findBlockById(arbitrationLibrary.getBlockId(),
                    true);
            arbitrationLibrary.setSubjectiveBlock(subjectiveBlock);

            List<TryLibrary> libList = tryLibraryService.findByExamIdAndSubjectCodeAndBlockIdAndSecretNoAndStatus(
                    arbitrationLibrary.getExamId(), arbitrationLibrary.getSubjectCode(),
                    arbitrationLibrary.getBlockId(), arbitrationLibrary.getSecretNo(), LibraryStatus.MARKED);
            List<TryHistory> list = new ArrayList<TryHistory>();
            for (TryLibrary library : libList) {
                List<TryHistory> historyList = tryHistoryService.findByLibraryId(library.getId());
                list.addAll(historyList);
            }

            arbitrationLibrary.setTryHistoryList(list);
            if (libList.size() > 0) {
                TryLibrary library = libList.get(0);
                arbitrationLibrary.setPictureConfig(subjectiveBlock.getPictureConfig());
                // arbitrationLibrary.setPictureUrls(PictureUrlBuilder.getSliceUrls(library.getExamId(),
                // library.getCampusCode(), subjectiveBlock.getSubjectCode(),
                // library.getExamNumber(),
                // library.getPicCount()));
            }

        } else {
            SubjectiveBlock subjectiveBlock = subjectiveBlockService.findBlockById(arbitrationLibrary.getBlockId(),
                    true);
            arbitrationLibrary.setSubjectiveBlock(subjectiveBlock);

            List<FormallyLibrary> libList = formallyLibraryService
                    .findByExamIdAndSubjectCodeAndBlockIdAndSecretNoAndStatus(arbitrationLibrary.getExamId(),
                            arbitrationLibrary.getSubjectCode(), arbitrationLibrary.getBlockId(),
                            arbitrationLibrary.getSecretNo(), LibraryStatus.MARKED);
            List<FormallyHistory> list = new ArrayList<FormallyHistory>();
            for (FormallyLibrary library : libList) {
                List<FormallyHistory> historyList = formallyHistoryService.findByLibraryId(library.getId());
                list.addAll(historyList);
            }

            arbitrationLibrary.setFormallyHistoryList(list);
            if (libList.size() > 0) {
                FormallyLibrary library = libList.get(0);
                arbitrationLibrary.setPictureConfig(subjectiveBlock.getPictureConfig());
                // arbitrationLibrary.setPictureUrls(PictureUrlBuilder.getSliceUrls(library.getExamId(),
                // library.getCampusCode(), subjectiveBlock.getSubjectCode(),
                // library.getExamNumber(),
                // library.getPicCount()));
            }
        }

        return arbitrationLibrary;

    }

    @Override
    public int findUntreated(Integer examId, String subjectCode) {
        List<ArbitrationLibrary> markedList = arbitrationLibraryDao.findByExamIdAndSubjectCodeAndTypeAndStatus(examId,
                subjectCode, LibraryType.FORMALLY, LibraryStatus.WAITING);
        int count = 0;
        if (markedList != null) {
            count += markedList.size();
        }

        return count;
    }

    @Override
    public int findUntreatedByBlockId(Integer examId, Integer subjectiveBlockId) {
        List<ArbitrationLibrary> markedList = arbitrationLibraryDao.findByExamIdAndBlockIdAndTypeAndStatus(examId,
                subjectiveBlockId, LibraryType.FORMALLY, LibraryStatus.WAITING);
        int count = 0;
        if (markedList != null) {
            count += markedList.size();
        }

        return count;
    }

}
