package com.qmth.themis.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.qmth.themis.business.cache.ExamRecordCacheUtil;
import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dto.WarningDto;
import com.qmth.themis.business.entity.TEConfig;
import com.qmth.themis.business.entity.TEExamStudentLog;
import com.qmth.themis.business.entity.TIeInvigilateWarnInfo;
import com.qmth.themis.business.entity.TOeExamRecord;
import com.qmth.themis.business.enums.ExamTypeEnum;
import com.qmth.themis.business.enums.VerifyExceptionEnum;
import com.qmth.themis.business.enums.WarningLevelEnum;
import com.qmth.themis.business.service.*;
import com.qmth.themis.common.enums.ExceptionResultEnum;
import com.qmth.themis.common.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * @Description: 预警规则公用
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020/8/18
 */
@Service
public class WarningServiceImpl implements WarningService {
    private final static Logger log = LoggerFactory.getLogger(WarningServiceImpl.class);

    @Resource
    TEConfigService teConfigService;

    @Resource
    TOeFaceVerifyHistoryService faceVerifyHistoryService;

    @Resource
    TIeInvigilateWarnInfoService tIeInvigilateWarnInfoService;

    @Resource
    TEExamStudentLogService teExamStudentLogService;

    @Resource
    TEExamStudentService teExamStudentService;

    @Resource
    TOeExamRecordService tOeExamRecordService;

    @Resource
    TOeLivenessVerifyHistoryService tOeLivenessVerifyHistoryService;

    /**
     * 人脸数量异常
     *
     * @param warningDto
     */
    @Override
    @Transactional
    public void faceCountError(WarningDto warningDto) {
        Long recordId = warningDto.getRecordId();
        Integer faceCount = warningDto.getFaceCount();
        VerifyExceptionEnum warningEnum = warningDto.getWarningEnum();
        String photoUrl = warningDto.getPhotoUrl();
        TEConfig teConfig = teConfigService.getGlobalConfig();
        Long examId = ExamRecordCacheUtil.getExamId(recordId);
        Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
        Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
        if (Objects.isNull(examStudentId)) {
            TOeExamRecord tOeExamRecord = tOeExamRecordService.getById(recordId);
            Optional.ofNullable(tOeExamRecord).orElseThrow(() -> new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD));
            examStudentId = tOeExamRecord.getExamStudentId();
            examActivityId = tOeExamRecord.getExamActivityId();
        }
        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
        if (faceCount > 1) {//多张人脸
            Map<String, Object> map = faceVerifyHistoryService.faceCountError(recordId, warningDto.getWarningEnum().name(), faceCount, true, ExamTypeEnum.IN_PROCESS.name(), warningDto.getRandom());
            if (Objects.nonNull(map) && map.size() > 0) {
                Integer count = Integer.parseInt(String.valueOf(map.get("tmpCount")));
                count = Objects.isNull(count) ? 0 : count;
                if (count > teConfig.getMultipleFaceCountError()) {
                    TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(1), WarningLevelEnum.valueOf(warningEnum.getLevel().get(1)).getTitle(), warningEnum, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
                    tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                    this.setWarningCount(recordId, tIeInvigilateWarnInfo);
                    this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, teConfig.getMultipleFaceCountError(), warningDto);
                }
            }
        } else if (faceCount <= 0) {//未检测到人脸
            Map<String, Object> map = faceVerifyHistoryService.faceCountError(recordId, warningDto.getWarningEnum().name(), faceCount, false, ExamTypeEnum.IN_PROCESS.name(), warningDto.getRandom());
            if (Objects.nonNull(map) && map.size() > 0) {
                Integer count = Integer.parseInt(String.valueOf(map.get("tmpCount")));
                count = Objects.isNull(count) ? 0 : count;
                if (count > teConfig.getNoFaceCountError()) {
                    TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(0), WarningLevelEnum.valueOf(warningEnum.getLevel().get(0)).getTitle(), warningEnum, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
                    tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                    this.setWarningCount(recordId, tIeInvigilateWarnInfo);
                    this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, teConfig.getNoFaceCountError(), warningDto);
                }
            }
        }
    }

    /**
     * 人脸比对异常
     *
     * @param warningDto
     */
    @Override
    @Transactional
    public void faceCompareError(WarningDto warningDto) {
        Long recordId = warningDto.getRecordId();
        VerifyExceptionEnum warningEnum = warningDto.getWarningEnum();
        String photoUrl = warningDto.getPhotoUrl();
        TEConfig teConfig = teConfigService.getGlobalConfig();
        Long examId = ExamRecordCacheUtil.getExamId(recordId);
        Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
        Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
        if (Objects.isNull(examStudentId)) {
            TOeExamRecord tOeExamRecord = tOeExamRecordService.getById(recordId);
            Optional.ofNullable(tOeExamRecord).orElseThrow(() -> new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD));
            examStudentId = tOeExamRecord.getExamStudentId();
            examActivityId = tOeExamRecord.getExamActivityId();
        }
        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
        Map<String, Object> map = faceVerifyHistoryService.faceCompareError(recordId, warningDto.getWarningEnum().name(), ExamTypeEnum.IN_PROCESS.name(), warningDto.getRandom());
        if (Objects.nonNull(map) && map.size() > 0) {
            Integer count = Integer.parseInt(String.valueOf(map.get("tmpCount")));
            count = Objects.isNull(count) ? 0 : count;
            if (count > teConfig.getTotalFaceCompareErrorCount()) {
                TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(0), WarningLevelEnum.valueOf(warningEnum.getLevel().get(0)).getTitle(), warningEnum, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
                tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                this.setWarningCount(recordId, tIeInvigilateWarnInfo);
                this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, teConfig.getTotalFaceCompareErrorCount(), warningDto);
            }
        }
    }

    /**
     * 闭眼检测异常
     *
     * @param warningDto
     */
    @Override
    @Transactional
    public void eyeCloseError(WarningDto warningDto) {
        Long recordId = warningDto.getRecordId();
        VerifyExceptionEnum warningEnum = warningDto.getWarningEnum();
        String photoUrl = warningDto.getPhotoUrl();
        TEConfig teConfig = teConfigService.getGlobalConfig();
        Long examId = ExamRecordCacheUtil.getExamId(recordId);
        Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
        Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
        if (Objects.isNull(examStudentId)) {
            TOeExamRecord tOeExamRecord = tOeExamRecordService.getById(recordId);
            Optional.ofNullable(tOeExamRecord).orElseThrow(() -> new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD));
            examStudentId = tOeExamRecord.getExamStudentId();
            examActivityId = tOeExamRecord.getExamActivityId();
        }
        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
        Map<String, Object> map = faceVerifyHistoryService.eyeCloseError(recordId, warningDto.getWarningEnum().name(), ExamTypeEnum.IN_PROCESS.name(), warningDto.getRandom());
        if (Objects.nonNull(map) && map.size() > 0) {
            Integer count = Integer.parseInt(String.valueOf(map.get("tmpCount")));
            count = Objects.isNull(count) ? 0 : count;
            if (count > teConfig.getTotalEyeCloseErrorCount()) {
                TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(0), WarningLevelEnum.valueOf(warningEnum.getLevel().get(0)).getTitle(), warningEnum, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
                tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                this.setWarningCount(recordId, tIeInvigilateWarnInfo);
                this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, teConfig.getTotalEyeCloseErrorCount(), warningDto);
            }
        }
    }

    /**
     * 真实性异常
     *
     * @param warningDto
     */
    @Override
    @Transactional
    public void realnessError(WarningDto warningDto) {
        Long recordId = warningDto.getRecordId();
        VerifyExceptionEnum warningEnum = warningDto.getWarningEnum();
        String photoUrl = warningDto.getPhotoUrl();
        TEConfig teConfig = teConfigService.getGlobalConfig();
        Long examId = ExamRecordCacheUtil.getExamId(recordId);
        Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
        Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
        if (Objects.isNull(examStudentId)) {
            TOeExamRecord tOeExamRecord = tOeExamRecordService.getById(recordId);
            Optional.ofNullable(tOeExamRecord).orElseThrow(() -> new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD));
            examStudentId = tOeExamRecord.getExamStudentId();
            examActivityId = tOeExamRecord.getExamActivityId();
        }
        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
        Map<String, Object> map = faceVerifyHistoryService.realnessError(recordId, warningDto.getWarningEnum().name(), ExamTypeEnum.IN_PROCESS.name(), warningDto.getRandom());
        if (Objects.nonNull(map) && map.size() > 0) {
            Integer count = Integer.parseInt(String.valueOf(map.get("tmpCount")));
            count = Objects.isNull(count) ? 0 : count;
            if (count > teConfig.getRealnessCount()) {
                TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, WarningLevelEnum.D15.name(), WarningLevelEnum.D15.getTitle(), warningEnum, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
                tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                this.setWarningCount(recordId, tIeInvigilateWarnInfo);
                this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, teConfig.getRealnessCount(), warningDto);
            }
        }
    }

    /**
     * 活检动作错误异常
     *
     * @param warningDto
     */
    @Override
    @Transactional
    public void livenessActionError(WarningDto warningDto) {
        Long recordId = warningDto.getRecordId();
        String photoUrl = warningDto.getPhotoUrl();
        Long examId = ExamRecordCacheUtil.getExamId(recordId);
        Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
        Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
        if (Objects.isNull(examStudentId)) {
            TOeExamRecord tOeExamRecord = tOeExamRecordService.getById(recordId);
            Optional.ofNullable(tOeExamRecord).orElseThrow(() -> new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD));
            examStudentId = tOeExamRecord.getExamStudentId();
            examActivityId = tOeExamRecord.getExamActivityId();
        }
        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
        Map<String, Object> map = tOeLivenessVerifyHistoryService.livenessActionError(recordId, warningDto.getWarningEnum().name(), ExamTypeEnum.IN_PROCESS.name(), warningDto.getRandom());
        if (Objects.nonNull(map) && map.size() > 0) {
            TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, VerifyExceptionEnum.LIVENESS_ACTION_ERROR.getLevel().get(0), VerifyExceptionEnum.LIVENESS_ACTION_ERROR.getTitle(), VerifyExceptionEnum.LIVENESS_ACTION_ERROR, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
            tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
            this.setWarningCount(recordId, tIeInvigilateWarnInfo);
            this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, 0, warningDto);
        }
    }

    /**
     * 设置预警数
     *
     * @param recordId
     * @param tIeInvigilateWarnInfo
     */
    public void setWarningCount(Long recordId, TIeInvigilateWarnInfo tIeInvigilateWarnInfo) {
        tOeExamRecordService.updateWarningCountCache(recordId, tIeInvigilateWarnInfo);
    }

    /**
     * 设置图片集合
     *
     * @param map
     * @param tIeInvigilateWarnInfo
     * @param examStudentCacheBean
     * @param recordId
     * @param count
     * @param warningDto
     */
    public void setPhotoUrls(Map<String, Object> map, TIeInvigilateWarnInfo tIeInvigilateWarnInfo, ExamStudentCacheBean examStudentCacheBean, Long recordId, Integer count, WarningDto warningDto) {
        List<String> photoUrls = new ArrayList();
        if (Objects.nonNull(map.get("photoUrls")) && !Objects.equals(map.get("photoUrls"), "")) {
            String[] s = String.valueOf(map.get("photoUrls")).split(",");
            Collections.addAll(photoUrls, s);
            if (photoUrls.size() > count) {
                count = count == 0 ? photoUrls.size() : count;
                photoUrls = photoUrls.subList(0, count);
            }
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("PHOTOS", photoUrls);
        jsonObject.put("MIN_CREATE_TIME", map.get(SystemConstant.CREATE_TIME));
        TEExamStudentLog teExamStudentLog = new TEExamStudentLog(tIeInvigilateWarnInfo.getType().name(), WarningLevelEnum.valueOf(tIeInvigilateWarnInfo.getLevel()).getTitle(), jsonObject.toJSONString(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId, WarningLevelEnum.valueOf(tIeInvigilateWarnInfo.getLevel()).getSecondTitle(),
                warningDto.getIp(), warningDto.getCountry(), warningDto.getRegion(), warningDto.getProvince(), warningDto.getCity(), warningDto.getIsp());
        teExamStudentLogService.saveOrUpdate(teExamStudentLog);
    }
}
