package cn.com.qmth.stmms.biz.exam.dao;

import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
import cn.com.qmth.stmms.common.enums.SubjectiveStatus;

import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Set;

public interface ExamStudentDao extends PagingAndSortingRepository<ExamStudent, Integer>,
        JpaSpecificationExecutor<ExamStudent> {

    public List<ExamStudent> findByExamId(int examId, Pageable pageable);

    public List<ExamStudent> findByExamIdAndSubjectCode(int examId, String subjectCode, Pageable pageable);

    public List<ExamStudent> findByExamIdAndUploadAndAbsent(int examId, boolean upload, boolean absent,
            Pageable pageable);

    public List<ExamStudent> findByExamIdAndCampusName(int examId, String campusName, Pageable pageable);

    public List<ExamStudent> findByExamIdAndExamNumber(int examId, String examNumber);

    public List<ExamStudent> findByExamIdAndSecretNumber(int examId, String secretNumber);

    @Query("select s.id from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.subjectiveStatus in (?3)")
    public List<Integer> findIdByExamIdAndSubjectCodeAndSubjectiveStatus(Integer examId, String subjectCode,
            SubjectiveStatus... status);

    @Query("select count(s) from ExamStudent s where s.examId=?1 and s.subjectCode=?2 "
            + "and s.upload=true and s.absent=false and s.breach=false")
    public long countUploaded(Integer examId, String subjectCode);

    @Query("select count(s) from ExamStudent s where s.examId=?1 "
            + "and s.upload=true and s.absent=false and s.breach=false")
    public long countUploaded(Integer examId);

    @Query("select count(s) from ExamStudent s where s.examId=?1 and s.secretNumber=?2")
    public long countByExamIdAndSecretNumber(int examId, String secretNumber);

    @Query("select count(s) from ExamStudent s where s.examId=?1 and s.campusName=?2")
    public long countByExamIdAndCampusName(int examId, String campusName);

    @Query("select count(distinct s.campusName) from ExamStudent s where s.examId=?1")
    public long countCampusNameByExamId(int examId);

    @Query("select s from ExamStudent s where s.examId=?1 group by s.subjectCode")
    public List<ExamStudent> findDistinctSubjectByExamId(int examId, Pageable pageable);

    @Query("select s from ExamStudent s where s.examId=?1 and s.campusName=?2 group by s.subjectCode")
    public List<ExamStudent> findDistinctSubjectByExamIdAndCampusName(int examId, String campusName);

    @Query("select s.campusName from ExamStudent s where s.examId=?1 group by s.campusName")
    public List<String> findDistinctCampusName(int examId);

    @Query("select s from ExamStudent s where s.examId=?1 group by s.campusName")
    public List<ExamStudent> findDistinctCampusName(int examId, Pageable pageable);

    @Query("select s.packageCode from ExamStudent s where s.examId=?1 group by s.packageCode")
    public List<String> findDistinctPackageCode(int examId);

    @Modifying
    @Query("update ExamStudent s set s.subjectiveStatus=?2, s.subjectiveScore=?3, s.subjectiveScoreList=?4 where s.id=?1")
    public void updateSubjectiveStatusAndScore(Integer id, SubjectiveStatus status, double score, String scoreList);

    @Modifying
    @Query("update ExamStudent s set s.subjectiveStatus=?3, s.subjectiveScore=?4, s.subjectiveScoreList=?5 where s.examId=?1 and s.subjectCode=?2")
    public void updateSubjectiveStatusAndScore(Integer examId, String subjetCode, SubjectiveStatus status,
            double score, String scoreList);

    // @Modifying
    // @Query("update ExamStudent s set s.subjectiveStatus=?3, s.subjectiveScore=?4, s.subjectiveScoreList=?5, s.inspectTime=?6, s.inspectorId=?7 "
    // +
    // " where s.examId=?1 and s.subjectCode=?2 and s.subjectiveStatus not in (?8)")
    // public void updateSubjectiveStatusAndScoreWithoutStatus(Integer examId,
    // String subjetCode, SubjectiveStatus status,
    // double score, String scoreList, Date inspectTime, Integer inspectorId,
    // SubjectiveStatus... notInStatus);

    @Modifying
    @Query("update ExamStudent s set s.subjectiveStatus=?3, s.subjectiveScore=?4, s.subjectiveScoreList=?5 "
            + "where s.examId=?1 and s.subjectCode=?2 and exists "
            + "(select g.pk.studentId from MarkGroupStudent g where g.pk.studentId=s.id and g.status in (?6))")
    public void updateSubjectiveStatusFromGroupStatus(Integer examId, String subjetCode, SubjectiveStatus status,
            double score, String scoreList, SubjectiveStatus... groupStatus);

    @Modifying
    @Query("update ExamStudent s set s.objectiveScore=?2, s.objectiveScoreList=?3 where s.id=?1")
    public void updateObjectiveScore(int id, double score, String scoreList);

    @Modifying
    @Query("update ExamStudent s set s.subjectName=?3, s.subjectLevel=?4, s.subjectCategory=?5 where s.examId=?1 and s.subjectCode=?2")
    public void updateSubjectInfo(int examId, String subjectCode, String subjectName, String subjectLevel,
            String subjectCategory);

    @Modifying
    @Query("update ExamStudent s set s.exception=?2 where s.id=?1")
    public void updateException(int id, boolean exception);

    @Modifying
    @Query("update ExamStudent s set s.manualAbsent=?2 where s.id=?1")
    public void updateManualAbsent(int id, boolean manualAbsent);

    @Modifying
    @Query("update ExamStudent s set s.breach=?2 where s.id=?1")
    public int updateBreach(int id, boolean breach);

    @Modifying
    @Query("update ExamStudent s set s.manualAbsent=?3 where s.examId=?1 and s.examNumber=?2")
    public void updateManualAbsent(int examId, String examNumber, boolean manualAbsent);

    @Modifying
    @Query("update ExamStudent s set s.sheetCount=?2, s.sliceCount=?3, s.answers=?4, s.batchCode=?5, s.paperType=?6,"
            + " s.absent=?7, s.upload=true, s.uploadTime=?8, s.objectiveScore=?9, s.objectiveScoreList=?10, "
            + "s.cardNumber=?11 where s.id=?1")
    public int updateScanInfo(Integer id, Integer sheetCount, Integer sliceCount, String answers, String batchCode,
            String paperType, boolean absent, Date uploadTime, Double objectiveScore, String objectiveScoreList,
            Integer cardNumber);

    @Modifying
    @Query("update ExamStudent s set s.sheetCount=0, s.sliceCount=0, s.answers=null, s.batchCode=null, s.paperType=?2,"
            + " s.absent=false, s.upload=false, s.uploadTime=null, s.objectiveScore=0, s.objectiveScoreList=null, "
            + " s.cardNumber=null, s.inspectCount=0 where s.id=?1")
    public int resetScanInfo(Integer id, String paperType);

    @Modifying
    @Query("update ExamStudent s set s.manualAbsent=0 where s.examId=?1")
    public void clearManualAbsent(int examId);

    @Modifying
    @Query("delete from ExamStudent s where s.examId=?1")
    public void deleteByExamId(int examId);

    @Modifying
    @Query("delete from ExamStudent s where s.examId=?1 and s.campusName=?2")
    public void deleteByExamIdAndCampusName(int examId, String campusName);

    public ExamStudent findByExamIdAndSubjectCodeAndStudentCode(Integer id, String subjectCode, String studentCode);

    public ExamStudent findBySchoolIdAndSubjectCodeAndStudentCodeAndRemark(Integer schoolId, String subjectCode,
            String studentCode, String examSeqCode);

    public List<ExamStudent> findByExamIdAndUploadTimeAfter(int examId, Date date);

    public List<ExamStudent> findByExamIdAndSubjectCodeAndUploadTimeAfter(int examId, String code, Date date,
            Pageable page);

    @Query("select count(s) from ExamStudent s where s.examId=?1 and s.subjectiveScoreList is not null ")
    public long countByExamIdAndSubjectiveScoreListNotNull(Integer examId);

    public List<ExamStudent> findByExamIdAndSubjectCodeAndUploadTimeNotNull(int examId, String code);

    public List<ExamStudent> findByExamIdAndSubjectCodeAndUploadTimeNotNullAndAbsent(int examId, String code,
            Boolean absent);

    @Query("select s from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.upload=true and s.absent=false and s.breach=false "
            + " and not exists (select l.id from MarkLibrary l where l.studentId=s.id and l.groupNumber=?3)")
    public List<ExamStudent> findUnLibraryStudent(Integer examId, String subjectCode, Integer groupNumber, Pageable page);

    @Query("select s from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.upload=true and s.absent=false and s.breach=false "
            + "and s.trial=?4 and not exists (select l.id from TrialLibrary l where l.studentId=s.id and l.groupNumber=?3)")
    public List<ExamStudent> findUnTrialStudent(Integer examId, String subjectCode, Integer groupNumber, boolean trial,
            Pageable page);

    @Query("select s from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.upload=true and (s.absent=true or s.breach=true) and "
            + "exists (select l.id from MarkLibrary l where l.studentId=s.id)")
    public List<ExamStudent> findAbsentOrBreachLibraryStudent(Integer examId, String subjectCode);

    @Query(value = "select s.id from eb_exam_student s where 1=1 and s.id in (select m.student_id from m_library m where 1=1 and m.marker_id in (select m.id from eb_marker m where 1=1 and m.login_name = ?1 ))", nativeQuery = true)
    public List<String[]> findIdsByMarkLogin(String markLogin);

    @Query(value = "select s.id from eb_exam_student s where 1=1 and s.id in (select m.student_id from m_library m where 1=1 and m.marker_id in (select m.id from eb_marker m where 1=1 and m.name = ?1))", nativeQuery = true)
    public List<String[]> findIdsByMarkName(String markName);

    public long countByIdAndUploadAndAbsentAndBreach(Integer id, boolean upload, boolean absent, boolean breach);

    @Query("select s.className from ExamStudent s where s.examId=?1 and s.subjectCode=?2 group by s.className")
    public List<String> findDistinctClassName(Integer examId, String subjectCode);

    @Query(value = "select cast(s.objective_score as decimal(10,3))+cast(s.subjective_score as decimal(10,3)) from eb_exam_student s where s.exam_id=?1 and s.subject_code=?2 and s.is_upload =true and s.is_absent=false and s.is_breach=false order by cast(s.objective_score as decimal(10,3))+cast(s.subjective_score as decimal(10,3)) desc limit ?3 ", nativeQuery = true)
    public List<BigDecimal> findHighCountTotalSocreByExamIdAndSubjectCode(Integer examId, String subjectCode,
            int highCount);

    @Query(value = "select cast(s.objective_score as decimal(10,3))+cast(s.subjective_score as decimal(10,3)) from eb_exam_student s where s.exam_id=?1 and s.subject_code=?2 and s.is_upload =true and s.is_absent=false and s.is_breach=false order by cast(s.objective_score as decimal(10,3))+cast(s.subjective_score as decimal(10,3)) asc limit ?3 ", nativeQuery = true)
    public List<BigDecimal> findLowCountTotalSocreByExamIdAndSubjectCode(Integer examId, String subjectCode,
            int lowCount);

    @Query(value = "select cast(s.objective_score as decimal(10,3))+cast(s.subjective_score as decimal(10,3)) from eb_exam_student s where s.exam_id=?1 and s.subject_code=?2 and s.class_name=?3 and s.is_upload =true and s.is_absent=false and s.is_breach=false order by cast(s.objective_score as decimal(10,3))+cast(s.subjective_score as decimal(10,3)) desc limit ?4 ", nativeQuery = true)
    public List<BigDecimal> findHighCountTotalSocreByExamIdAndSubjectCodeAndClass(Integer examId, String subjectCode,
            String className, int highCount);

    @Query(value = "select cast(s.objective_score as decimal(10,3))+cast(s.subjective_score as decimal(10,3)) from eb_exam_student s where s.exam_id=?1 and s.subject_code=?2 and s.class_name=?3 and s.is_upload =true and s.is_absent=false and s.is_breach=false order by cast(s.objective_score as decimal(10,3))+cast(s.subjective_score as decimal(10,3)) asc limit ?4 ", nativeQuery = true)
    public List<BigDecimal> findLowCountTotalSocreByExamIdAndSubjectCodeAndClass(Integer examId, String subjectCode,
            String className, int lowCount);

    @Query("select s.className from ExamStudent s where s.examId=?1 group by s.className")
    public List<String> findDistinctClassName(Integer examId);

    @Modifying
    @Query("update ExamStudent s set s.subjectiveStatus=?2, s.inspectTime=?3 ,s.inspectorId=?4 where s.id=?1 ")
    public void updateSubjectiveStatusAndTimeAndInspectorId(Integer studentId, SubjectiveStatus status,
            Date inspectTime, Integer inspectorId);

    public List<ExamStudent> findByExamIdAndStudentCodeAndSubjectCode(int examId, String studentCode, String subjectCode);

    @Query("select sum(s.sheetCount) from ExamStudent s where s.examId=?1 ")
    public Long sumSheetCountByExamId(Integer examId);

    @Query("select sum(s.sheetCount) from ExamStudent s where s.examId=?1 and s.subjectCode=?2 ")
    public Long sumSheetCountByExamIdAndSubjectCode(int examId, String subjectCode);

    @Query("select distinct m.subjectCode from ExamStudent m where m.examId=?1 and m.subjectiveStatus in (?3) and m.inspected=?2 and m.upload=true and m.absent=false and m.breach=false ")
    Set<String> findSubjectUnInspectedByExamId(int examId, boolean inspected, SubjectiveStatus... status);

    @Query("select s.college from ExamStudent s where s.examId=?1 group by s.college")
    public List<String> findDistinctCollege(int examId);

    @Query("select distinct m.subjectCode from ExamStudent m where m.examId=?1 and m.college=?2 ")
    public List<String> findDistinctSubjectCodeByCollege(int examId, String college);

    @Query("select min(s.inspectCount) from ExamStudent s where s.examId=?1 and s.subjectCode=?2  and s.upload=true and s.absent=false and s.breach=false ")
    public Integer findMinInspectCountByExamIdAndSubjectCode(int examId, String subjectCode);

    @Modifying
    @Query("update ExamStudent s set s.inspectCount=?2,s.inspected=?5, s.inspectTime=?3 ,s.inspectorId=?4 where s.id=?1 ")
    public void updateInspectCount(Integer studentId, Integer inspectCount, Date inspectTime, Integer inspectorId,
            boolean inspected);

    @Modifying
    @Query("update ExamStudent s set s.college=?2 ,s.className=?3, s.teacher=?4,s.examRoom=?5, s.examSite=?6, s.remark=?7 where s.id=?1 ")
    public int updateInfo(Integer id, String college, String className, String teacher, String examRoom,
            String examSite, String remark);

    @Modifying
    @Query("update ExamStudent s set s.scoreVerifyUser=?1,s.scoreVerifyTime=?2,s.scoreVerifyFlagged=?3 where s.id=?4 ")
    public void scoreVerifyTag(Integer userId, Date time, Boolean tag, Integer studentId);

    @Modifying
    @Query("update ExamStudent s set s.inspected=?3,s.inspectTime=null ,s.inspectorId=null where s.examId=?1 and s.subjectCode=?2 and s.inspected=?4")
    public void cancelInspect(int examId, String subjectCode, boolean inspected, boolean inspectedCon);

    @Modifying
    @Query("update ExamStudent s set s.inspected=?4, s.inspectTime=?2 ,s.inspectorId=?3 where s.id=?1 ")
    public void inspect(Integer studentId, Date inspectTime, Integer inspectorId, boolean inspected);

    @Modifying
    @Query("update ExamStudent s set s.inspected=?2, s.inspectTime=null ,s.inspectorId=null where s.id=?1 ")
    public int cancelInspect(Integer studentId, boolean inspected);

    @Modifying
    @Query("update ExamStudent s set s.trial=?2 where s.id=?1")
    public int updateTrialById(Integer studentId, boolean trial);

    @Modifying
    @Query("update ExamStudent s set s.scoreVerifyUser=?1,s.scoreVerifyTime=?2 where s.id=?3 ")
    public void scoreVerifyTag(Integer userId, Date date, Integer studentId);

    @Modifying
    @Query("update ExamStudent s set s.trial=?3 where s.examId=?1 and s.subjectCode=?2 ")
    public void updateTrial(Integer examId, String subjectCode, boolean trial);

    @Query("select s.examSite from ExamStudent s where s.examId=?1 group by s.examSite")
    public List<String> findDistinctExamSite(int examId);

    @Query("select sum(s.sheetCount) from ExamStudent s where s.examId=?1 and s.examSite=?2 ")
    public Long sumSheetCountByExamIdAndExamSite(int examId, String examSite);

}
