package com.qmth.themis.admin.api;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qmth.themis.business.annotation.ApiJsonObject;
import com.qmth.themis.business.annotation.ApiJsonProperty;
//import com.qmth.themis.business.annotation.RedisLimitAnnotation;
import com.qmth.themis.business.bean.admin.ReexamListRequestBean;
import com.qmth.themis.business.cache.bean.ExamCacheBean;
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.entity.TBUser;
import com.qmth.themis.business.entity.TEExamReexam;
import com.qmth.themis.business.entity.TEExamReexamAuditing;
import com.qmth.themis.business.entity.TEExamStudent;
import com.qmth.themis.business.enums.ReexamReasonEnum;
import com.qmth.themis.business.enums.RoleEnum;
import com.qmth.themis.business.service.*;
import com.qmth.themis.business.util.RedisUtil;
import com.qmth.themis.business.util.ServletUtil;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import java.util.*;

/**
 * @Description: 考生重考处理 前端控制器
 * @Param:
 * @returnß:
 * @Author: wangliang
 * @Date: 2020/6/25
 */
@Api(tags = "考生重考处理Controller")
@RestController
@RequestMapping(SystemConstant.PREFIX_URL_ADMIN + "/invigilate/reexam")
@Validated
public class TEExamReexamController {
    private final static Logger log = LoggerFactory.getLogger(TEExamReexamController.class);

    @Resource
    TEExamReexamService teExamReexamService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    TEExamService teExamService;

    @Resource
    TBUserRoleService tbUserRoleService;

    @Resource
    TEExamReexamAuditingService teExamReexamAuditingService;

    @Resource
    TEExamStudentService teExamStudentService;

    @Resource
    ThemisCacheService themisCacheService;

    @ApiOperation(value = "重考申请接口")
    @RequestMapping(value = "/apply", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Transactional
    public Result apply(@ApiJsonObject(name = "reexamApply", value = {
            @ApiJsonProperty(key = "examStudentId", description = "考生id数组", required = true),
            @ApiJsonProperty(key = "model", type = "int", example = "1", description = "重考方式", required = true),
            @ApiJsonProperty(key = "reason", description = "重考原因", required = true),
            @ApiJsonProperty(key = "remark", description = "备注")
    }) @ApiParam(value = "重考信息", required = true) @RequestBody Map<String, Object> mapParameter) {
        if (Objects.isNull(mapParameter.get(SystemConstant.EXAM_STUDENT_ID)) || Objects.equals(mapParameter.get(SystemConstant.EXAM_STUDENT_ID), "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_STUDENT_ID_IS_NULL);
        }
        List<String> examStudentIdList = (List<String>) mapParameter.get(SystemConstant.EXAM_STUDENT_ID);
        if (Objects.isNull(mapParameter.get("model")) || Objects.equals(mapParameter.get("model"), "")) {
            throw new BusinessException("重考方式不能为空");
        }
        Integer model = Integer.parseInt(String.valueOf(mapParameter.get("model")));
        if (Objects.isNull(mapParameter.get("reason")) || Objects.equals(mapParameter.get("reason"), "")) {
            throw new BusinessException("重考原因不能为空");
        }
        List<Long> examStudentIdNotAuditingList = null;
        if (examStudentIdList.size() > 0) {
            examStudentIdNotAuditingList = new ArrayList<>();
            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
            ReexamReasonEnum reason = ReexamReasonEnum.valueOf(String.valueOf(mapParameter.get("reason")));
            Integer reexamAuditing = null, status;
            List<TEExamReexamAuditing> teExamReexamAuditingList = new ArrayList<>();
            List<TEExamStudent> teExamStudentList = teExamStudentService.listByIds(examStudentIdList);
            for (TEExamStudent teExamStudent : teExamStudentList) {
                if (Objects.nonNull(teExamStudent)) {
                    if (redisUtil.lock(SystemConstant.REDIS_LOCK_EXAM_STUDENT_PREFIX + teExamStudent.getId(), SystemConstant.REDIS_LOCK_REEXAM_EXAM_STUDENT_TIME_OUT)) {
                        try {
                            ExamCacheBean examCacheBean = teExamService.getExamCacheBean(teExamStudent.getExamId());//考试缓存
                            if (Objects.isNull(examCacheBean)) {
                                throw new BusinessException("考试批次[" + examCacheBean + "]不存在");
                            }
                            reexamAuditing = examCacheBean.getReexamAuditing();
                            status = Objects.isNull(reexamAuditing) || reexamAuditing.intValue() == 0 ? 0 : 1;
                            TEExamReexam teExamReexam = new TEExamReexam(teExamStudent.getExamId(), teExamStudent.getExamActivityId(), teExamStudent.getId(), model, reason, status, Objects.isNull(mapParameter.get(SystemConstant.REMARK)) ? null : String.valueOf(mapParameter.get(SystemConstant.REMARK)));
                            teExamReexam.setCreateId(tbUser.getId());
                            if (Objects.nonNull(status) && status.intValue() == 1) {
                                //这里查询该机构下所有为管理员角色的账号
                                List<TBUser> tbUserList = tbUserRoleService.userQueryByRole(tbUser.getOrgId(), RoleEnum.ADMIN.name());
                                if (Objects.nonNull(tbUserList) && tbUserList.size() > 0) {
                                    for (TBUser t : tbUserList) {
                                        TEExamReexamAuditing teExamReexamAuditing = new TEExamReexamAuditing(teExamReexam.getId(), t.getId());
                                        teExamReexamAuditingList.add(teExamReexamAuditing);
                                    }
                                }
                            } else if (Objects.nonNull(status) && status.intValue() == 0) {//无需审核时考生已考次数-1
                                examStudentIdNotAuditingList.add(teExamStudent.getId());
                                teExamReexam.setAuditingId(tbUser.getId());
                                teExamReexam.setAuditingStatus(0);
                                teExamReexam.setAuditingTime(System.currentTimeMillis());
                                teExamReexam.setAuditingSuggest("无需审核");
                                teExamReexam.setUpdateId(tbUser.getId());
                            }
                            teExamReexamService.save(teExamReexam);
                        } finally {
                            redisUtil.releaseLock(SystemConstant.REDIS_LOCK_EXAM_STUDENT_PREFIX + teExamStudent.getId());
                        }
                    }
                }
            }
            if (Objects.nonNull(teExamReexamAuditingList) && teExamReexamAuditingList.size() > 0) {
                teExamReexamAuditingService.saveBatch(teExamReexamAuditingList);
            }
            if (Objects.nonNull(examStudentIdNotAuditingList) && examStudentIdNotAuditingList.size() > 0) {
                examStudentIdNotAuditingList.forEach(s -> {
                    ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(s);
                    if (Objects.nonNull(examStudentCacheBean)) {
                        if (redisUtil.lock(SystemConstant.REDIS_LOCK_EXAM_STUDENT_NOT_AUDITING_PREFIX + s, SystemConstant.REDIS_LOCK_REEXAM_EXAM_STUDENT_TIME_OUT)) {
                            try {
                                Integer alreadyExamCount = Objects.nonNull(examStudentCacheBean.getAlreadyExamCount()) ? examStudentCacheBean.getAlreadyExamCount() : 0;
                                if (alreadyExamCount > 0) {
                                    alreadyExamCount = alreadyExamCount - 1;
                                    ExamCacheBean ec = teExamService.getExamCacheBean(examStudentCacheBean.getExamId());//考试缓存
                                    if (alreadyExamCount.intValue() >= ec.getExamCount().intValue()) {
                                        alreadyExamCount = 0;
                                    }
                                    UpdateWrapper<TEExamStudent> teExamStudentUpdateWrapper = new UpdateWrapper<>();
                                    teExamStudentUpdateWrapper.lambda().set(TEExamStudent::getAlreadyExamCount, alreadyExamCount)
                                            .eq(TEExamStudent::getId, s);
                                    teExamStudentService.update(teExamStudentUpdateWrapper);
                                    teExamStudentService.updateExamStudentCacheBean(s);
                                }
                            } finally {
                                redisUtil.releaseLock(SystemConstant.REDIS_LOCK_EXAM_STUDENT_NOT_AUDITING_PREFIX + s);
                            }
                        }
                    }
                });
            }
        }
        return ResultUtil.ok(true);
    }

    @ApiOperation(value = "重考审核接口")
    @RequestMapping(value = "/auditing", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Transactional
    public Result auditing(@ApiJsonObject(name = "reexamAuditing", value = {
            @ApiJsonProperty(key = "reexamId", description = "重考id数组", required = true),
            @ApiJsonProperty(key = "auditingSuggest", description = "审批意见"),
            @ApiJsonProperty(key = "auditingStatus", type = "long", example = "1", description = "审批状态", required = true)
    }) @ApiParam(value = "重考信息", required = true) @RequestBody Map<String, Object> mapParameter) {
        if (Objects.isNull(mapParameter.get("reexamId")) || Objects.equals(mapParameter.get("reexamId"), "")) {
            throw new BusinessException("重考id不能为空");
        }
        List<String> reexamIdList = null;
        try {
            reexamIdList = (List<String>) mapParameter.get("reexamId");
            if (Objects.isNull(mapParameter.get("auditingStatus")) || Objects.equals(mapParameter.get("auditingStatus"), "")) {
                throw new BusinessException("审批状态不能为空");
            }
            if (reexamIdList.size() > 0) {
                Integer auditingStatus = Integer.parseInt(String.valueOf(mapParameter.get("auditingStatus")));
                TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
                List<TEExamReexam> teExamReexamUpdateList = new ArrayList<>();
                for (String reexamId : reexamIdList) {
                    if (redisUtil.lock(SystemConstant.REDIS_LOCK_REEXAM_AUDITING_PREFIX + Long.parseLong(reexamId), SystemConstant.REDIS_LOCK_REEXAM_TIME_OUT)) {
                        try {
                            TEExamReexam teExamReexam = teExamReexamService.getById(Long.parseLong(reexamId));
                            if (Objects.isNull(teExamReexam)) {
                                throw new BusinessException("重考id[" + reexamId + "]记录不存在");
                            }
                            if (Objects.nonNull(teExamReexam.getStatus()) && teExamReexam.getStatus().intValue() == 2) {
                                throw new BusinessException("重考id[" + reexamId + "]已经审核");
                            } else {
                                teExamReexam.setAuditingId(tbUser.getId());
                                teExamReexam.setAuditingStatus(auditingStatus);
                                teExamReexam.setAuditingTime(System.currentTimeMillis());
                                teExamReexam.setAuditingSuggest(Objects.isNull(mapParameter.get("auditingSuggest")) ? null : String.valueOf(mapParameter.get("auditingSuggest")));
                                teExamReexam.setStatus(2);
                                teExamReexam.setUpdateId(tbUser.getId());
                                teExamReexamUpdateList.add(teExamReexam);
                                if (auditingStatus.intValue() == 0) {
                                    ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(teExamReexam.getExamStudentId());
                                    if (Objects.nonNull(examStudentCacheBean)) {
                                        Integer alreadyExamCount = Objects.nonNull(examStudentCacheBean.getAlreadyExamCount()) ? examStudentCacheBean.getAlreadyExamCount() : 0;
                                        if (alreadyExamCount > 0) {
                                            alreadyExamCount = alreadyExamCount - 1;
                                            ExamCacheBean ec = teExamService.getExamCacheBean(teExamReexam.getExamId());//考试缓存
                                            if (alreadyExamCount.intValue() >= ec.getExamCount().intValue()) {
                                                alreadyExamCount = 0;
                                            }
                                            UpdateWrapper<TEExamStudent> teExamStudentUpdateWrapper = new UpdateWrapper<>();
                                            teExamStudentUpdateWrapper.lambda().set(TEExamStudent::getAlreadyExamCount, alreadyExamCount)
                                                    .eq(TEExamStudent::getId, teExamReexam.getExamStudentId());
                                            teExamStudentService.update(teExamStudentUpdateWrapper);
                                            teExamStudentService.updateExamStudentCacheBean(teExamReexam.getExamStudentId());
                                        }
                                    }
                                }
                            }
                        } finally {
                            redisUtil.releaseLock(SystemConstant.REDIS_LOCK_REEXAM_AUDITING_PREFIX + Long.parseLong(reexamId));
                        }
                    }
                }
                teExamReexamService.updateBatchById(teExamReexamUpdateList);
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        return ResultUtil.ok(true);
    }

    @ApiOperation(value = "重考审核明细接口")
    @RequestMapping(value = "/detail", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = TEExamReexam.class)})
    public Result detail(@ApiParam(value = "重考id") @RequestParam Long reexamId) {
        if (Objects.isNull(reexamId) || Objects.equals(reexamId, "")) {
            throw new BusinessException("重考id不能为空");
        }
        return ResultUtil.ok(teExamReexamService.getById(reexamId));
    }

    @ApiOperation(value = "重考申请列表接口")
    @RequestMapping(value = "/list", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = ReexamListRequestBean.class)})
    public Result list(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
                       @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
                       @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
                       @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
                       @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
                       @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
                       @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
                       @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        AuthDto authDto = themisCacheService.addAccountAuthCache(tbUser.getId());
        //如果有监考员角色，只能查看自己所监考的考场，巡考员和管理员则可以查看全部考场
        Long userId = null;
        if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
            userId = tbUser.getId();
        }
        return ResultUtil.ok(teExamReexamService.reexamPageRequestList(new Page<>(pageNumber, pageSize), examId, examActivityId, roomCode, courseCode, name, identity, userId, tbUser.getOrgId()));
    }

    @ApiOperation(value = "重考待审列表接口")
    @RequestMapping(value = "/list_not_done", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = ReexamListRequestBean.class)})
    public Result listNotDone(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
                              @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
                              @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
                              @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
                              @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
                              @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
                              @ApiParam(value = "申请理由", required = false) @RequestParam(required = false) String reason,
                              @ApiParam(value = "申请开始时间", required = false) @RequestParam(required = false) Long reasonStartTime,
                              @ApiParam(value = "申请结束时间", required = false) @RequestParam(required = false) Long reasonEndTime,
                              @ApiParam(value = "申请人", required = false) @RequestParam(required = false) String applyName,
                              @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
                              @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return ResultUtil.ok(teExamReexamService.reexamPageNotDoneList(new Page<>(pageNumber, pageSize), examId, examActivityId, roomCode, courseCode, name, identity, reason, reasonStartTime, reasonEndTime, applyName, tbUser.getId(), tbUser.getOrgId()));
    }

    @ApiOperation(value = "重考待审提醒接口")
    @RequestMapping(value = "/list_not_done_notify", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
//    @RedisLimitAnnotation(key = "listNotDoneNotify", period = 1, count = 1)
    public Result listNotDoneNotify(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        Integer count = teExamReexamService.reexamPageNotDoneCount(examId, tbUser.getId(), tbUser.getOrgId());
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.COUNT, count));
    }

    @ApiOperation(value = "重考已审列表接口")
    @RequestMapping(value = "/list_done", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = ReexamListRequestBean.class)})
    public Result listDone(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
                           @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
                           @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
                           @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
                           @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
                           @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
                           @ApiParam(value = "审核状态", required = false) @RequestParam(required = false) Integer auditingStatus,
                           @ApiParam(value = "申请开始时间", required = false) @RequestParam(required = false) Long reasonStartTime,
                           @ApiParam(value = "申请结束时间", required = false) @RequestParam(required = false) Long reasonEndTime,
                           @ApiParam(value = "申请人", required = false) @RequestParam(required = false) String applyName,
                           @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
                           @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return ResultUtil.ok(teExamReexamService.reexamPageDoneList(new Page<>(pageNumber, pageSize), examId, examActivityId, roomCode, courseCode, name, identity, auditingStatus, reasonStartTime, reasonEndTime, applyName, tbUser.getId(), tbUser.getOrgId()));
    }
}
