package com.xjrsoft.module.student.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xjrsoft.common.enums.EnrollTypeEnum;
import com.xjrsoft.common.enums.GenderDictionaryEnum;
import com.xjrsoft.common.enums.StudyStatusEnum;
import com.xjrsoft.common.model.result.RT;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.module.base.entity.BaseGrade;
import com.xjrsoft.module.base.entity.BaseSemester;
import com.xjrsoft.module.base.service.IBaseGradeService;
import com.xjrsoft.module.base.service.IBaseSemesterService;
import com.xjrsoft.module.databoard.vo.ItemCountVo;
import com.xjrsoft.module.student.dto.AddStudentReportRecordDto;
import com.xjrsoft.module.student.dto.StudentReportRecordPageDto;
import com.xjrsoft.module.student.dto.StudentReportRecordStatisticsDto;
import com.xjrsoft.module.student.dto.UpdateStudentReportRecordDto;
import com.xjrsoft.module.student.entity.StudentReportRecord;
import com.xjrsoft.module.student.service.IStudentReportRecordService;
import com.xjrsoft.module.student.vo.StudentReportRecordPageVo;
import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsListVo;
import com.xjrsoft.module.student.vo.StudentReportRecordStatisticsVo;
import com.xjrsoft.module.student.vo.StudentReportRecordVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @title: 学生报到记录表
* @Author dzx
* @Date: 2024-08-28
* @Version 1.0
*/
@RestController
@RequestMapping("/student" + "/studentReportRecord")
@Api(value = "/student"  + "/studentReportRecord",tags = "学生报到记录表代码")
@AllArgsConstructor
public class StudentReportRecordController {


    private final IStudentReportRecordService studentReportRecordService;
    private final IBaseSemesterService semesterService;
    private final IBaseGradeService gradeService;

    @GetMapping(value = "/page")
    @ApiOperation(value="学生报到记录表列表(分页)")
    @SaCheckPermission("studentreportrecord:detail")
    public RT<PageOutput<StudentReportRecordPageVo>> page(@Valid StudentReportRecordPageDto dto){

        LambdaQueryWrapper<StudentReportRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                    .orderByDesc(StudentReportRecord::getId)
                .select(StudentReportRecord.class,x -> VoToColumnUtil.fieldsToColumns(StudentReportRecordPageVo.class).contains(x.getProperty()));
        IPage<StudentReportRecord> page = studentReportRecordService.page(ConventPage.getPage(dto), queryWrapper);
        PageOutput<StudentReportRecordPageVo> pageOutput = ConventPage.getPageOutput(page, StudentReportRecordPageVo.class);
        return RT.ok(pageOutput);
    }

    @GetMapping(value = "/info")
    @ApiOperation(value="根据id查询学生报到记录表信息")
    @SaCheckPermission("studentreportrecord:detail")
    public RT<StudentReportRecordVo> info(@RequestParam Long id){
        StudentReportRecord studentReportRecord = studentReportRecordService.getById(id);
        if (studentReportRecord == null) {
           return RT.error("找不到此数据！");
        }
        return RT.ok(BeanUtil.toBean(studentReportRecord, StudentReportRecordVo.class));
    }


    @PostMapping
    @ApiOperation(value = "新增学生报到记录表")
    @SaCheckPermission("studentreportrecord:add")
    public RT<Boolean> add(@Valid @RequestBody AddStudentReportRecordDto dto){
        LambdaQueryWrapper<BaseSemester> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .orderByDesc(BaseSemester::getStartDate)
                .select(BaseSemester.class,x -> VoToColumnUtil.fieldsToColumns(BaseSemester.class).contains(x.getProperty()));
        List<BaseSemester> semesterList = semesterService.list(queryWrapper);
        Long semesterId = null;
        if(!semesterList.isEmpty()){
            semesterId = semesterList.get(0).getId();
        }
        StudentReportRecord one = studentReportRecordService.getOne(
                new QueryWrapper<StudentReportRecord>().lambda()
                        .eq(StudentReportRecord::getUserId, dto.getUserId())
                        .eq(StudentReportRecord::getBaseSemesterId, semesterId)
        );
        boolean isSuccess = true;
        if(one != null){
            one.setReportTime(new Date());
            isSuccess = studentReportRecordService.updateById(one);
        }else{
            StudentReportRecord studentReportRecord = BeanUtil.toBean(dto, StudentReportRecord.class);
            studentReportRecord.setBaseSemesterId(semesterId);
            studentReportRecord.setReportTime(new Date());
            isSuccess = studentReportRecordService.save(studentReportRecord);
        }

        return RT.ok(isSuccess);
    }

    @PutMapping
    @ApiOperation(value = "修改学生报到记录表")
    @SaCheckPermission("studentreportrecord:edit")
    public RT<Boolean> update(@Valid @RequestBody UpdateStudentReportRecordDto dto){

        StudentReportRecord studentReportRecord = BeanUtil.toBean(dto, StudentReportRecord.class);
        return RT.ok(studentReportRecordService.updateById(studentReportRecord));

    }

    @DeleteMapping
    @ApiOperation(value = "删除学生报到记录表")
    @SaCheckPermission("studentreportrecord:delete")
    public RT<Boolean> delete(@Valid @RequestBody List<Long> ids){
        return RT.ok(studentReportRecordService.removeByUserId(ids));

    }

    @GetMapping(value = "/mobile-page")
    @ApiOperation(value="班主任查询(分页)")
    @SaCheckPermission("studentreportrecord:detail")
    public RT<PageOutput<StudentReportRecordPageVo>> mobilePage(@Valid StudentReportRecordPageDto dto){
        if(dto.getBaseSemesterId() == null){
            LambdaQueryWrapper<BaseSemester> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper
                    .orderByDesc(BaseSemester::getStartDate)
                    .select(BaseSemester.class,x -> VoToColumnUtil.fieldsToColumns(BaseSemester.class).contains(x.getProperty()));
            List<BaseSemester> semesterList = semesterService.list(queryWrapper);
            if(!semesterList.isEmpty()){
                dto.setBaseSemesterId(semesterList.get(0).getId());
            }
        }
        if(dto.getTeacherId() == null){
            dto.setTeacherId(StpUtil.getLoginIdAsLong());
        }
        if(dto.getGradeId() == null){
            LambdaQueryWrapper<BaseGrade> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper
                    .orderByDesc(BaseGrade::getTitle)
                    .select(BaseGrade.class,x -> VoToColumnUtil.fieldsToColumns(BaseGrade.class).contains(x.getProperty()));
            List<BaseGrade> gradeList = gradeService.list(queryWrapper);
            if(!gradeList.isEmpty()){
                dto.setGradeId(gradeList.get(0).getId());
            }
        }
        Page<StudentReportRecordPageVo> page = studentReportRecordService.getMobilePage(new Page<>(dto.getLimit(), dto.getSize()), dto);
        PageOutput<StudentReportRecordPageVo> pageOutput = ConventPage.getPageOutput(page, StudentReportRecordPageVo.class);
        return RT.ok(pageOutput);
    }

    @GetMapping(value = "/class-statistics")
    @ApiOperation(value="班级统计")
    @SaCheckPermission("studentreportrecord:detail")
    public RT<StudentReportRecordStatisticsVo> classStatistics(@Valid StudentReportRecordStatisticsDto dto){
        if(dto.getTeacherId() == null){
            dto.setTeacherId(StpUtil.getLoginIdAsLong());
        }
        if(dto.getBaseSemesterId() == null){
            LambdaQueryWrapper<BaseSemester> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper
                    .orderByDesc(BaseSemester::getStartDate)
                    .select(BaseSemester.class,x -> VoToColumnUtil.fieldsToColumns(BaseSemester.class).contains(x.getProperty()));
            List<BaseSemester> semesterList = semesterService.list(queryWrapper);
            if(!semesterList.isEmpty()){
                dto.setBaseSemesterId(semesterList.get(0).getId());
            }
        }
        if(dto.getGradeId() == null){
            LambdaQueryWrapper<BaseGrade> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper
                    .orderByDesc(BaseGrade::getTitle)
                    .select(BaseGrade.class,x -> VoToColumnUtil.fieldsToColumns(BaseGrade.class).contains(x.getProperty()));
            List<BaseGrade> gradeList = gradeService.list(queryWrapper);
            if(!gradeList.isEmpty()){
                dto.setGradeId(gradeList.get(0).getId());
            }
        }
        StudentReportRecordStatisticsVo statisticsVo = studentReportRecordService.getClassStatistics(dto);
        if(statisticsVo == null){
            statisticsVo = new StudentReportRecordStatisticsVo();
            return RT.ok(statisticsVo);
        }
        long notArrivedCount = statisticsVo.getAllCount() - statisticsVo.getArrivedCount();
        statisticsVo.setNotArrivedCount(notArrivedCount);
        BigDecimal divide = BigDecimal.ZERO;
        if( statisticsVo.getAllCount() != 0){
            divide = BigDecimal.valueOf(statisticsVo.getArrivedCount()).divide(BigDecimal.valueOf(statisticsVo.getAllCount()), 4, RoundingMode.HALF_UP);
        }
        statisticsVo.setReportRate(divide.doubleValue());
        return RT.ok(statisticsVo);
    }

    @GetMapping(value = "/statistics")
    @ApiOperation(value="领导统计")
    @SaCheckPermission("studentreportrecord:detail")
    public RT<StudentReportRecordStatisticsVo> statistics(@Valid StudentReportRecordStatisticsDto dto){
        if(dto.getGradeId() == null){
            LambdaQueryWrapper<BaseGrade> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper
                    .orderByDesc(BaseGrade::getTitle)
                    .select(BaseGrade.class,x -> VoToColumnUtil.fieldsToColumns(BaseGrade.class).contains(x.getProperty()));
            List<BaseGrade> gradeList = gradeService.list(queryWrapper);
            if(!gradeList.isEmpty()){
                dto.setGradeId(gradeList.get(0).getId());
            }
        }
        if(dto.getEnrollType() == null || dto.getEnrollType().isEmpty()){
            dto.setEnrollType(EnrollTypeEnum.AUTUMN_ENROLLMENT.getCode());
        }
        List<StudentReportRecordStatisticsListVo> dataList = studentReportRecordService.getStatisticsDataList(dto);
        StudentReportRecordStatisticsVo statisticsVo = new StudentReportRecordStatisticsVo();
        statisticsVo.setAllCount(dataList.stream().count());

        statisticsVo.setArrivedCount(dataList.stream().filter(x -> x.getReportTime() != null).count());
        statisticsVo.setNotArrivedCount(dataList.stream().filter(x -> x.getReportTime() == null).count());
        statisticsVo.setArrivedMaleCount(dataList.stream().filter(x -> x.getReportTime() != null && GenderDictionaryEnum.MALE.getCode().equals(x.getGender())).count());
        statisticsVo.setArrivedFemaleCount(dataList.stream().filter(x -> x.getReportTime() != null && GenderDictionaryEnum.FEMALE.getCode().equals(x.getGender())).count());

        statisticsVo.setStayMaleCount(dataList.stream().filter(
                x -> GenderDictionaryEnum.MALE.getCode().equals(x.getGender())
                        && StudyStatusEnum.InResidence.getCode().equals(x.getStduyStatus())
                        && x.getReportTime() != null
        ).count());
        statisticsVo.setStayFemaleCount(dataList.stream().filter(
                x -> GenderDictionaryEnum.FEMALE.getCode().equals(x.getGender())
                        && StudyStatusEnum.InResidence.getCode().equals(x.getStduyStatus())
                        && x.getReportTime() != null
        ).count());
        statisticsVo.setNotStayMaleCount(dataList.stream().filter(
                x -> GenderDictionaryEnum.MALE.getCode().equals(x.getGender())
                        && StudyStatusEnum.AttendDaySchool.getCode().equals(x.getStduyStatus())
                        && x.getReportTime() != null
        ).count());
        statisticsVo.setNotStayFemaleCount(dataList.stream().filter(
                x -> GenderDictionaryEnum.FEMALE.getCode().equals(x.getGender())
                        && StudyStatusEnum.AttendDaySchool.getCode().equals(x.getStduyStatus())
                        && x.getReportTime() != null
        ).count());
        Map<String, List<StudentReportRecordStatisticsListVo>> graduatedUniversityMap = dataList.stream().filter(x -> x.getReportTime() != null).collect(Collectors.groupingBy(StudentReportRecordStatisticsListVo::getGraduatedUniversity));
        List<ItemCountVo> graduatedUniversityList = new ArrayList<>();
        for (String graduatedUniversity : graduatedUniversityMap.keySet()) {
            graduatedUniversityList.add(
                    new ItemCountVo(){{
                        setItem(graduatedUniversity);
                        setCount(graduatedUniversityMap.get(graduatedUniversity).size());
                    }}
            );
        }
        statisticsVo.setGraduatedUniversityList(graduatedUniversityList);

        Map<String, List<StudentReportRecordStatisticsListVo>> classMap = dataList.stream().filter(x -> x.getReportTime() != null).collect(Collectors.groupingBy(StudentReportRecordStatisticsListVo::getClassName));
        List<ItemCountVo> classList = new ArrayList<>();
        for (String className : classMap.keySet()) {
            classList.add(
                    new ItemCountVo(){{
                        setItem(className);
                        setCount(classMap.get(className).size());
                    }}
            );
        }
        statisticsVo.setClassList(classList);

        Map<String, List<StudentReportRecordStatisticsListVo>> classTypeMap = dataList.stream().filter(x -> x.getReportTime() != null).collect(Collectors.groupingBy(StudentReportRecordStatisticsListVo::getClassType));
        List<ItemCountVo> classTypeList = new ArrayList<>();
        for (String classType : classTypeMap.keySet()) {
            classTypeList.add(
                    new ItemCountVo(){{
                        setItem(classType);
                        setCount(classTypeMap.get(classType).size());
                    }}
            );
        }
        statisticsVo.setClassTypeList(classTypeList);

        Map<String, List<StudentReportRecordStatisticsListVo>> majorMap = dataList.stream().filter(x -> x.getReportTime() != null && x.getMajorName() != null).collect(Collectors.groupingBy(StudentReportRecordStatisticsListVo::getMajorName));
        List<ItemCountVo> majorList = new ArrayList<>();
        for (String majorName : majorMap.keySet()) {
            majorList.add(
                    new ItemCountVo(){{
                        setItem(majorName);
                        setCount(majorMap.get(majorName).size());
                    }}
            );
        }
        statisticsVo.setMajorList(majorList);

        BigDecimal divide = BigDecimal.ZERO;
        if( statisticsVo.getAllCount() != 0){
            divide = BigDecimal.valueOf(statisticsVo.getArrivedCount()).divide(BigDecimal.valueOf(statisticsVo.getAllCount()), 4, RoundingMode.HALF_UP);
        }
        statisticsVo.setReportRate(divide.doubleValue());
        return RT.ok(statisticsVo);
    }

}