package com.ruoyi.web.controller.front;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Dict;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.ruoyi.common.core.content.VistorContextHolder;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.AjaxResult2;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.ExamType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.dz.domain.DzControl;
import com.ruoyi.dz.domain.DzSubject;
import com.ruoyi.dz.service.IDzControlService;
import com.ruoyi.dz.service.IDzSubjectService;
import com.ruoyi.enums.PaperType;
import com.ruoyi.ie.domain.AEnrollUniversity;
import com.ruoyi.ie.domain.AMarjorPlan;
import com.ruoyi.ie.service.IAEnrollUniversityService;
import com.ruoyi.ie.service.IAMarjorPlanService;
import com.ruoyi.learn.domain.*;
import com.ruoyi.learn.service.*;
import com.ruoyi.sy.domain.SyMajor;
import com.ruoyi.sy.service.ISyMajorService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.service.ExamService;
import com.ruoyi.web.service.LearnStatService;
import com.ruoyi.web.service.LearnTeacherService;
import com.ruoyi.web.service.StudentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.web.bind.annotation.*;

import javax.validation.ValidationException;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/front/student")
@Api(tags = "前台-学习-学生")
public class FrontStudentController extends BaseController {
    private final IDzControlService dzControlService;
    private final IAEnrollUniversityService universityService;
    private final ISyMajorService syMajorService;
    private final ISysUserService sysUserService;
    private final ILearnPlanService learnPlanService;
    private final ILearnPlanStudyService learnPlanStudyService;
    private final IAMarjorPlanService marjorPlanService;
    private final ILearnDirectedKnowledgeService learnDirectedKnowledgeService;
    private final StudentService studentService;
    private final IDzSubjectService dzSubjectService;
    private final LearnTeacherService learnTeacherService;
    private final LearnStatService learnStatService;
    private final ExamService examService;
    private final ILearnTestStudentService learnTestStudentService;

    public FrontStudentController(IDzControlService dzControlService, IAEnrollUniversityService universityService, ISyMajorService syMajorService, ISysUserService sysUserService,
                                  ILearnPlanService learnPlanService, ILearnPlanStudyService learnPlanStudyService, IAMarjorPlanService marjorPlanService, ILearnDirectedKnowledgeService learnDirectedKnowledgeService, StudentService studentService, IDzSubjectService dzSubjectService, LearnTeacherService learnTeacherService, LearnStatService learnStatService, ExamService examService, ILearnTestStudentService learnTestStudentService) {
        this.dzControlService = dzControlService;
        this.universityService = universityService;
        this.syMajorService = syMajorService;
        this.sysUserService = sysUserService;
        this.learnPlanService = learnPlanService;
        this.learnPlanStudyService = learnPlanStudyService;
        this.marjorPlanService = marjorPlanService;
        this.learnDirectedKnowledgeService = learnDirectedKnowledgeService;
        this.studentService = studentService;
        this.dzSubjectService = dzSubjectService;
        this.learnTeacherService = learnTeacherService;
        this.learnStatService = learnStatService;
        this.examService = examService;
        this.learnTestStudentService = learnTestStudentService;
    }

    @ApiOperation("02 全部科目")
    @GetMapping(value = "subject")
    public AjaxResult2<List<DzSubject>> getSubject(@ApiParam("定向") @RequestParam(defaultValue = "false") boolean directed) {
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        DzSubject sCond = new DzSubject();
        sCond.setLocations(sysUser.getLocation());
        sCond.setExamTypes(sysUser.getExamType().name());
        List<DzSubject> list = dzSubjectService.selectDzSubjectList(sCond);
        if(ExamType.VHS.equals(sysUser.getExamType())) {
            Long validSubjectId = null != sysUser.getExamMajor() ? sysUser.getExamMajor().longValue() : 0L;
            return AjaxResult2.success(list.stream().filter(t -> t.getSubjectId() < 10 || t.getSubjectId().equals(validSubjectId)).collect(Collectors.toList()));
        }
        return AjaxResult2.success(list);
    }

    @ApiOperation("试卷作业统计")
    @GetMapping("paperStats")
    public AjaxResult paperStats()
    {
        return AjaxResult.success(studentService.selectStatsForStudent(SecurityUtils.getUserId()));
    }

    @ApiOperation("试卷作业列表")
    @GetMapping("papers")
    public TableDataInfo papers(@ApiParam("status=1未做3正做4完成") Integer status)
    {
        startPage();
        List<LearnPaper> list = studentService.selectLearnPaperForStudent(SecurityUtils.getUserId(), status);
        return getDataTable(list);
    }

    @ApiOperation("01 计划院校列表")
    @GetMapping(value = "university")
    public AjaxResult getUniversity() {
        DzControl dzControl = dzControlService.selectDzControl(VistorContextHolder.getContext());
        AEnrollUniversity cond = new AEnrollUniversity();
        cond.setYear(dzControl.getPlanYear());
        return AjaxResult.success(universityService.selectAEnrollUniversityList(cond).stream().map(
                t -> JSONObject.of("universityId", t.getUniversityId(), "universityName", t.getUniversityName())
        ).collect(Collectors.toList()));
    }

    @ApiOperation("02 计划院校专业及上级")
    @GetMapping(value = "university/major")
    public AjaxResult getUniversityMajor(@ApiParam("院校ID") Long universityId) {
        SysUser sysUser = VistorContextHolder.getContext();
        DzControl dzControl = dzControlService.selectDzControl(sysUser);
        List<SyMajor> syMajorList = syMajorService.selectPlanMajorList(dzControl.getPlanYear(), sysUser, universityId);

        LearnDirectedKnowledge dkCond = new LearnDirectedKnowledge();
        dkCond.setUniversityId(universityId);
        dkCond.setMatchYear(dzControl.getPlanYear());
        dkCond.setLocations(sysUser.getLocation());
        dkCond.setExamineeTypes(sysUser.getExamType().name());
        Map<String, LearnDirectedKnowledge> directedKnowledgeMap = learnDirectedKnowledgeService.selectLearnDirectedKnowledgeList(dkCond).stream().collect(Collectors.toMap(LearnDirectedKnowledge::getDirectKey, t -> t));
        return AjaxResult.success(syMajorList.stream().map(t -> {
            String majorGroup = t.getExamType();
            String majorName = t.getParentCode();
            t.setParentCode(null);
            t.setExamType(null);
            t.setParams(null);
            JSONObject o = JSONObject.from(t);
            LearnDirectedKnowledge learnDirectedKnowledge = learnTeacherService.getBestLearnDirectedKnowledge(majorGroup, majorName, directedKnowledgeMap);
            o.put("notice", null != learnDirectedKnowledge && "技能展示/实践操作".equals(learnDirectedKnowledge.getModules()) ? "该专业只考技能展示/实践操作" : "");
            o.put("majorGroup",majorGroup);
            return o;
        }).collect(Collectors.toList()));
    }

    @ApiOperation("30 计划院校专业信息")
    @GetMapping("university/plan")
    public AjaxResult getUniversityPlan(@ApiParam("专业") Long planId) {
        AMarjorPlan mp = marjorPlanService.selectAMarjorPlanById(planId);
        LearnDirectedKnowledge cond = new LearnDirectedKnowledge();
        String groupName = StringUtils.trimToEmpty(mp.getMajorGroup());
        List<LearnDirectedKnowledge> result = null;
        if(StringUtils.isNotBlank(mp.getMajorName())) {
            cond.setDirectKey(mp.getYear() + "_" + mp.getUniversityId() + "_" + groupName + "_" + mp.getMajorName()); // 三级键
            result = learnDirectedKnowledgeService.selectLearnDirectedKnowledgeList(cond);
        }
        if(CollectionUtils.isEmpty(result)) {
            cond.setDirectKey(mp.getYear() + "_" + mp.getUniversityId() + "_" + groupName); // 二级键
            result = learnDirectedKnowledgeService.selectLearnDirectedKnowledgeList(cond);
        }
        if(CollectionUtils.isEmpty(result) && StringUtils.isNotBlank(groupName)) {
            cond.setDirectKey(mp.getYear() + "_" + mp.getUniversityId().toString()); // 一级键
            result = learnDirectedKnowledgeService.selectLearnDirectedKnowledgeList(cond);
        }
        return CollectionUtils.isNotEmpty(result) ? AjaxResult.success(result.get(0)) : AjaxResult.error("无计划");
    }

    @ApiOperation("03 查询学生定向院校")
    @GetMapping(value = "simulated/info")
    public AjaxResult getSimulateInfo() {
        JSONObject result = new JSONObject();
        SysUser user = SecurityUtils.getLoginUser().getUser();
        if(ExamType.OHS.name().equals(user.getUserType())) {
            result.put("subjects", Lists.newArrayList("职业技能", "语数外"));
        } else {
            result.put("subjects", Lists.newArrayList("职业技能"));
        }
        SysUser sysUser = sysUserService.selectUserById(SecurityUtils.getUserId());
        result.put("evalCount", sysUser.getEvalCounts());
        return AjaxResult.success(result);
    }

    @ApiOperation("03 查询学生定向院校")
    @GetMapping(value = "directed/school")
    public AjaxResult getDirectionSchools() {
        SysUser user = sysUserService.selectUserById(SecurityUtils.getLoginUser().getUserId());
        List<JSONObject> resultList = Lists.newArrayList();
        List<Long> idList = Lists.newArrayList();
        if(StringUtils.isBlank(user.getDirectedStudy())) {
            return AjaxResult.success(resultList);
        }
        JSONArray.parse(user.getDirectedStudy()).stream().forEach(t -> {
            JSONObject o = (JSONObject) t;
            idList.add(o.getLong("majorId"));
            o.put("notice", "");
            resultList.add(o);
        });
        if(idList.isEmpty()) {
            return AjaxResult.success(resultList);
        }
        Integer planYear = dzControlService.selectDzControl(VistorContextHolder.getContext()).getPlanYear();
        Set<Long> idSet = marjorPlanService.selectAMarjorPlanByIds(idList.toArray(new Long[idList.size()])).stream()
                .filter(t -> t.getMatchYear().equals(planYear)).map(t -> t.getId()).collect(Collectors.toSet());
        return AjaxResult.success(resultList.stream().filter(t -> idSet.contains(t.getLong("majorId"))));
    }

    @ApiOperation("04 保存学生定向院校")
    @PostMapping(value = "directed/school")
    public AjaxResult saveStudySchool(@RequestBody JSONArray directionStudy) {
        SysUser user = new SysUser();
        user.setUserId(SecurityUtils.getLoginUser().getUserId());
        if(!directionStudy.isEmpty()) {
            JSONObject directed = directionStudy.getJSONObject(0);
            Long planId = directed.getLongValue("majorId");
            Long universityId = directed.getLongValue("universityId");
            directed.put("notice", learnTeacherService.updateDirected(user.getUserId(), universityId, planId));
            directionStudy.set(0, directed);
        }
        user.setDirectedStudy(directionStudy.toJSONString());
        return sysUserService.updateUserProfile(user) > 0 ? AjaxResult.success("更新成功") : AjaxResult.success("无更新");
    }

    @ApiOperation("10 查询学习计划")
    @GetMapping("plan")
    public AjaxResult getPlan()
    {
        return AjaxResult.success(learnPlanService.getCurrLearnPlan());
    }

    @ApiOperation("11 保存学习计划")
    @PostMapping("plan")
    public AjaxResult savePlan(@RequestBody LearnPlan plan)
    {
        LearnPlan curr = learnPlanService.getCurrLearnPlan();
        Date today = DateUtils.truncate(new Date(), Calendar.DATE);
        if(null != curr) {
            if(curr.getStatus().equals(1)) {
                if(DateUtils.isSameDay(curr.getBeginTime(), today)) { // 当天的更新计划
                    curr.setVideoTime(plan.getVideoTime());
                    curr.setQuestionCnt(plan.getQuestionCnt());
                } else {
                    curr.setStatus(0);
                }
                curr.setStudentId(null);
                curr.setBeginTime(null);
                curr.setStats(null);
                plan.setFirstTime(curr.getFirstTime());
                learnPlanService.updateLearnPlan(curr);
            }
            if(curr.getStatus().equals(1)) {
                return AjaxResult.success();
            }
        } else {
            plan.setFirstTime(today);
        }
        plan.setStudentId(SecurityUtils.getLoginUser().getUserId());
        plan.setBeginTime(today);
        plan.setStatus(1);
        learnPlanService.insertLearnPlan(plan);
        return AjaxResult.success();
    }

    @ApiOperation("10 查询学习计划统计")
    @GetMapping("plan/stats")
    public AjaxResult getPlanStats(@ApiParam String reportMonth)
    {
        LearnPlan curr = learnPlanService.getCurrLearnPlan();
        if(null == curr) {
            throw new RuntimeException("未配置学习计划");
        }
        // 统计每天的学习情况, 再汇总
        LearnPlanStudy cond = new LearnPlanStudy();
        cond.setStudentId(SecurityUtils.getLoginUser().getUserId());
        try {
            cond.setReportDate(DateUtils.parseDate(reportMonth, "yyyy-MM-dd"));
        } catch (ParseException e) {
            throw new ValidationException("日期格式错误");
        }
        List<LearnPlanStudy> studyList = learnPlanStudyService.selectPlanStudyStats(cond);
        Integer doneDay = 0;
        Long videoTimes = 0L;
        Long questionCnt = 0L;
        List<Dict> monthStudyList = Lists.newArrayList();
        Date firstDate = null;
        JSONObject today = null;
        for(LearnPlanStudy study : studyList) {
            JSONObject planStudy = toStudyStats(study);
            if(DateUtils.isSameDay(cond.getReportDate(), study.getReportDate())) {
                today = planStudy;
            }
            boolean videoCompleted;
            if(null != study.getVideoCount()) {
                videoCompleted = study.getVideoCount() >= study.getVideoPlan();
            } else {
                videoCompleted = study.getVideoPlan().equals(0);
            }
            if(null != study.getVideoTime()) {
                videoTimes += study.getVideoTime();
            }
            boolean questionCompleted;
            if(null != study.getQuestionCount()) {
                questionCnt += study.getQuestionCount();
                questionCompleted = study.getQuestionCount() >= study.getQuestionPlan();
            } else {
                questionCompleted = study.getQuestionPlan().equals(0);
            }
            if(videoCompleted && questionCompleted) {
                doneDay++;
            }
            if(null == firstDate) {
                firstDate = study.getReportDate();
            }
            monthStudyList.add(Dict.create().set("date", DateUtil.format(study.getReportDate(), "yyyy-MM-dd")).set("data", planStudy));
        }

        Integer preDay = 0; // 同月的排队计划开始之前的 历史月不好计算，待定 TODO MF
        Date month = DateUtils.truncate(cond.getReportDate(), Calendar.MONTH);
        if(DateUtils.isSameDay(month, DateUtils.truncate(curr.getFirstTime(), Calendar.MONTH))) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(curr.getFirstTime());
            preDay = cal.get(Calendar.DAY_OF_MONTH) - 1;
        }
        JSONObject stats = new JSONObject();
        stats.put("firstDay", DateUtil.format(curr.getFirstTime(), "yyyy-MM-dd"));
        stats.put("preDay", preDay);
        stats.put("doneDay", doneDay);
        stats.put("undoneDay", LocalDateTimeUtil.of(DateUtils.addDays(DateUtils.addMonths(month, 1), -1)).getDayOfMonth() - doneDay - preDay);
        stats.put("videoTimes", videoTimes);
        stats.put("questionCnt", questionCnt);
        stats.put("studyList", monthStudyList);
        stats.put("today", today);
        return AjaxResult.success(stats);
    }

    private JSONObject toStudyStats(LearnPlanStudy todayStudy) {
        JSONObject study = new JSONObject();
        study.put("questionPlan", todayStudy.getQuestionPlan());
        study.put("videoPlan", todayStudy.getVideoPlan());
        study.put("questionCnt", todayStudy.getQuestionCount());
        study.put("videoTime", todayStudy.getVideoCount());
        study.put("videoTimes", todayStudy.getVideoTime());
        study.put("rightRate", Math.round((float)(todayStudy.getRightCount() * 100 / todayStudy.getQuestionCount())));
        return study;
    }

    @ApiOperation("50 记录-知识点统计")
    @GetMapping("record/knowledge")
    public TableDataInfo getRecordKnowledge()
    {
        List<JSONObject> list = learnStatService.getRecordKnowledge(SecurityUtils.getUserId(), dzControlService.selectDzControl(SecurityUtils.getLoginUser().getUser()).getPlanYear());
        return getDataTable(list);
    }

    @ApiOperation("51 记录-模拟卷")
    @GetMapping("record/simulated")
    public AjaxResult getRecordSimulated()
    {
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        return AjaxResult.success(studentService.getSimulateList(sysUser.getUserId()));
    }

    @ApiOperation("52 记录-模拟卷结果")
    @GetMapping("record/simulated/{recordId}")
    public AjaxResult getSimulatedDetail(@ApiParam("记录ID") @PathVariable("recordId") Long recordId)
    {
        return AjaxResult.success(examService.loadExaminee(recordId, false));
    }

    @ApiOperation("53 记录-测试卷")
    @GetMapping("record/test")
    public TableDataInfo getRecordTest(@ApiParam("状态") @RequestParam(required = false) Integer state)
    {
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        startPage();
        return getDataTable(studentService.getTestList(sysUser.getUserId(), state));
    }

    @ApiOperation("54 记录-测试卷结果")
    @GetMapping("record/test/{recordId}")
    public AjaxResult getTestDetail(@ApiParam("记录ID") @PathVariable("recordId") Long recordId)
    {
        LearnTestStudent learnTestStudent = learnTestStudentService.selectLearnTestStudentById(recordId);
        if(null == learnTestStudent || null == learnTestStudent.getExamineeId()) {
            return AjaxResult.error("记录无效");
        }
        return AjaxResult.success(examService.loadExaminee(learnTestStudent.getExamineeId(), false));
    }

    @ApiOperation("55 记录-计划刷题")
    @GetMapping("record/planStudy")
    public AjaxResult getRecordPlanStudy(@ApiParam Integer year, @ApiParam @RequestParam(required = false) Long month)
    {
        return AjaxResult.success(learnStatService.getRecordPlanStudy(SecurityUtils.getUserId(), year, month));
    }

    @ApiOperation("练习列表")
    @GetMapping("record/practice")
    public TableDataInfo practice(@ApiParam @RequestParam(defaultValue = "0") Integer questionType)
    {
        startPage();
        return getDataTable(learnStatService.selectStudentPractices(SecurityUtils.getUserId(), PaperType.Practice, questionType));
    }

    @ApiOperation("同步练习列表")
    @GetMapping("record/coursePractice")
    public TableDataInfo coursePractice(@ApiParam @RequestParam(defaultValue = "0") Integer questionType)
    {
        return getDataTable(learnStatService.selectStudentPractices(SecurityUtils.getUserId(), PaperType.Course, questionType));
    }

    @ApiOperation("56 记录-视频学习")
    @GetMapping("record/video")
    public AjaxResult getRecordVideo()
    {
        return AjaxResult.success(learnStatService.getRecordVideo(SecurityUtils.getUserId()));
    }
}
