package com.qmth.themis.exam.api;

import com.alibaba.fastjson.JSONObject;
import com.qmth.themis.business.bean.exam.*;
import com.qmth.themis.business.bean.mobile.MobileAuthorizationBean;
import com.qmth.themis.business.bean.mobile.MobileAuthorizationParamBean;
import com.qmth.themis.business.bean.result.TEAudioResult;
import com.qmth.themis.business.cache.ExamRecordCacheUtil;
import com.qmth.themis.business.cache.MobileAuthCacheUtil;
import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dto.MqDto;
import com.qmth.themis.business.dto.cache.TEStudentCacheDto;
import com.qmth.themis.business.entity.SysConfig;
import com.qmth.themis.business.entity.TBAttachment;
import com.qmth.themis.business.enums.ExamRecordStatusEnum;
import com.qmth.themis.business.enums.MobileModeEnum;
import com.qmth.themis.business.enums.MqTagEnum;
import com.qmth.themis.business.service.*;
import com.qmth.themis.business.util.*;
import com.qmth.themis.common.enums.ExceptionResultEnum;
import com.qmth.themis.common.exception.BusinessException;
import com.qmth.themis.common.util.Result;
import com.qmth.themis.common.util.ResultUtil;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Api(tags = "移动端接口")
@RestController
@RequestMapping(SystemConstant.PREFIX_URL_MOBILE)
public class TEMobileController {

    @Resource
    TEMobileService mobileService;

    @Resource
    TEExamService examService;

    @Resource
    TEExamStudentService examStudentService;

    @Resource
    MqUtil mqUtil;

    @Resource
    MqDtoService mqDtoService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    TEAudioService teAudioService;

    @Resource
    ThemisCacheService themisCacheService;

    @Resource
    OssUtil ossUtil;

    @ApiOperation(value = "获取登录详细信息")
    @RequestMapping(value = "/authorization", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "登录信息", response = MobileAuthorizationBean.class)})
    public Result authorization(@RequestBody MobileAuthorizationParamBean param) throws NoSuchAlgorithmException {
        if (param.getMode() == null) {
            throw new BusinessException("mode不能为空");
        }
        if (param.getCode() == null) {
            throw new BusinessException("code不能为空");
        }
        String lockKey = SystemConstant.REDIS_LOCK_MOBILE_AUTHORIZATION_PREFIX + param.toString();
        Boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_CACHE_TIME_OUT);
        if (!lock) {
            throw new BusinessException(ExceptionResultEnum.REQUEST_AWAIT);
        }
        try {
            MobileAuthorizationBean mobileAuthorizationBean = mobileService.authorization(param);
            MobileModeEnum mode = MobileModeEnum.valueOf(param.getMode().toUpperCase());
            if (Objects.nonNull(mode) && MobileModeEnum.MOBILE_MONITOR.equals(mode)) {
                SysConfig sysConfigQrExpireTime = themisCacheService.addSysConfigCache(SystemConstant.QR_EXPIRE_TIME);
                Optional.ofNullable(sysConfigQrExpireTime).orElseThrow(() -> new BusinessException("未设置二维码失效时间"));

                Integer qrExpireTime = Integer.parseInt(sysConfigQrExpireTime.getConfigValue());
                if (qrExpireTime.intValue() > 0) {
                    MobileAuthCacheUtil.deleteMode(MobileModeEnum.valueOf(param.getMode().toUpperCase()), param.getCode());
                }
            }
            return ResultUtil.ok(mobileAuthorizationBean);
        } finally {
            redisUtil.releaseLock(lockKey);
        }
    }

    @ApiOperation(value = "拍照/录音答题就绪")
    @RequestMapping(value = "/answer/ready", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "拍照/录音信息", response = AnswerReadyResponseBean.class)})
    public Result answerReady(@RequestBody AnswerReadyParamBean param) {
        if (param.getRecordId() == null) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        if (param.getMainNumber() == null) {
            throw new BusinessException("大题号不能为空");
        }
        if (param.getSubNumber() == null) {
            throw new BusinessException("小题号不能为空");
        }
        Long esId = ExamRecordCacheUtil.getExamStudentId(param.getRecordId());
        if (ExamRecordCacheUtil.getId(param.getRecordId()) == null) {
            throw new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD);
        }
        SystemConstant.checkExamStatus(param.getRecordId());
        ExamRecordStatusEnum sta = ExamRecordCacheUtil.getStatus(param.getRecordId());
//        if (ExamRecordStatusEnum.FIRST_PREPARE.equals(sta)) {
//            throw new BusinessException("该考试未开始答题");
//        }
        if (ExamRecordStatusEnum.FINISHED.equals(sta) || ExamRecordStatusEnum.PERSISTED.equals(sta) || sta == ExamRecordStatusEnum.JUNK) {
            throw new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_STUDENT);
        }

        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        Map<String, Object> mapParameter = new HashMap<String, Object>();
        mapParameter.put(SystemConstant.RECORD_ID, param.getRecordId());
        mapParameter.put("mainNumber", param.getMainNumber());
        mapParameter.put("subNumber", param.getSubNumber());
        if (param.getSubIndex() != null) {
            mapParameter.put("subIndex", param.getSubIndex());
        }
        MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_READY.name(), param.getRecordId(), MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_READY, String.valueOf(param.getRecordId()), mapParameter, teStudent.getName());
        mqDtoService.assembleSendAsyncOrderMsg(mqDto);
        ExamStudentCacheBean es = examStudentService.getExamStudentCacheBean(esId);
        AnswerReadyResponseBean ret = new AnswerReadyResponseBean();
        ret.setCourseName(es.getCourseName());
        ret.setExamName(examService.getExamCacheBean(es.getExamId()).getName());
        return ResultUtil.ok(ret);
    }

    @ApiOperation(value = "文件上传")
    @RequestMapping(value = "/file/upload", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "附件信息", response = ExamFileUploadBean.class)})
    public Result fileUpload(@ApiParam(value = "考试记录ID", required = true) @RequestParam Long recordId,
                             @ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file,
                             @ApiParam(value = "后缀名", required = true) @RequestParam String suffix,
                             @ApiParam(value = "md5", required = true) @RequestParam String md5) {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        SystemConstant.checkExamStatus(recordId);
        return ResultUtil.ok(examService.fileUpload(teStudent.getId(), recordId, file, suffix, md5));
    }

    @ApiOperation(value = "提交作答结果")
    @RequestMapping(value = "/answer/submit", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "答案信息", response = MobileAnswerSubmitReponseBean.class)})
    public Result answerSubmit(@RequestBody MobileAnswerSubmitParamBean param) {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        if (param.getRecordId() == null) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        if (param.getMainNumber() == null) {
            throw new BusinessException("大题号不能为空");
        }
        if (param.getSubNumber() == null) {
            throw new BusinessException("小题号不能为空");
        }
        if (StringUtils.isBlank(param.getUrls())) {
            throw new BusinessException("答案不能为空");
        }
        SystemConstant.checkExamStatus(param.getRecordId());
        MobileAnswerSubmitReponseBean ret = mobileService.answerSubmit(teStudent.getId(), param.getRecordId(), param.getMainNumber(),
                param.getSubNumber(), param.getSubIndex(), param.getUrls());
        Map<String, Object> mapParameter = new HashMap<String, Object>();
        mapParameter.put(SystemConstant.RECORD_ID, param.getRecordId());
        mapParameter.put("mainNumber", param.getMainNumber());
        mapParameter.put("subNumber", param.getSubNumber());
        if (param.getSubIndex() != null) {
            mapParameter.put("subIndex", param.getSubIndex());
        }
        mapParameter.put("urls", param.getUrls());

        MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_UPLOAD.name(), param.getRecordId(), MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_READY, String.valueOf(param.getRecordId()), mapParameter, teStudent.getName());
        mqDtoService.assembleSendAsyncOrderMsg(mqDto);
        return ResultUtil.ok(ret);
    }

    @ApiOperation(value = "查询考试状态")
    @RequestMapping(value = "/exam/status", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考试状态", response = ExamRecordStatusEnum.class)})
    public Result examStatus(@RequestBody MobileAnswerSubmitParamBean param) {
        if (Objects.isNull(param)) {
            throw new BusinessException(ExceptionResultEnum.PARAMS_ILLEGALITY);
        }
        if (Objects.isNull(param.getRecordId())) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(param.getRecordId());
        if (Objects.isNull(examRecordStatusEnum)) {
            examRecordStatusEnum = Objects.isNull(examRecordStatusEnum) ? SystemConstant.getExamStatus(param.getRecordId()) : examRecordStatusEnum;
        }
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.STATUS, examRecordStatusEnum));
    }

    @ApiOperation(value = "查询考试语音信息")
    @RequestMapping(value = "/exam/audio/query", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "语音信息", response = TEAudioResult.class)})
    public Result examAudioQuery(@RequestBody MobileAnswerSubmitParamBean param) {
        if (Objects.isNull(param)) {
            throw new BusinessException(ExceptionResultEnum.PARAMS_ILLEGALITY);
        }
        if (Objects.isNull(param.getRecordId())) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        List<TEAudioResult> teAudioList = null;
        ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(param.getRecordId());
        if (Objects.nonNull(examRecordStatusEnum)) {
            teAudioList = teAudioService.query(ExamRecordCacheUtil.getExamActivityId(param.getRecordId()));
            if (!CollectionUtils.isEmpty(teAudioList)) {
                for (TEAudioResult t : teAudioList) {
                    if (Objects.nonNull(t.getAttachmentId())) {
                        TBAttachment tbAttachment = themisCacheService.attachmentCache(t.getAttachmentId());
                        if (Objects.nonNull(tbAttachment) && Objects.nonNull(tbAttachment.getRemark())) {
                            JSONObject jsonObject = JSONObject.parseObject(tbAttachment.getRemark());
                            t.setAttachmentPath(ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + jsonObject.getString(SystemConstant.PATH));
                        }
                        t.setAttachmentName(tbAttachment.getName() + tbAttachment.getType());
                        t.setAttachmentMd5(tbAttachment.getMd5());
                    }
                }
            }
        }
        return ResultUtil.ok(Collections.singletonMap("audios", teAudioList));
    }
}
