package com.qmth.distributed.print.api;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qmth.boot.api.constant.ApiConstant;
import com.qmth.distributed.print.business.bean.result.EditResult;
import com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult;
import com.qmth.distributed.print.business.entity.ExamPrintPlan;
import com.qmth.distributed.print.business.entity.TBSyncTask;
import com.qmth.distributed.print.business.entity.TSyncExamStudentScore;
import com.qmth.distributed.print.business.enums.ExamPrintPlanSyncStatusEnum;
import com.qmth.distributed.print.business.enums.ImageTrajectoryEnum;
import com.qmth.distributed.print.business.service.BasicExamService;
import com.qmth.distributed.print.business.service.ExamPrintPlanService;
import com.qmth.distributed.print.business.service.PrintCommonService;
import com.qmth.distributed.print.business.service.TSyncExamStudentScoreService;
import com.qmth.distributed.print.business.templete.execute.AsyncScoreBatchDownloadService;
import com.qmth.distributed.print.business.templete.execute.AsyncScoreExportService;
import com.qmth.distributed.print.business.templete.execute.AsyncScorePushService;
import com.qmth.teachcloud.common.base.BaseEntity;
import com.qmth.teachcloud.common.config.DictionaryConfig;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicExam;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.entity.TBTask;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.PushTypeEnum;
import com.qmth.teachcloud.common.enums.TaskTypeEnum;
import com.qmth.teachcloud.common.util.Result;
import com.qmth.teachcloud.common.util.ResultUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import io.swagger.annotations.*;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
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.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 同步考生成绩表 前端控制器
 * </p>
 *
 * @author wangliang
 * @since 2021-10-28
 */
@Api(tags = "成绩归档Controller")
@RestController
@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.sync}")
//@Aac(auth = BOOL.FALSE, strict = BOOL.FALSE)
@Validated
public class TSyncExamStudentScoreController {

    @Resource
    TSyncExamStudentScoreService tSyncExamStudentScoreService;

    @Resource
    PrintCommonService printCommonService;

    @Resource
    AsyncScoreExportService asyncScoreExportService;

    @Resource
    DictionaryConfig dictionaryConfig;

    @Resource
    AsyncScorePushService asyncScorePushService;

    @Resource
    AsyncScoreBatchDownloadService asyncScoreBatchDownloadService;

    @Resource
    ExamPrintPlanService examPrintPlanService;

    @Resource
    BasicExamService basicExamService;

    @ApiOperation(value = "成绩归档查询列表")
    @ApiResponses({@ApiResponse(code = 200, message = "成绩查询信息", response = TSyncExamStudentScoreResult.class)})
    @RequestMapping(value = "/score/list", method = RequestMethod.POST)
    public Result list(@ApiParam(value = "学期ID", required = true) @RequestParam String semesterId,
                       @ApiParam(value = "考试ID", required = true) @RequestParam(required = true) String examId,
                       @ApiParam(value = "班级id", required = false) @RequestParam(required = false) String clazzId,
                       @ApiParam(value = "课程编码", required = true) @RequestParam String courseCode,
                       @ApiParam(value = "页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
                       @ApiParam(value = "数量", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
        return ResultUtil.ok(tSyncExamStudentScoreService.list(new Page<>(pageNumber, pageSize), SystemConstant.convertIdToLong(semesterId), SystemConstant.convertIdToLong(examId), SystemConstant.convertIdToLong(clazzId), courseCode));
    }

    @ApiOperation(value = "成绩导出")
    @ApiResponses({@ApiResponse(code = 200, message = "同步信息", response = TBTask.class)})
    @RequestMapping(value = "/score/export", method = RequestMethod.POST)
    public Result export(@ApiParam(value = "学期ID", required = true) @RequestParam String semesterId,
                         @ApiParam(value = "考试ID", required = true) @RequestParam(required = true) String examId,
                         @ApiParam(value = "班级id", required = false) @RequestParam(required = false) String clazzId,
                         @ApiParam(value = "课程编码", required = true) @RequestParam String courseCode) {
        return createScoreTbTask(TaskTypeEnum.SCORE_EXPORT, semesterId, examId, clazzId, courseCode);
    }

    @ApiOperation(value = "成绩查询同步")
    @ApiResponses({@ApiResponse(code = 200, message = "同步异步任务信息", response = TBSyncTask.class)})
    @RequestMapping(value = "/score/sync", method = RequestMethod.POST)
    public Result sync(@ApiParam(value = "学期ID", required = true) @RequestParam String semesterId,
                       @ApiParam(value = "考试ID", required = true) @RequestParam String examId,
                       @ApiParam(value = "课程编码", required = false) @RequestParam(required = false) String courseCode) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        QueryWrapper<ExamPrintPlan> examPrintPlanQueryWrapper = new QueryWrapper<ExamPrintPlan>();
        examPrintPlanQueryWrapper.select(" DISTINCT third_relate_id ").eq("school_id", sysUser.getSchoolId())
                .eq("exam_id", examId)
                .eq("sync_status", ExamPrintPlanSyncStatusEnum.FINISH);
        List<ExamPrintPlan> examPrintPlanList = examPrintPlanService.list(examPrintPlanQueryWrapper);
        if (Objects.isNull(examPrintPlanList) || examPrintPlanList.size() == 0) {
            throw ExceptionResultEnum.ERROR.exception("此学期学院下未找到需要同步的考试记录");
        }
        LinkedMultiValueMap<Long, Integer> semesterExamIdMap = new LinkedMultiValueMap<>();
        for (ExamPrintPlan e : examPrintPlanList) {
            semesterExamIdMap.add(Long.valueOf(semesterId), Integer.parseInt(String.valueOf(e.getThirdRelateId())));
        }
        Map<String, Object> map = printCommonService.savePush(PushTypeEnum.SCORE_PUSH);
        map.computeIfAbsent("semesterExamIdMap", v -> semesterExamIdMap);
        asyncScorePushService.pushTask(map);
        TBSyncTask tbSyncTask = Objects.nonNull(map.get(SystemConstant.TB_SYNC_TASK)) ? (TBSyncTask) map.get(SystemConstant.TB_SYNC_TASK) : null;
        return Objects.nonNull(tbSyncTask) ? ResultUtil.ok(tbSyncTask.getId()) : ResultUtil.error("创建同步推送任务失败");
    }

    @CrossOrigin(maxAge = 3600) //支持跨域
    @ApiOperation(value = "成绩动态轨迹图下载")
    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = EditResult.class)})
    @RequestMapping(value = "/score/download", method = RequestMethod.POST)
    @Transactional
    public void download(@ApiParam(value = "主键", required = true) @RequestParam String id) throws Exception {
        TSyncExamStudentScore tSyncExamStudentScore = downloadOrPreview(id, ImageTrajectoryEnum.DOWNLOAD);
        tSyncExamStudentScoreService.createZipFile(tSyncExamStudentScore);
    }

    @ApiOperation(value = "成绩归档查看原卷")
    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = EditResult.class)})
    @RequestMapping(value = "/score/preview", method = RequestMethod.POST)
    @Transactional
    public Result preview(@ApiParam(value = "主键", required = true) @RequestParam String id) throws Exception {
        TSyncExamStudentScore tSyncExamStudentScore = downloadOrPreview(id, ImageTrajectoryEnum.PREVIEW);
        return ResultUtil.ok(tSyncExamStudentScore.getTrailUrls());
    }

    @ApiOperation(value = "成绩动态轨迹图一键下载")
    @ApiResponses({@ApiResponse(code = 200, message = "同步信息", response = TBTask.class)})
    @RequestMapping(value = "/score/batch_download", method = RequestMethod.POST)
    public Result batchDownload(@ApiParam(value = "学期id", required = true) @RequestParam String semesterId,
                                @ApiParam(value = "考试ID", required = false) @RequestParam(required = false) String examId,
                                @ApiParam(value = "班级id", required = false) @RequestParam(required = false) String clazzId,
                                @ApiParam(value = "课程编码", required = true) @RequestParam String courseCode) {
        return createScoreTbTask(TaskTypeEnum.SCORE_DOWNLOAD, semesterId, examId, clazzId, courseCode);
    }

    /**
     * 创建任务公用
     *
     * @param taskTypeEnum
     * @param params
     * @return
     */
    private Result createScoreTbTask(TaskTypeEnum taskTypeEnum, String... params) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        int count = tSyncExamStudentScoreService.exportCount(sysUser.getSchoolId(), SystemConstant.convertIdToLong(params[0]), SystemConstant.convertIdToLong(params[1]), SystemConstant.convertIdToLong(params[2]), params[3]);
        if (count == 0) {
            throw ExceptionResultEnum.ERROR.exception("没有成绩信息");
        }
        Map<String, Object> map = printCommonService.saveTask(taskTypeEnum);
        map.computeIfAbsent("semesterId", v -> SystemConstant.convertIdToLong(params[0]));
        map.computeIfAbsent("examId", v -> SystemConstant.convertIdToLong(params[1]));
        map.computeIfAbsent("clazzId", v -> SystemConstant.convertIdToLong(params[2]));
        map.computeIfAbsent("courseCode", v -> params[3]);
        map.computeIfAbsent(SystemConstant.OSS, v -> dictionaryConfig.sysDomain().isOss());
        if (taskTypeEnum == TaskTypeEnum.SCORE_EXPORT) {
            asyncScoreExportService.exportTask(map);
        } else if (taskTypeEnum == TaskTypeEnum.SCORE_DOWNLOAD) {
            asyncScoreBatchDownloadService.exportTask(map);
        } else {
            throw ExceptionResultEnum.ERROR.exception("任务类型错误");
        }
        TBTask tbTask = Objects.nonNull(map.get(SystemConstant.TASK)) ? (TBTask) map.get(SystemConstant.TASK) : null;
        return Objects.nonNull(tbTask) ? ResultUtil.ok(tbTask.getId()) : ResultUtil.error("创建任务失败");
    }

    /**
     * 下载或预览
     *
     * @param id
     * @param imageTrajectoryEnum
     * @return
     */
    private TSyncExamStudentScore downloadOrPreview(String id, ImageTrajectoryEnum imageTrajectoryEnum) {
        TSyncExamStudentScore tSyncExamStudentScore = tSyncExamStudentScoreService.getById(SystemConstant.convertIdToLong(id));
        Optional.ofNullable(tSyncExamStudentScore).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未找到此考生信息"));
        boolean update = Objects.isNull(tSyncExamStudentScore.getTrajectoryUrls()) ? true : false;
        tSyncExamStudentScore = tSyncExamStudentScoreService.createImageTrajectory(tSyncExamStudentScore, imageTrajectoryEnum);
        Optional.ofNullable(tSyncExamStudentScore.getTrajectoryUrls()).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("阅卷方式未使用轨迹阅卷，无轨迹图"));
        if (update || Objects.isNull(tSyncExamStudentScore.getTrajectoryUrls())) {
            tSyncExamStudentScoreService.updateById(tSyncExamStudentScore);
        }
        return tSyncExamStudentScore;
    }
}
