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

import com.qmth.themis.business.bean.exam.MobileAnswerSubmitReponseBean;
import com.qmth.themis.business.bean.mobile.MobileAuthorizationBean;
import com.qmth.themis.business.bean.mobile.MobileAuthorizationMonitorBean;
import com.qmth.themis.business.bean.mobile.MobileAuthorizationParamBean;
import com.qmth.themis.business.bean.mobile.MobileAuthorizationUploadBean;
import com.qmth.themis.business.cache.ExamRecordCacheUtil;
import com.qmth.themis.business.cache.MobileAuthCacheUtil;
import com.qmth.themis.business.cache.RedisKeyHelper;
import com.qmth.themis.business.cache.bean.ExamStudentAnswerCacheBean;
import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dto.AuthDto;
import com.qmth.themis.business.dto.MqDto;
import com.qmth.themis.business.entity.TBSession;
import com.qmth.themis.business.enums.*;
import com.qmth.themis.business.service.MqDtoService;
import com.qmth.themis.business.service.TEExamStudentService;
import com.qmth.themis.business.service.TEMobileService;
import com.qmth.themis.business.util.RedisUtil;
import com.qmth.themis.business.util.ServletUtil;
import com.qmth.themis.business.util.SessionUtil;
import com.qmth.themis.business.util.TencentYunUtil;
import com.qmth.themis.common.enums.Platform;
import com.qmth.themis.common.enums.Source;
import com.qmth.themis.common.exception.BusinessException;
import com.qmth.themis.common.signature.SignatureInfo;
import com.qmth.themis.common.signature.SignatureType;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

@Service
public class TEMobileServiceImpl implements TEMobileService {

    @Resource
    RedisUtil redisUtil;

    @Resource
    TEExamStudentService examStudentService;

    @Resource
    TencentYunUtil tencentYunUtil;

    @Resource
    MqDtoService mqDtoService;

    @Override
    public MobileAuthorizationBean authorization(MobileAuthorizationParamBean param) throws NoSuchAlgorithmException {
        MobileModeEnum mode = MobileModeEnum.valueOf(param.getMode().toUpperCase());
        String code = param.getCode();
        MobileAuthorizationBean ret = null;
        if (MobileModeEnum.MOBILE_MONITOR.equals(mode)) {
            ret = monitorAuthorization(mode, code);
        } else if (MobileModeEnum.PHOTO_UPLOAD.equals(mode) || MobileModeEnum.AUDIO_UPLOAD.equals(mode)) {
            ret = answerUploadAuthorization(mode, code);
        }
        if (ExamRecordCacheUtil.getId(ret.getRecordId()) == null) {
            throw new BusinessException("考试记录不存在");
        }
        ExamStudentCacheBean es = examStudentService
                .getExamStudentCacheBean(ExamRecordCacheUtil.getExamStudentId(ret.getRecordId()));
        if (es == null) {
            throw new BusinessException("未找到考生");
        }
        ExamRecordStatusEnum sta = ExamRecordCacheUtil.getStatus(ret.getRecordId());
        if (ExamRecordStatusEnum.FINISHED.equals(sta) || ExamRecordStatusEnum.PERSISTED.equals(sta)) {
            throw new BusinessException("该考试已结束");
        }
        Platform platform = Platform.valueOf(ServletUtil.getRequestPlatform());
        String deviceId = ServletUtil.getRequestDeviceId();
        AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.studentOauth + "::" + es.getStudentId());
        // 生成token
        String token = RandomStringUtils.randomAlphanumeric(32);
        String source = MobileAuthCacheUtil.getPlatformSource(mode, code);
        String sessionId = MobileAuthCacheUtil.getSessionId(mode, code);
        Map<String, Object> expireMap = SystemConstant.getExpireTime(platform);
        Date expire = (Date) expireMap.get("date");
        Long redisExpire = Long.parseLong(String.valueOf(expireMap.get("redisExpire")));
        TBSession tbSession = new TBSession(sessionId, String.valueOf(es.getStudentId()),
                authDto.getRoleCodes().toString(), source, platform.name(), deviceId,
                ServletUtil.getRequest().getLocalAddr(), token, expire.getTime());
        redisUtil.setUserSession(sessionId, tbSession, redisExpire);
        ret.setSessionId(sessionId);
        ret.setTime(System.currentTimeMillis());
        ret.setMode(mode);
        //mq发送消息start
        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), platform.name(), tbSession, MqTagEnum.valueOf(platform.name()), tbSession.getId(), es.getIdentity());
        mqDtoService.assembleSendOneWayMsg(mqDto);
        MqDto mqDtoLog = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.STUDENT.name(), SystemOperationEnum.LOGIN, MqTagEnum.STUDENT, String.valueOf(es.getStudentId()), es.getIdentity());
        mqDtoService.assembleSendOneWayMsg(mqDtoLog);
        //mq发送消息end
        //测试
        String test = SignatureInfo.build(SignatureType.TOKEN, sessionId, token);
        ret.setAccessToken(test);
        return ret;
    }

    private MobileAuthorizationBean monitorAuthorization(MobileModeEnum mode, String code) throws NoSuchAlgorithmException {
        Long recordId = MobileAuthCacheUtil.getRecordId(mode, code);
        String monitorKey = MobileAuthCacheUtil.getMonitorKey(mode, code);
        Source monitorVideoSource = MobileAuthCacheUtil.getMonitorVideoSource(mode, code);
        Boolean monitorAudioEnable = MobileAuthCacheUtil.getMonitorAudioEnable(mode, code);
        if (MobileAuthCacheUtil.getMode(mode, code) == null) {
            throw new BusinessException("二维码已过期");
        }
        MobileAuthorizationMonitorBean ret = new MobileAuthorizationMonitorBean();
        ret.setRecordId(recordId);
        ret.setMonitorKey(monitorKey);
        ret.setMonitorVideoSource(monitorVideoSource);
        ret.setMonitorAudioEnable(monitorAudioEnable);
        ExamStudentCacheBean es = examStudentService
                .getExamStudentCacheBean(ExamRecordCacheUtil.getExamStudentId(ret.getRecordId()));
        String source = null;
        if (mode.equals(MobileModeEnum.MOBILE_MONITOR)) {
            Source sourceEnum = MobileAuthCacheUtil.getSource(mode, code);
            source = sourceEnum.name();
        } else if (mode.equals(MobileModeEnum.PHOTO_UPLOAD) || mode.equals(MobileModeEnum.AUDIO_UPLOAD)) {
            source = Source.OE_ANSWER.name();
        }
        String userType = MobileAuthCacheUtil.getUserType(mode, code);
        AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.studentOauth + "::" + es.getStudentId());
        String sessionId = SessionUtil.digest(es.getIdentity(), Math.abs(authDto.getRoleCodes().toString().hashCode()), source);
        MobileAuthCacheUtil.setSessionId(mode, code, sessionId);
        MobileAuthCacheUtil.setPlatformSource(mode, code, source);
        if (Objects.nonNull(userType) && userType.contains(RoleEnum.STUDENT.name())) {
            ret.setMonitorUserId("s_" + sessionId);
        } else {
            ret.setMonitorUserId("m_" + sessionId);
        }
        ret.setMonitorUserSig(tencentYunUtil.getSign(ret.getMonitorUserId(), SystemConstant.TENCENT_EXPIRE_TIME));
        return ret;
    }

    private MobileAuthorizationBean answerUploadAuthorization(MobileModeEnum mode, String code) throws NoSuchAlgorithmException {
        Long recordId = MobileAuthCacheUtil.getRecordId(mode, code);
        Integer mainNumber = MobileAuthCacheUtil.getMainNumber(mode, code);
        Integer subNumber = MobileAuthCacheUtil.getSubNumber(mode, code);
        Integer subIndex = MobileAuthCacheUtil.getSubIndex(mode, code);
        if (MobileAuthCacheUtil.getMode(mode, code) == null) {
            throw new BusinessException("二维码已过期");
        }
        ExamStudentCacheBean es = examStudentService
                .getExamStudentCacheBean(ExamRecordCacheUtil.getExamStudentId(recordId));
        String source = null;
        if (mode.equals(MobileModeEnum.MOBILE_MONITOR)) {
            Source sourceEnum = MobileAuthCacheUtil.getSource(mode, code);
            source = sourceEnum.name();
        } else if (mode.equals(MobileModeEnum.PHOTO_UPLOAD) || mode.equals(MobileModeEnum.AUDIO_UPLOAD)) {
            source = Source.OE_ANSWER.name();
        }
        AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.studentOauth + "::" + es.getStudentId());
        String sessionId = SessionUtil.digest(es.getIdentity(), Math.abs(authDto.getRoleCodes().toString().hashCode()), source);
        MobileAuthCacheUtil.setSessionId(mode, code, sessionId);
        MobileAuthCacheUtil.setPlatformSource(mode, code, source);
        MobileAuthorizationUploadBean ret = new MobileAuthorizationUploadBean();
        ret.setRecordId(recordId);
        ret.setMainNumber(mainNumber);
        ret.setSubNumber(subNumber);
        ret.setSubIndex(subIndex);
        return ret;
    }

    @Override
    public MobileAnswerSubmitReponseBean answerSubmit(Long studentId, Long recordId, Integer mainNumber, Integer subNumber, Integer subIndex,
                                                      String answer) {
        // 校验当前登录用户和参数一致性
        if (ExamRecordCacheUtil.getId(recordId) == null) {
            throw new BusinessException("未找到考试记录");
        }
        Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
        ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
                .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
        if (es == null) {
            throw new BusinessException("未找到考生");
        }
        if (!studentId.equals(es.getStudentId())) {
            throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
        }
        ExamRecordStatusEnum sta = ExamRecordCacheUtil.getStatus(recordId);
        if (ExamRecordStatusEnum.FINISHED.equals(sta) || ExamRecordStatusEnum.PERSISTED.equals(sta)) {
            throw new BusinessException("该考试已结束");
        }
        ExamStudentAnswerCacheBean answerCache = (ExamStudentAnswerCacheBean) redisUtil.get(
                RedisKeyHelper.examAnswerKey(recordId),
                RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex));
        if (answerCache == null) {
            answerCache = new ExamStudentAnswerCacheBean();
            answerCache.setMainNumber(mainNumber);
            answerCache.setSubNumber(subNumber);
            answerCache.setSubIndex(subIndex);
            answerCache.setAnswer(answer);
        }
        // 更新考生作答
        redisUtil.set(RedisKeyHelper.examAnswerKey(recordId),
                RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex), answerCache);
        MobileAnswerSubmitReponseBean ret = new MobileAnswerSubmitReponseBean();
        ret.setUpdateTime(System.currentTimeMillis());
        return ret;
    }
}
